2008-10-22 62 views
13

我发现this page描述了Muenchian方法,但我认为我错误地应用了它。如何选择独特节点

认为这将返回一组年龄:

/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)] 

上午什么我错过了?

+0

糟糕,它看起来像例如我其次是*不是* Muenchian方法 - 而是作者反对它。 – pc1oad1etter 2008-10-22 22:13:37

回答

20

下面是一个例子:

<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() 

结果: ABCD

编辑: 由于mousio评论说,如果它是唯一出现的时间,它不会捕获列表中的最后一项。考虑这一点,考虑F隺nor的评论,这里有一个更好的解决方案:

/root/item[not(.=preceding-sibling::item)] 
+0

很明显,您可以使用额外的XPath根据实际文件中的类型属性或其他数据进行限制。在我的快速测试中,我刚刚在那里。 – 2008-10-22 22:47:30

+0

另请注意,XPath中的“item”不是关键字,它是前面的::和之前的 - sibling ::轴正在处理的XML文档中元素的名称。 – 2008-10-22 22:50:55

1

您是否错过前面的值之后引用'描述性'?有些东西像下面这样:

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

(没有测试过)

14

下面是使用他的数据BQ的答案的Muenchian版本:

<?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> 

这种转变给

一个

C
D

  1. key()item的模板中查找上面返回的节点集包含与上下文节点具有相同字符串值的所有item元素。
  2. 如果您将一个需要单个节点的函数应用于节点集,它将在该节点集中的第一个节点上运行。
  3. 所有对generate-id()的调用都保证在单次传递文档期间为给定节点生成相同的ID。
  4. 因此,如果上下文节点与key()调用返回的第一个节点是相同的节点,则测试将为真。
2

Muenchian方法使用键来创建节点集中项目的唯一列表。为您的数据,关键是这样的:

<!-- 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> 
3

对于那些谁仍在寻找一个SELECT DISTINCT在XSLT:

使用XSLT 2.0, 可以使用 “不同的值(/ DOC /类/人/描述[(@名= '年龄')] /值)”