如何使用XSL计算XML中特定节点的出现次数

时间:2013-10-05 03:20:47

标签: xml xslt

我有以下XML

<Root>
<PW>
  <Wec>
    <ID>11425</ID>
    <Data>
      <item>A3400301040TT01</item>
      <item>A3400301040TT02</item>
      <item>A3400301040TT03</item>
    </Data>
  </Wec>
  <Wec>
    <Data>
    <ID>11426</ID>
      <item>A3400302040TT01</item>
      <item>A3400302040TT03</item>
      <item>A3400302040TT02</item>
    </Data>
  </Wec>
</PW>
<PWSlots>
  <Rec>11</Rec>
  <Rec>12</Rec>
  <Rec>13</Rec>
  <Rec>14</Rec>
  <Rec>16</Rec>
  <Rec>15</Rec>
</PWSlots>
</Root>

我想生成一个像这样的xml

<Root>
<PW>
  <Wec>
    <ID>11425</ID>
    <Data>
      <Item id="A3400301040TT01" slotNumber="11"/>
      <item id="A3400301040TT02" slotNumber="12"/>
      <item id="A3400301040TT03" slotNumber="13"/>
    </Data>
  </Wec>
  <Wec>
    <ID>11426</ID>
    <Data>        
      <item id="A3400302040TT01" slotNumber="14"/>
      <item id="A3400302040TT03" slotNumber="16"/>
      <item id="A3400302040TT02" slotNumber="15"/>
    </Data>
  </Wec>
</PW>
</Root>   

好吧,所以我正在为每个Wec标签做一个xsl:foreach,在那个foreach里面我还有一个循环遍历每个item标签。 当我尝试将插槽作为项目的一部分包含在内时,问题出现了,因为我在特定的Wec节点内循环。

我需要一种基于特定项目标记的机制,我可以获得该项目节点的当前发生(在整个xml字符串中),以了解我必须从PWSlots分配的特定Rec标记。

举个例子,我在第一个Wec标签(ID 11425)中循环。由于这是节点项的第一次发生,我必须在PWSlots下分配第一个Rec标记的值。

有关如何使用XSL执行此操作的任何想法? 感谢您的帮助

2 个答案:

答案 0 :(得分:2)

我要做的是使用推送方法而不是拉取,并使用xsl:numberposition()来获取正确的Rec值。

我没有在第二个ID中更改Wec的位置,因为它似乎是一个错字。如果这需要移动而您无法解决,请告诉我。

示例...

XML输入

<Root>
    <PW>
        <Wec>
            <ID>11425</ID>
            <Data>
                <item>A3400301040TT01</item>
                <item>A3400301040TT02</item>
                <item>A3400301040TT03</item>
            </Data>
        </Wec>
        <Wec>
            <Data>
                <ID>11426</ID>
                <item>A3400302040TT01</item>
                <item>A3400302040TT03</item>
                <item>A3400302040TT02</item>
            </Data>
        </Wec>
    </PW>
    <PWSlots>
        <Rec>11</Rec>
        <Rec>12</Rec>
        <Rec>13</Rec>
        <Rec>14</Rec>
        <Rec>16</Rec>
        <Rec>15</Rec>
    </PWSlots>
</Root>

XSLT 1.0

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

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

    <xsl:template match="item">
        <xsl:variable name="pos">
            <xsl:number level="any"/>
        </xsl:variable>
        <item id="{.}" slotNumber="{/*/PWSlots/Rec[number($pos)]}"/>
    </xsl:template>

    <xsl:template match="PWSlots"/>

</xsl:stylesheet>

XML输出

<Root>
   <PW>
      <Wec>
         <ID>11425</ID>
         <Data>
            <item id="A3400301040TT01" slotNumber="11"/>
            <item id="A3400301040TT02" slotNumber="12"/>
            <item id="A3400301040TT03" slotNumber="13"/>
         </Data>
      </Wec>
      <Wec>
         <Data>
            <ID>11426</ID>
            <item id="A3400302040TT01" slotNumber="14"/>
            <item id="A3400302040TT03" slotNumber="16"/>
            <item id="A3400302040TT02" slotNumber="15"/>
         </Data>
      </Wec>
   </PW>
</Root>

答案 1 :(得分:2)

我更喜欢@ Daniel的方法。但这是另一种解决方案:

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

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

   <!-- remove PWSlots -->
   <xsl:template match="PWSlots" />

   <xsl:template match="item">
      <xsl:variable name="id" select="normalize-space()" />
      <xsl:variable name="pos">
         <xsl:for-each select="//item">
            <xsl:if test="normalize-space(.)=$id">
               <xsl:value-of select="position()" />
            </xsl:if>
         </xsl:for-each>
      </xsl:variable>
      <Item id="{.}">
         <xsl:attribute name="slotNumber">
            <xsl:value-of select="//PWSlots/Rec[number($pos)]" />
         </xsl:attribute>
      </Item>
   </xsl:template>
</xsl:stylesheet>