1

我有一个非常棘手的 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 值时(如示例中所示)。任何人都可以帮助我吗?

谢谢。

4

3 回答 3

1

一般来说,避免使用 value-of 并了解 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>
于 2012-08-30T19:22:22.337 回答
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>
于 2012-08-30T19:30:17.497 回答
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>
于 2012-08-31T03:13:02.130 回答