XSL到XML循环问题

时间:2011-06-09 08:47:30

标签: xml xslt

我需要循环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>

2 个答案:

答案 0 :(得分:2)

你需要选择前面的兄弟;有example here

基本上你的xpath语法就像(未经测试):

preceding-sibling::NodeName[1]

答案 1 :(得分:1)

我没有拒绝完全审核您的代码:)

下面是一个更加面向功能的完整XSLT 1.0解决方案(无过程方法)。它可能看起来很难看到,但是,imho,这是开始使用XSLT模板机制的一个很好的例子。

在特定情况下使用xsl:for-each也不是那么容易,因为在循环的某个步骤中,您希望所有前面的相邻兄弟都使用空id,而不知道它们有多少< em>先验。

我还使用了身份模板来简化重新创建目标的工作。

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