2012-08-30 59 views
1

我有一個非常棘手的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值(如在本例中)。 任何人都可以幫助我嗎?

謝謝。

+0

注意:感謝您的答案,但輸出錯誤。我對此很抱歉。事實上,它似乎可能有一個簡單的解決方案,但我不是很有經驗。謝謝。 – user295744

回答

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> 
+0

這很好用!我其實不知道有關generate-id()。謝謝。 – user295744

+0

'...是在XSLT 1中測試節點標識的唯一方法。0' – MiMo

+0

@ user295744,不客氣。 generate-id()是在XSLT 1.0中測試節點標識的唯一方法。在XPath 2.0(XSLT 2.0)中,is運算符的唯一語義是確認兩個節點之間的身份。 - –

1

通常,避免使用價值和了解apply-templates,這將成爲一個非常簡單的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> 
+0

前三個模板不需要.... – MiMo

+0

感謝您的答案,但輸出錯誤。我對此很抱歉。我編輯了輸出。 – user295744

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> 
+0

它不會產生問題中要求的輸出:元素應該被稱爲「值」,而不是「Item1」,「Item2」等。 – MiMo

+0

@MiMo - 我沒有注意到這一點。很好的接收。當我有一分鐘時,我會盡力更新。謝謝! –

+0

已更新。再次感謝。 –