2011-06-09 69 views
2

我需要循环一个XML文档。那里没问题。
问题来了,当我需要从上一行我刚刚跳过的文本。XSL到XML循环问题

XML将看一些这样的事

<lines> 
    <line> 
    <id>1</id> 
    <text>Some fancy text here 1</text> 
    </line> 
    <line> 
    <id></id> 
    <text>This I need in the next line with a ID</text> 
    </line> 
    <line> 
    <id></id> 
    <text>Also need this.</text> 
    </line> 
    <line> 
    <id>4</id> 
    <text>Here we go</text> 
    </line> 
</lines> 

输出XML文件需要这个样子

<output> 
    <line> 
    <id>1</id> 
    <note>Some fancy text here 1</note> 
    </line> 
    <line> 
    <id>4</id> 
    <note>Here we go</note> 
    <extra> 
     <note>This I need in the next line with a ID</note> 
     <note>Also need this.</note> 
    </extra> 
    </line> 
</output> 

的XSL我有这样的票价是简单的梳理没有ID设置的线。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
    <output> 
    <xsl:for-each select="lines/line"> 
     <xsl:if test="id/text() &gt; 0"> 
     <line> 
      <id> 
      <xsl:value-of select="id" /> 
      </id> 
      <note> 
      <xsl:value-of select="text" /> 
      </note> 
     </line> 
     </xsl:if> 
    </xsl:for-each> 
    </output> 
    </xsl:template> 
</xsl:stylesheet> 
+0

的'的xsl:for-each'是** **不循环。这是你的'select'每个匹配的函数分配。 – Mikaveli 2011-06-09 13:41:08

+0

+1为好问题。 – 2011-06-09 13:55:46

回答

1

我没有反抗彻底检查你的代码:)

这里有个完整的XSLT 1.0解决方案的更多功能(无程序方法)。它可能首先看起来很难看,但是,imho,这是开始使用XSLT模板机制的一个很好的例子。

此外,在特定情况下使用xsl:for-each不是那么容易,因为你想获得所有前面相邻的兄弟姐妹与空id环的某一步,不知道他们有多少人先验

我也使用标识模板来简化重新创建目标的工作。

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

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

    <!-- match line with empty id and do not output --> 
    <xsl:template match="line[not(boolean(id/text()))]"/> 

    <!-- match line with id and build output --> 
    <xsl:template match="line[boolean(id/text())]"> 
     <xsl:copy> 
      <xsl:copy-of select="id"/> 
      <xsl:apply-templates select="text"/> 
      <extra> 
       <!-- apply recursive template to the first preceding 
       sibling adajacent node with empty id --> 
       <xsl:apply-templates select="(preceding-sibling::*[1]) 
        [name()='line' and not(boolean(id/text()))]/text" 
        mode="extra"/> 
      </extra> 
     </xsl:copy> 
    </xsl:template> 

    <!-- change text element to note --> 
    <xsl:template match="text"> 
     <note> 
      <xsl:value-of select="."/> 
     </note> 
    </xsl:template> 

    <!-- recursive template for extra note elements --> 
    <xsl:template match="text" mode="extra"> 
     <note> 
      <xsl:value-of select="."/> 
     </note> 
     <xsl:apply-templates select="(parent::line/preceding-sibling::*[1]) 
      [name()='line' and not(boolean(id/text()))]/text" 
      mode="extra"/> 
    </xsl:template> 

</xsl:stylesheet> 

应用在你的输入,得出:

<?xml version="1.0" encoding="UTF-8"?> 
<lines> 
    <line> 
     <id>1</id> 
     <note>Some fancy text here 1</note> 
     <extra/> 
    </line> 
    <line> 
     <id>4</id> 
     <note>Here we go</note> 
     <extra> 
     <note>Also need this.</note> 
     <note>This I need in the next line with a ID</note> 
     </extra> 
    </line> 
</lines> 
+0

这很好。我可能会在第一个ekasmple上加速一些,因为在id 4之后我可能会有更多的急速。在eatch之后,可以用bee sevel来表示一行,并且所有这些都需要将相同的两行添加到额外的字段中。我会和它一起玩。再次感谢 – Tyde 2011-06-10 06:12:03

2

你需要选择前同辈;有一个example here

基本上XPath语法的你会是这样的(未测试):

preceding-sibling::NodeName[1] 
+0

这个xpath将会得到第一个prince-sibling(什么?)。看起来OP需要所有先前相邻的兄弟姐妹。对于如何将这个应用到当前的用例中,这还不是很清楚。 – 2011-06-09 13:39:44