Отображение XSLT и суммирование дочерних элементов источника в один целевой атрибут - PullRequest
1 голос
/ 06 марта 2012

У меня есть исходный документ со структурой XML, похожей на эту:

<FOO>
     <BAR>x</BAR>
     <BAR>y</BAR>
     <BAR>z</BAR>
</FOO>

Мой целевой XML должен иметь атрибут с числом, представляющим числовую сумму x, y и z.Где x = 1, y = 2 и z = 3

ПРИМЕЧАНИЕ. X, y и z на самом деле не являются числами в исходном документе.Они являются буквами и должны быть сопоставлены с числами, которые они представляют в первую очередь.

В этом случае цель должна выглядеть примерно так:

<Target Sum=6>
</Target>

У кого-нибудь есть пример XSLT, который будет делать то, что мне нужно?

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 07 марта 2012

Гораздо более простое, короткое и эффективное решение :

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

 <xsl:key name="kMap" match="@value" use="../@key"/>

 <xsl:variable name="vMaps" as="element()*">
  <map key="x" value="1"/>
  <map key="y" value="2"/>
  <map key="z" value="3"/>
 </xsl:variable>

 <xsl:template match="/*">
    <Target Sum="{sum(key('kMap', BAR, document('')))}"/>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному документу XML :

<FOO>
     <BAR>x</BAR>
     <BAR>y</BAR>
     <BAR>z</BAR>
</FOO>

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

<Target Sum="6"/>

Объяснение : правильное использование xsl:key, 3-й аргумент функции key()и AVT.

0 голосов
/ 06 марта 2012
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
  <Target Sum="{sum(FOO/BAR)}" />
</xsl:template>

EDIT:

Это немного многословно, и, вероятно, есть более элегантный способ сделать это, но, по сути, у меня есть именованный шаблон, который рекурсивно вызывает себя для вычисления суммы после жестко закодированного отображения:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <Target>
      <xsl:attribute name="Sum">
        <xsl:call-template name="GetSum">
          <xsl:with-param name="CurrentNode" select="FOO/BAR[position()=1]"/>
        </xsl:call-template>
     </xsl:attribute>
    </Target>
  </xsl:template>

  <xsl:template name="GetSum">
    <xsl:param name="CurrentNode"/>
    <xsl:param name="Number" select="0"/>

    <xsl:variable name="Recursive_Result">
      <xsl:variable name="MappedNumber">
        <xsl:choose>
          <xsl:when test="$CurrentNode/. = 'x'">1</xsl:when>
          <xsl:when test="$CurrentNode/. = 'y'">2</xsl:when>
          <xsl:when test="$CurrentNode/. = 'z'">3</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
        </xsl:choose>
      </xsl:variable>

      <!-- if there is a next sibling, recursively call GetSum  -->
      <xsl:choose>
        <xsl:when test="$CurrentNode/following-sibling::BAR[1]">
          <xsl:call-template name="GetSum">
            <xsl:with-param name="CurrentNode" select="$CurrentNode/following-sibling::BAR[1]"/>
            <xsl:with-param name="Number">
              <xsl:value-of select="$MappedNumber"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$MappedNumber"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <!-- add the recursive_result to the number passed into the template. this will eventually build a sum -->
    <xsl:value-of select="$Recursive_Result + $Number"/>
  </xsl:template>
</xsl:stylesheet>
...