XSLT for-each循环

时间:2012-08-30 18:43:38

标签: xml xslt

我有一个非常棘手的XSLT问题。 想象一下,我有以下输入:

<OtherCharges>        
<LineId>
    <Id>P</Id>
</LineId>
<Items>
    <Item1>1</Item1>
    <Item2>2</Item2>
    <Item3>3</Item3>  
</Items>    
<LineId>
    <Id>P</Id>
</LineId>
<Items>
    <Item1>4</Item1>
</Items>
<LineId>
    <Id>P</Id>
</LineId>
<Items>
    <Item1>5</Item1>
    <Item2>6</Item2>    
</Items>
</OtherCharges>

作为输出我希望有这个:

<OtherCharges>
  <LineId>P</LineId>
  <OtherChargesValues>
    <value>1</value>
    <value>2</value>
    <value>3</value>
  </OtherChargesValues>
</OtherCharges>
<OtherCharges> 
  <LineId>P</LineId>
  <OtherChargesValues>
    <value>4</value>
  </OtherChargesValues>
</OtherCharges>
<OtherCharges> 
  <LineId>P</LineId>
  <OtherChargesValues>
    <value>5</value>
    <value>6</value>
  </OtherChargesValues>
</OtherCharges>

我可以拥有无​​限数量的行,但每行最多有3个项目。 我尝试过以下代码:

<xsl:for-each select="/OtherCharges/LineId">
<Id>
    <xsl:value-of select="Id"/>
<Id>
<xsl:variable name="ChargeLine" select="."/>
<xsl:for-each select="following-sibling::Items[preceding-sibling::LineId[1] = $ChargeLine]">    
    <xsl:if test="name(.)='Items'">
        <xsl:if test="Item1">
            <value>
                <xsl:value-of select="Item1"/>
            </value>
        </xsl:if>  
        <xsl:if test="Item2">
            <value>
                <xsl:value-of select="Item2"/>
            </value>
        </xsl:if> 
        <xsl:if test="Item3">
            <value>
                <xsl:value-of select="Item3"/>
            </value>
        </xsl:if>
    </xsl:if>
</xsl:for-each>

如果ID不同,它运行良好,但问题是我有相同的ID值(如示例中所示)。 有人可以帮我这个吗?

感谢。

3 个答案:

答案 0 :(得分:1)

一般来说,避免使用应用模板的价值和知识,这将成为一个非常简单的XSLT问题。顺便说一下,你的输出不是格式良好的XML,因为它没有单个根包装元素。

<xsl:strip-space elements="OtherCharges" />

<xsl:template match="OtherCharges">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="OtherCharges/LineId">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="OtherCharges/Items">
  <xsl:apply-templates/>
</xsl:template>

<!--* now the real work *-->
<xsl:template match="OtherCharges/LineId/Id">
  <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="OtherCharges/Items/*">
  <value><xsl:apply-templates/></value>
</xsl:template>

答案 1 :(得分:1)

starts-with()可能有帮助...

XML输入

<OtherCharges>        
    <LineId>
        <Id>P</Id>
    </LineId>
    <Items>
        <Item1>1</Item1>
        <Item2>2</Item2>
        <Item3>3</Item3>  
    </Items>    
    <LineId>
        <Id>P</Id>
    </LineId>
    <Items>
        <Item1>4</Item1>
    </Items>
    <LineId>
        <Id>P</Id>
    </LineId>
    <Items>
        <Item1>5</Item1>
        <Item2>6</Item2>    
    </Items>
</OtherCharges>

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="Id">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Items/*[starts-with(name(),'Item')]">
        <value>
            <xsl:apply-templates select="@*|node()"/>
        </value>
    </xsl:template>

</xsl:stylesheet>

XML输出(格式不正确)

<Id>P</Id>
<value>1</value>
<value>2</value>
<value>3</value>
<Id>P</Id>
<value>4</value>
<Id>P</Id>
<value>5</value>
<value>6</value>

答案 2 :(得分:1)

此转化

<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:key name="kFollowing" match="*[not(self::LineId)]"
  use="generate-id(preceding-sibling::LineId[1])"/>

 <xsl:template match="LineId">
  <OtherCharges>
     <LineId><xsl:value-of select="."/></LineId>
     <OtherChargesValues>
       <xsl:apply-templates mode="inGroup"
            select="key('kFollowing', generate-id())"/>
     </OtherChargesValues>
  </OtherCharges>
 </xsl:template>

 <xsl:template match="Items/*" mode="inGroup">
  <value><xsl:value-of select="."/></value>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

应用于提供的XML文档

<OtherCharges>
    <LineId>
        <Id>P</Id>
    </LineId>
    <Items>
        <Item1>1</Item1>
        <Item2>2</Item2>
        <Item3>3</Item3>
    </Items>
    <LineId>
        <Id>P</Id>
    </LineId>
    <Items>
        <Item1>4</Item1>
    </Items>
    <LineId>
        <Id>P</Id>
    </LineId>
    <Items>
        <Item1>5</Item1>
        <Item2>6</Item2>
    </Items>
</OtherCharges>

会产生想要的正确结果:

<OtherCharges>
   <LineId>P</LineId>
   <OtherChargesValues>
      <value>1</value>
      <value>2</value>
      <value>3</value>
   </OtherChargesValues>
</OtherCharges>
<OtherCharges>
   <LineId>P</LineId>
   <OtherChargesValues>
      <value>4</value>
   </OtherChargesValues>
</OtherCharges>
<OtherCharges>
   <LineId>P</LineId>
   <OtherChargesValues>
      <value>5</value>
      <value>6</value>
   </OtherChargesValues>
</OtherCharges>