XSL副本中的XPath祖先和后代

时间:2010-06-01 18:53:46

标签: xml xslt xpath

我是XPath的新手,从我在一些有关轴的教程中读到的内容,我仍然想知道如何实现它们。他们的行为并不像我预期的那样。我对使用祖先和后代轴特别感兴趣。

我有以下XML结构:

<file>
    <criteria>
        <root>ROOT</root>
        <criterion>AAA</criterion>
        <criterion>BBB</criterion>
        <criterion>CCC</criterion> 
    </criteria>
    <format>
        <sort>BBB</sort>
    </format>
</file>

我有以下XSL:

<xsl:template match="/">
    <xsl:copy-of select="ancestor::criterion/>
</xsl:template>

什么都不产生!

我预计会产生:

<file>
    <criteria>
    </criteria>
</file>

有人能比我之前阅读过的教程更有帮助地向我解释祖先和后代的轴吗?

谢谢!

2 个答案:

答案 0 :(得分:5)

  

我有以下XSL:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template>
     

什么都不产生!

应该这样做!

ancestor::criterion

是一个相对表达式,这意味着它是从当前节点(由模板匹配)评估的。但是当前节点是文档节点/

因此,上述内容相当于:

/ancestor::criterion

但是,根据定义,文档节点/没有父节点(这意味着没有祖先),因此这个XPath表达式不会选择任何节点。

  

我预计会产生:

<file> 
    <criteria> 
    </criteria> 
</file>

你可能想要的是:

//criterion/ancestor::*

//*[descendant::criterion]

最后两个XPath表达式是等效的,并选择所有具有criterion后代的元素。

最后,为了产生您想要的输出,这是一个可能的解决方案:

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

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

 <xsl:template match="root | criterion | format"/>
</xsl:stylesheet>

在提供的XML文档上应用此转换时,会生成所需的输出

<file>
<criteria>
</criteria>
</file>

答案 1 :(得分:1)

ancestor用于选择XML文档中更高(更接近根)的节点。 descendant用于选择XML文档中较低(子项)的节点。

在您的示例中,ancestor::criterion不会选择任何内容,因为当前节点为/(意味着文档的根目录 - 在这种情况下为<file>),如match="/"所示。根节点没有祖先,因此ancestor轴不执行任何操作。

要获取每个<criterion>元素,您应该使用descendant轴:

<xsl:template match="/">
  <xsl:copy-of select="descendant::criterion"/>
</xsl:template>

或其快捷方式//

<xsl:template match="/">
  <xsl:copy-of select="//criterion"/>
</xsl:template>

这将返回以下内容:

<criterion>AAA</criterion>

使用循环或其他模板,您可以获得所有这三个:

<xsl:template match="/">
  <file>
    <xsl:apply-templates select="//criterion"/>
  </file>
</xsl:template>
<xsl:template match="criterion">
  <xsl:copy-of select="."/>
</xsl:template>

这将产生以下结果:

<file>
  <criterion>AAA</criterion>
  <criterion>BBB</criterion>
  <criterion>CCC</criterion> 
</file>

如果你想获得<file>元素,它也会有点复杂。 XPath指定节点和简单副本不会复制包含所选元素的元素。如果你仍然感到困惑,我可以更多地澄清这一点。