2016-07-28 76 views
0

节点我有下面的XML:选择以下一些同胞只有

<root> 
<table>Table 1</table> 
<foot>1.1</foot> 
<foot>2.2</foot> 
<p>...</p> 
<p>...</p> 
<table>Table X</table> 
<foot>M.1</foot> 
<foot>M.2</foot> 
<p>...</p> 
<p>...</p> 
<table>Table 132</table> 
<foot>A.A.E</foot> 
<foot>234</foot> 
<p>...</p> 
<p>...</p> 
</root> 

我想将其转换为:

<root> 
<table> 
<text>Table 1</text> 
<foot>1.1</foot> 
<foot>2.2</foot> 
</table> 
<p>...</p> 
<p>...</p> 
<table> 
<text>Table X</text> 
<foot>M.1</foot> 
<foot>M.2</foot> 
</table> 
<p>...</p> 
<p>...</p> 
<table> 
<text>Table 132</text> 
<foot>A.A.E</foot> 
<foot>234</foot> 
</table> 
<p>...</p> 
<p>...</p> 
</root> 

我有以下XSL代码:

<xsl:template match="table"> 
<xsl:element name="table"> 
    <xsl:element name="text"> 
    <xsl:apply-templates /> 
    </xsl:element> 
    <xsl:for-each select="following-sibling::foot"> 
    <xsl:element name="foot"> 
    <xsl:apply-templates /> 
    </xsl:element> 
    </xsl:for-each> 
</xsl:element> 

其中输出为:

<root> 
<table> 
<text>Table 1</text> 
<foot>1.1</foot> 
<foot>2.2</foot> 
<foot>M.1</foot> 
<foot>M.2</foot> 
<foot>A.A.E</foot> 
<foot>234</foot> 
</table> 
<p>...</p> 
<p>...</p> 
<table> 
<text>Table X</text> 
<foot>M.1</foot> 
<foot>M.2</foot> 
<foot>A.A.E</foot> 
<foot>234</foot> 
</table> 
<p>...</p> 
<p>...</p> 
<table> 
<text>Table 132</text> 
<foot>A.A.E</foot> 
<foot>234</foot> 
</table> 
<p>...</p> 
<p>...</p> 
</root> 

如何只能选择foot元件,其立即在关闭table元素,只要将nfoot元素立即table元以下。任何对此的帮助表示赞赏。

+0

您可以使用XSLT 2.0吗? –

+0

对不起。 XSLT 2.0是可以的。我应该指定它。 – Jagath

回答

1

最简单的方法是使用XSL键。 (在这个答案的解决方案将在所有的XSLT版本。)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes" /> 

    <xsl:strip-space elements="*" /> 
    <xsl:key name="foot" match="foot" use="generate-id(preceding-sibling::table[1])" /> 

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

    <xsl:template match="table"> 
     <xsl:copy> 
      <text><xsl:apply-templates select="@*|node()"/></text> 
      <xsl:copy-of select="key('foot', generate-id())" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="foot" /> 
</xsl:transform> 

<xsl:key>指标使用唯一的ID文档中的所有元素<foot>(见spec)的前一个<table>

<xsl:template match="table">然后在相同唯一ID的帮助下选择属于每个<table><foot>元素。


这样做的功能等同物是:

<xsl:template match="table"> 
    <xsl:copy> 
     <text><xsl:apply-templates select="@*|node()"/></text> 
     <xsl:copy-of select="following-sibling::foot[ 
      generate-id(preceding-sibling::table[1]) = generate-id(current()) 
     ]" /> 
    </xsl:copy> 
</xsl:template> 

在这种变型中,XSL键将不需要。其结果是在这两种情况下:

<root> 
    <table> 
     <text>Table 1</text> 
     <foot>1.1</foot> 
     <foot>2.2</foot> 
    </table> 
    <p>...</p> 
    <p>...</p> 
    <table> 
     <text>Table X</text> 
     <foot>M.1</foot> 
     <foot>M.2</foot> 
    </table> 
    <p>...</p> 
    <p>...</p> 
    <table> 
     <text>Table 132</text> 
     <foot>A.A.E</foot> 
     <foot>234</foot> 
    </table> 
    <p>...</p> 
    <p>...</p> 
</root> 

注:

  • 不要使用<xsl:element name="text">。你可以简单地写<text><xsl:element>适用于元件名称未预先确定的情况。
  • 避免<xsl:for-each>。在大多数情况下,使用<xsl:template><xsl:apply-templates>是优越的。
+0

完美!谢谢 – Jagath

+0

对于XSLT 2.0环境,@ michael.hor257k提供的解决方案当然更好。 – Tomalak

1

基本上,这是一个分组问题。如果您使用的是XSLT 2.0,则可以利用其内置的分组功能:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 

<xsl:template match="/root"> 
    <xsl:copy> 
     <xsl:for-each-group select="*" group-starting-with="table"> 
      <table> 
       <text> 
        <xsl:value-of select="."/> 
       </text> 
       <xsl:copy-of select="current-group()[self::foot]"/> 
      </table> 
      <xsl:copy-of select="current-group()[not(self::table or self::foot)]"/> 
     </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet>