代码之家  ›  专栏  ›  技术社区  ›  pc1oad1etter

如何选择唯一节点

  •  14
  • pc1oad1etter  · 技术社区  · 16 年前

    我发现 this page 描述明钦方法,但我认为我用错了。

    /doc/class/person/descriptive[(@name='age')]/value
    

    1..2..2..2..3..3..4..7

    但是我想要一个节点集,每个年龄只有一个节点。

    1..2..3..4..7

    每种方法似乎都返回所有值,而不是唯一值:

    /doc/class/person/descriptive[(@name='age')][not(value=preceding-sibling::value)]/value
    /doc/class/person/descriptive[(@name='age')]/value[not(value=preceding-sibling::value)]
    

    我错过了什么?

    5 回复  |  直到 11 年前
        1
  •  24
  •   BQ.    13 年前

    <root>
        <item type='test'>A</item>
        <item type='test'>B</item>
        <item type='test'>C</item>
        <item type='test'>A</item>
        <item type='other'>A</item>
        <item type='test'>B</item>
        <item type='other'>D</item>
        <item type=''>A</item>
    </root>
    

    还有XPath:

    //preceding::item/preceding::item[not(.=preceding-sibling::item)]/text()
    

    结果: A、B、C、D

    编辑 正如mousio所评论的,如果列表中的最后一项是唯一一次出现,那么它不会捕获该项。考虑到这一点和Fanor的评论,这里有一个更好的解决方案:

    /root/item[not(.=preceding-sibling::item)]
    
        2
  •  14
  •   ChuckB    16 年前

    以下是使用BQ数据的慕尼黑版本的答案:

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <xsl:output indent="yes" method="text"/>
      <xsl:key name="item-by-value" match="item" use="."/>
    
      <xsl:template match="/">
        <xsl:apply-templates select="/root/item"/>
      </xsl:template>
    
      <xsl:template match="item">
        <xsl:if test="generate-id() = generate-id(key('item-by-value', normalize-space(.)))">
          <xsl:value-of select="."/>
          <xsl:text>
    </xsl:text>
        </xsl:if>
      </xsl:template>
    
      <xsl:template match="text()">
        <xsl:apply-templates/>
      </xsl:template>
    </xsl:stylesheet>
    

    这一转变产生了

    A.

    C

    1. 这个 key() 在模板中查找上面的 item 返回包含所有节点的节点集 与上下文节点具有相同字符串值的元素。
    2. 如果您将一个函数应用于一个节点集,它将在该节点集中的第一个节点上运行。
    3. generate-id() 保证在文档的单次传递过程中为给定节点生成相同的ID。
    4. 键() 呼叫
        3
  •  5
  •   Grégory    11 年前

    对于仍在XSLT中查找select distinct的用户:

    使用XSLT2.0, 你可以用 “不同的值(/doc/class/person/description[(@name='age')]]/value)”

        4
  •  2
  •   matpie    15 年前

    <!-- Set the name to whatever you want -->
    <xsl:key name="PeopleAges" match="/doc/class/person/descriptive[@name = 'age']/value" use="." />
    

    从那以后,我会亲自使用 xsl:apply-templates 但是您可以使用以下命令 select 其他地方的属性:

    <!-- you can change `apply-templates` to: `copy-of` or `for-each`. -->
    <xsl:apply-templates select="/doc/class/person/descriptive[@name = 'age']/value[count(. | key('PeopleAges', .)[1]) = 1]" />
    

    上述内容的附带匹配要简单得多:

    <xsl:template match="person/descriptive[@name = 'age']/value">
        <strong>Age: </strong><xsl:value-of select="." />
    </xsl:template>
    
        5
  •  1
  •   JacobE    16 年前

    在前面的值之后,是否缺少对“描述性”的引用?有些事情如下:

    /doc/class/person/descriptive[(@name='age')][not(value=preceding-sibling::descriptive[@name='age']/value)]/value
    

    (尚未测试)