web-dev-qa-db-ja.com

一意のノードを選択する方法

このページ ミュンチアン法を説明しているのを見つけましたが、間違って適用していると思います。

これにより一連の年齢が返されることを考慮してください。

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

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

ただし、ノードセットには、年齢ごとに1つのノードのみが必要です。

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

何が足りないのですか?

14
pc1oad1etter

次に例を示します。

<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

[〜#〜] edit [〜#〜]:mousioがコメントしたように、リストの最後のアイテムが表示されるのがそれだけの場合、これはリストの最後のアイテムをキャプチャしません。それとFëanorのコメントを考慮に入れて、ここにもっと良い解決策があります:

/root/item[not(.=preceding-sibling::item)]
23
BQ.

これは、彼のデータを使用した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
B
C
D

  1. 上記のitemのテンプレートでのkey()ルックアップは、コンテキストノードと同じ文字列値を持つすべてのitem要素を含むノードセットを返します。
  2. 単一のノードを期待する関数をノードセットに適用すると、そのノードセットの最初のノードで動作します。
  3. generate-id()のすべての呼び出しは、ドキュメントの1回のパス中に、特定のノードに対して同じIDを生成することが保証されています。
  4. したがって、コンテキストノードがkey()呼び出しによって返された最初のノードと同じノードである場合、テストはtrueになります。
14
ChuckB

XSLTで別の選択をまだ探している人のために:

XSLT 2.0では、「distinct-values(/ doc/class/person/description [(@ name = 'age')]/value)」を使用できます。

3
Grégory

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>
2
matpie

前の値の直後に「記述的」への参照がありませんか?次のようなもの:

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

(テストしていません)

1
JacobE