如何使用xpath 2.0在节点集中执行交集

时间:2019-07-06 07:08:09

标签: xslt

我有两个不同的节点集,其中包含一个或多个具有相同名称的元素。

我想通过在XPath 2.0和XPath 1.0中使用相交操作来选择这些同名元素。

这是我尝试过的示例代码。

输入:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
    <child1>
    <a />
    <b />
    <d />
    </child1>
    <child2>
    <c />
    <a />
    <d />
    </child2>
    </root>

我尝试过的代码

Xpath 1.0:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <!-- TODO: Auto-generated template -->
    <xsl:variable name="ns2" select="/root/child2/child::*"/>       
    <xsl:copy-of select="/root/child1/child[.=$ns2]"/>
    </xsl:template>
    </xsl:stylesheet>

Xpath 2.0:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <!-- TODO: Auto-generated template -->
    <xsl:variable name="ns1" select="/root/child1/child::*"/>
    <xsl:variable name="ns2" select="/root/child2/child::*"/>       
    <xsl:copy-of select="$ns1 intersect $ns2"/>
    </xsl:template>
    </xsl:stylesheet>

问题:我得到的结果是空的。

预期结果:

    <?xml version="1.0" encoding="UTF-8"?>
    <a/>
    <d/>

请提出我所缺少的内容。

我尝试了两个不同音符集的set操作交集。我在下面附加了我的代码示例,

2 个答案:

答案 0 :(得分:1)

您在这里实际上并不是在进行“交集”,因为child1的所有子元素都与child2的子元素不同。仅仅因为两个元素具有相同的名称,就不会使它们成为相同的元素。

看起来像child1下的元素与child2下的元素同名的元素

如果您希望XSLT 1.0解决方案获得结果,则需要将xsl:copy-of更改为此

<xsl:copy-of select="/root/child1/child::*[.=$ns2]"/>

或者这个...

 <xsl:copy-of select="/root/child1/*[.=$ns2]"/>

但是,这将返回所有child1个子元素,因为您正在检查元素的值是否相同,而不是名称。一种方法是...

<xsl:for-each select="/root/child1/*">
    <xsl:variable name="name" select="local-name()" />
    <xsl:copy-of select=".[$ns2[local-name() = $name]]" />
</xsl:for-each>

或者,如下定义键:

<xsl:key name="child2" match="child2/*" use="local-name()" />

那你就可以做...

<xsl:copy-of select="/root/child1/*[key('child2', local-name())]"/>

在XSLT 2.0中,您可以执行以下操作。...

<xsl:copy-of select="$ns1[some $name in $ns2/local-name() satisfies $name=local-name()]"/>

答案 1 :(得分:0)

不重复蒂姆的正确话,只是针对问题:

XSLT 1.0 (除非使用单个XPath表达式,否则除非使用XSLT标准函数(例如current()),否则:

<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="child1/*">
    <xsl:copy-of select="self::*[../../child2/*[name() = name(current())]]"/>
  </xsl:template>
</xsl:stylesheet>

XPath 2.0

使用:

/*/child1/*[name() = /*/child2/*/name()]

这可以通过下面的XSLT 2.0转换来验证,该转换评估表达式并输出所选节点:

<xsl:stylesheet version="2.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="/">
    <xsl:sequence select=
     "/*/child1/*[name() = /*/child2/*/name()]"/>
  </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<root>
    <child1>
        <a />
        <b />
        <d />
    </child1>
    <child2>
        <c />
        <a />
        <d />
    </child2>
</root>

两个转换都能产生想要的正确结果

<a/>
<d/>