Xslt Nested For-Loop с перерывом - PullRequest
       6

Xslt Nested For-Loop с перерывом

1 голос
/ 24 февраля 2012

All

Я новичок в XSLT и сталкиваюсь с типичной проблемой. Ниже подробно описана проблема

Исходя из приведенных ниже данных, мне нужно было показывать элемент ItemA / ANum только тогда, когда он имеет AName BBC, а не является частью ItemB / tempBNum

Таким образом, желаемый результат для приведенных ниже данных должен быть 0214, BBC, поскольку его часть ItemA, также является BBC, не появляется в ItemB.

<myData>
<ItemA>
    <ANum>0213</ANum>
    <AName>OOC</AName>
</ItemA>
<ItemA>
    <ANum>0031</ANum>
    <AName>BBC</AName>
</ItemA>
<ItemA>
    <ANum>0214</ANum>
    <AName>BBC</AName>
</ItemA>
<ItemA>
    <ANum>0044</ANum>
    <AName>BBC</AName>
</ItemA>

<ItemB>
    <tempBNum>0031</tempBNum>
</ItemB>
<ItemB>
    <tempBNum>0044</tempBNum>
</ItemB>
</myData>

С этой целью я попытался ввести логику наличия вложенных циклов, только проблема с вложенным циклом должна прерываться, когда ItemAObj / ANum = tempBNum, но не прерывается и не дает повторяющихся результатов.

  <xsl:for-each select="myData/ItemA">
    <xsl:variable name="ItemAObj" select="." />
    Num = <xsl:value-of select="$ItemAObj/ANum"/>
    <xsl:for-each select="/myData/ItemB">
    <xsl:choose>
        <xsl:when test="$ItemAObj/ANum!=tempBNum and $ItemAObj/AName='BBC'"> <xsl:value-of select="tempBNum"/>
        <xsl:text> </xsl:text>
    </xsl:when>
        </xsl:choose>
        </xsl:for-each>
  </xsl:for-each>

Любая помощь по этому вопросу будет принята с благодарностью.

Ответы [ 3 ]

0 голосов
/ 24 февраля 2012

Это может быть достигнуто другим способом, с необходимостью для каждого для перебора элементов и проверки его по очереди. Вместо этого вы можете использовать ключ для поиска, существуют ли элементы ItemB для числа

<xsl:key name="itemB" match="ItemB" use="tempBNum" />

Тогда вы можете просто сопоставить элементы itemA , если для элемента ANNum

нет элементов ItemB .
<xsl:apply-templates select="ItemA[AName='BBC'][not(key('itemB', ANum))]" />

Вот полный XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="itemB" match="ItemB" use="tempBNum" />

   <xsl:template match="/myData">
      <xsl:apply-templates select="ItemA[AName='BBC'][not(key('itemB', ANum))]" />
   </xsl:template>

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

При применении к вашему образцу XML выводится следующее:

<ItemA>
   <ANum>0214</ANum>
   <AName>BBC</AName>
</ItemA>
0 голосов
/ 24 февраля 2012

Вам не нужно использовать какие-либо xsl:for-each для решения проблемы, гораздо больше вам не нужно вложенные xsl:for-each.

На самом деле,требуемые ItemA элементы могут быть выбраны с помощью одного выражения XPath :

/*/ItemA[AName = 'BBC' 
       and 
         not(ANum = /*/ItemB/tempBNum)
        ]

Поэтому простое преобразование XSLT, которое оценивает вышеприведенное выражение XPath и копирует результат в вывод:1014 *

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

<myData>
    <ItemA>
        <ANum>0213</ANum>
        <AName>OOC</AName>
    </ItemA>
    <ItemA>
        <ANum>0031</ANum>
        <AName>BBC</AName>
    </ItemA>
    <ItemA>
        <ANum>0214</ANum>
        <AName>BBC</AName>
    </ItemA>
    <ItemA>
        <ANum>0044</ANum>
        <AName>BBC</AName>
    </ItemA>
    <ItemB>
        <tempBNum>0031</tempBNum>
    </ItemB>
    <ItemB>
        <tempBNum>0044</tempBNum>
    </ItemB>
</myData>

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

<ItemA>
   <ANum>0214</ANum>
   <AName>BBC</AName>
</ItemA>

Если нам нужны только значения текстовых узлов, просто используйте функцию string():

string(/*/ItemA[AName = 'BBC' and not(ANum = /*/ItemB/tempBNum)])

Затем измененное преобразование:

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

 <xsl:template match="/">
     <xsl:copy-of select=
     "string(/*/ItemA[AName = 'BBC' and not(ANum = /*/ItemB/tempBNum)])"/>
 </xsl:template>
</xsl:stylesheet>

при применении ктот же XML-документ (см. выше) создает:

    0214
    BBC

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

0 голосов
/ 24 февраля 2012

Вы не можете сломать, но вы добавляете условие, чтобы убедиться, что нет previous-sibling ItemAObj/ANum = tempBNum

...