仅选择一些以下兄弟节点

时间:2016-07-28 13:44:23

标签: xml xslt xpath

我有以下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元素,只要n元素后面有foottable个元素元件。对此有任何帮助表示赞赏。

2 个答案:

答案 0 :(得分: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>使用前一个<foot>的唯一ID(请参阅spec)索引文档中的所有<table>元素。

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

功能等同于:

<table>

在此变体中,不需要XSL密钥。结果是在两种情况下:

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

注意:

  • 请勿使用<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>都是优越的。

答案 1 :(得分: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>