Подстановка значений из списка пар в XSLT - PullRequest
4 голосов
/ 23 августа 2011

Я использую XSLT для преобразования из одного формата XML в другой, но мне также нужно, если это возможно, выполнять подстановку некоторых значений одновременно. Может ли кто-то предоставить решение для изменения большого количества значений; например «AppName» следует изменить на «1», «AppNameTwo» на «2», и в идеале я хотел бы сделать это с помощью некоторых типов списков поиска в XSLT:

<Application>
 <oldvalue="AppName" replacewith="1">
 <oldvalue="AppNameTwo" replacewith="2">
</Application>
<ResponseOne>
 <oldvalue="True" replacewith="Okay">
 <oldvalue="False" replacewith="Error">
</ResponseOne>

Единственный способ, которым я сейчас могу думать об этом, - это использовать множество вложенных замен?

Input

<Message>
  <Header>
    <Application>AppName</Application>
    <ResponseOne>True</ResponseOne>
    ...
</Header>
</Message>

Пока XSLT

    <?xml version="1.0" encoding="utf-8"?>
        <xsl:stylesheet version="1.0">
        <xsl:template match="/">
        <n1:Message>
          <Header>
            <Application><xsl:value-of select="//Message/Organisation/Application/Name"/>   </Application>
   <Response><xsl:value-of select="//Message/Organisation/Application/ResponseOne"/>   </Response>
            ...
          </Header>
    </n1:Message>

Требуемый выход

 <?xml version="1.0" encoding="utf-8"?>
        <n1:Message>
          <Header>
          <Application>1</Application>
          <Response>Error</Response>
            ...
          </Header>
    </n1:Message>

Намерение запустить этот XSLT в Visual Studio 2010.

Ответы [ 3 ]

1 голос
/ 23 августа 2011

Это простое преобразование (только один шаблон переопределяет правило идентификации и нет необходимости в функциях расширения), позволяет использовать огромное количество правил замены без необходимости изменять код ввсе .Другой альтернативой является указание значения глобального параметра $pReps вне преобразования - тогда этот код можно даже немного упростить:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pReps">
  <elem name="Application">
   <replace>
     <this>AppName</this>
     <with>1</with>
   </replace>
   <replace>
     <this>AppNameTwo</this>
     <with>2</with>
   </replace>
  </elem>
  <elem name="ResponseOne">
   <replace>
     <this>True</this>
     <with>Okay</with>
   </replace>
   <replace>
     <this>False</this>
     <with>Error</with>
   </replace>
  </elem>
 </xsl:param>

 <xsl:variable name="vReps" select=
 "document('')/*/xsl:param[@name='pReps']"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="text()">
  <xsl:variable name="vNewVal" select=
   "$vReps/elem
       [@name=name(current()/..)]
              /replace[this = current()]
                 /with/text()
   "/>

   <xsl:copy-of select=
    "$vNewVal | self::text()[not($vNewVal)]"/>
 </xsl:template>
</xsl:stylesheet>

При применении к предоставленному документу XML :

<Message>
  <Header>
    <Application>AppName</Application>
    <ResponseOne>True</ResponseOne>
    ...
</Header>
</Message>

желаемый, правильный результат получен :

<Message>
   <Header>
      <Application>1</Application>
      <ResponseOne>Okay</ResponseOne>
    ...
</Header>
</Message>

Пояснение :

  1. Правило идентификации (шаблон) копирует каждый узел "как есть" .

  2. Правила замены:кодируется как последовательность elem элементов , которые являются дочерними элементами глобального параметра pReps.Структура и значение каждого элемента elem должны быть самоочевидными.

  3. Существует один шаблон, переопределяющий правило идентификации, который соответствует любому текстовому узлу.В этом шаблоне возможное новое значение вычисляется как определено переменной $vNewVal. Это либо пустой набор узлов (в случае, если родительское имя текущего узла и строковое значение текущего узла не сопоставленына любое значение replace/this из $pReps. Или, если совпадает, это with родственное значение replace/this из $pReps. Наконец, либо $vNewVal (если не пусто), либотекущий узел копируется.

1 голос
/ 23 августа 2011

Вот проверенный пример использования exslt:node-set(), который должен быть доступным в процессоре MS XML:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exslt="http://exslt.org/common"
    version="1.0">
    <xsl:variable name="tbl">
        <Application>
            <oldvalue val="AppName" replacewith="1"/>
            <oldvalue val="AppNameTwo" replacewith="2"/>
        </Application>
        <ResponseOne>
            <oldvalue val="True" replacewith="Okay"/>
            <oldvalue val="False" replacewith="Error"/>
        </ResponseOne>
    </xsl:variable>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Application">
        <xsl:variable name="old" select="./text()"/>
        <xsl:copy><xsl:value-of select="exslt:node-set($tbl)/Application/oldvalue[@val=$old]/@replacewith"/></xsl:copy>
    </xsl:template>
</xsl:stylesheet>

При этом используется переменная, содержащая таблицу поиска (я исправил ваш XML для таблицы), а также преобразование идентичности, которое копирует входные данные в выходные данные. Затем есть шаблон для Application узлов, который выполняет преобразование с использованием таблицы поиска. Вам нужна функция exslt:node-set() для преобразования фрагмента результирующего дерева в набор узлов, который можно искать с помощью XPath.

Я оставил вам преобразование тегов <ResponseOne>. Подсказка: просто создайте другой шаблон, подобный шаблону для Application.

0 голосов
/ 23 августа 2011

Вот подход с использованием ключей. Шаблон прост без сложных выражений, а правила замены хранятся отдельно от кода. Правила могут быть расширены без какой-либо модификации кода.

lookup.xml

<?xml version="1.0"?>
<replacements>
    <Application>
        <replace oldvalue="AppName" replacewith="1"/>
        <replace oldvalue="AppNameTwo" replacewith="2"/>
    </Application>
    <ResponseOne>
        <replace oldvalue="True" replacewith="Okay"/>
        <replace oldvalue="False" replacewith="Error"/>
    </ResponseOne>
</replacements>

Input.xml

<?xml version="1.0"?>
<Message>
    <Header>
        <Application>AppName</Application>
        <ResponseOne>True</ResponseOne>
    </Header>
    <Header>
        <Application>AppNameTwo</Application>
        <ResponseOne>False</ResponseOne>
    </Header>
</Message>

transform.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:variable name="lookup" select="document('lookup.xml')"/>
    <xsl:key name="MasterKey" match="/replacements/*/replace" use="concat(local-name(..), ':', @oldvalue)"/>
    <xsl:template match="/Message">
        <Message>
            <xsl:apply-templates select="$lookup"/>
            <xsl:apply-templates/>
        </Message>
    </xsl:template>
    <xsl:template match="replacements"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Header/*">
        <xsl:variable name="ThisKey" select="concat(local-name(), ':', text())"/>
        <xsl:variable name="nodename" select="local-name()"/>
        <xsl:choose>
            <xsl:when test="$lookup/replacements/*[name() =$nodename]">
                <xsl:element name="{$nodename}">
                    <xsl:for-each select="$lookup/replacements[1]">
                        <xsl:value-of select="key('MasterKey', $ThisKey)/@replacewith"/>
                    </xsl:for-each>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Выход:

<?xml version="1.0" encoding="UTF-16"?>
<Message>
    <Header>
        <Application>1</Application>
        <ResponseOne>Okay</ResponseOne>
    </Header>
    <Header>
        <Application>2</Application>
        <ResponseOne>Error</ResponseOne>
    </Header>
</Message>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...