根据两个属性值的组合选择唯一节点

时间:2010-08-25 13:54:58

标签: xslt xpath

我有一些看起来像这样的XML:

<Root>
    <Documents>
        <Document id="1"/>
    </Documents>
    <People>
        <Person id="1"/>
        <Person id="2"/>
    </People>
    <Links>
        <Link personId="1" documentId="1"/>
        <Link personId="1" documentId="1"/>
        <Link personId="2" documentId="1"/>
    </Links>
</Root>

我感兴趣的是只获得具有'personId'和'documentId'的独特组合的'Link'元素,所以这两个链接:

<Root>
    <Links>
        <Link personId="1" documentId="1"/>
        <Link personId="2" documentId="1"/>
    </Links>
</Root>

我怎么可能这样做?我找到了this question,虽然我觉得我的情况稍微复杂一些但可能不适用......我估计我需要在某个地方使用key()函数...

提前致谢。

3 个答案:

答案 0 :(得分:3)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kDocAndPeoById" match="Document|Person" use="@id"/>
    <xsl:key name="kLinksByIds" match="Link" 
             use="concat(@personId,'++',@documentId)"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Documents|People|
     Link[count(.|key('kLinksByIds',concat(@personId,'++',@documentId))[1])!=1
          or not(key('kDocAndPeoById',@personId)/self::Person)
          or not(key('kDocAndPeoById',@documentId)/self::Document)]"/>
</xsl:stylesheet>

输出:

<Root>
    <Links>
        <Link personId="1" documentId="1"></Link>
        <Link personId="2" documentId="1"></Link>
    </Links>
</Root>

如果你没有兴趣检查是否有这样的Document或Person @id,那么这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kLinksByIds" match="Link" 
              use="concat(@personId,'++',@documentId)"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Documents|People|
  Link[count(.|key('kLinksByIds',concat(@personId,'++',@documentId))[1])!=1]"/>
</xsl:stylesheet>

输出:

<Root>
    <Links>
        <Link personId="1" documentId="1"></Link>
        <Link personId="2" documentId="1"></Link>
    </Links>
</Root>

答案 1 :(得分:1)

您可以将多个选择器属性组合到XPath查询中,而不必只是一个attribute = value对。

Find through multiple attributes in XML

答案 2 :(得分:0)

您需要使用类似的内容过滤<Link>,其中current()函数返回<Link>您要检查的唯一性。

.[not(preceding-sibling::Link[@personId   = current()/@personId and
                              @documentId = current()/@documentId])]

preceding-sibling::轴用于查找较早的<Link>元素,方括号中的部分用于检查匹配的ID号。包裹整个表达式的not()表示只有当前面的兄弟匹配没有匹配时,整个括号表达式才为真,即没有先前的<Link>具有相同的人和文档ID。

我的XSLT知识生疏了,所以我会把那部分留给你。我在想的是你首先找到所有链接,比如//Link,然后在上面的XPath的第二步中过滤它们。我努力了,但想不出任何办法一步到位,因为这依赖于current()功能。