模板在匹配一次时匹配两次

时间:2015-03-17 11:58:29

标签: xml xslt

我有这个XML:

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <shortbody>
        <text>
            testing
        </text>
        <text>
            shortbody
        </text>
    </shortbody>
    <body>
        <paragraph>
            <text>
                A new version of xsltransform.net is released!
            </text>
        </paragraph>
        <paragraph>
            <text>
                We have added the following new features:
            </text>
        </paragraph>
    </body>
</document>

这个XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:template match="body">
    <result>
      <p>
        <xsl:apply-templates select="//shortbody" />
      </p>

      <xsl:for-each select="paragraph">
        <xsl:element name="paragraph">
          <xsl:apply-templates select="."/>
        </xsl:element>
      </xsl:for-each>
    </result>
  </xsl:template>

  <xsl:template match="body/paragraph/text | shortbody/text">
    <xsl:value-of select="."/>
  </xsl:template>

  <xsl:template match="text()"/>
</xsl:stylesheet>

结果是(see fiddle here):

<?xml version="1.0" encoding="UTF-8"?>
testing

shortbody
<result>
  <p>
    testing

    shortbody
  </p>
  <paragraph>
    A new version of xsltransform.net is released!
  </paragraph>
  <paragraph>
    We have added the following new features:
  </paragraph>
</result>

我无法理解为什么shortbody/text的模板被调用两次所以它在我的XML之外结束,但是body/paragrap/text没有被调用两次?我尝试了很多不同的匹配方法,但每次shortbody都在我的XML元素之外。为什么这样,我如何更改我的XSLT,以便模板只匹配<xsl:template match="body">内的调用?

2 个答案:

答案 0 :(得分:2)

您需要添加另一个与根元素document匹配的模板。

尝试添加此内容:

<xsl:template match="document">
    <xsl:apply-templates select="body"/>
</xsl:template>

XML的根元素之外的文本是因为默认模板适用于根元素,它以递归方式处理子节点,最终复制文本节点。

答案 1 :(得分:1)

您看到的是built-in template rules的结果。由于您没有匹配/document的模板,因此应用于document的模板就是此内置模板:

<xsl:template match="document">
  <xsl:apply-templates/>
</xsl:template>

这会将模板应用于document的子级,包括shortbody - 并且在没有匹配shortbody的模板的情况下,默认模板相同:

<xsl:template match="shortbody">
  <xsl:apply-templates/>
</xsl:template>

将模板应用于shortbody的子项。

防止这种情况的一种方法是以这种方式组织样式表:

<xsl:template match="/document">
    <result>
        <xsl:apply-templates/>
    </result>
</xsl:template>

<xsl:template match="shortbody">
    <p>
        <xsl:apply-templates/>
    </p>
</xsl:template> 

<xsl:template match="paragraph">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template> 

请注意,缺少与bodytext匹配的模板。在这里,内置模板规则完全符合要求。