Jak wybrać unikalne węzły

Znalazłem tę stronę opisującą metodę Muenchiana, ale myślę, że źle ją stosuję.

Rozważ, że zwróci to zbiór wieków:

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

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

Ale chciałbym, aby nodeset tylko jeden węzeł dla każdego wieku.

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

Każdy z nich wydaje się zwracać wszystkie wartości, zamiast unikalnych wartości:

/doc/class/person/descriptive[(@name='age')][not(value=preceding-sibling::value)]/value
/doc/class/person/descriptive[(@name='age')]/value[not(value=preceding-sibling::value)]
Co mi umyka?
 14
Author: Mathias Müller, 2008-10-23

5 answers

Oto przykład:

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

I XPath:

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

Wyniki: A B C D

EDIT : Jak skomentował mousio, nie uchwyci to ostatniego elementu na liście, jeśli tylko się pojawi. Biorąc to pod uwagę i komentarz Fëanora, tutaj jest lepsze rozwiązanie: {]}

/root/item[not(.=preceding-sibling::item)]
 22
Author: BQ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-26 13:45:05

Oto Muenchiańska Wersja odpowiedzi BQ na podstawie jego danych:

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

Transformata ta daje

A
B
C
D

  1. powyższe wyszukiwanie key() w szablonie dla item zwraca nodeset zawierający wszystkie elementy item z tą samą wartością łańcuchową co węzeł kontekstowy.
  2. jeśli zastosujesz funkcję, która oczekuje pojedynczego węzła do nodesetu, będzie ona działać na pierwszym węźle w tym nodesecie.
  3. wszystkie połączenia do generate-id() są gwarantowane generuje ten sam ID dla danego węzła podczas pojedynczego przejścia przez dokument.
  4. dlatego test będzie prawdziwy, jeśli węzeł kontekstowy jest tym samym węzłem, co pierwszy zwrócony przez wywołanie key().
 14
Author: ChuckB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 14:49:18

Dla tych, którzy nadal szukają select distinct w XSLT:

Z XSLT 2.0, możesz użyć "distinct-values(/doc/class/person/descriptive[(@name='age')]/value) "

 3
Author: Grégory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-21 10:54:46

Metoda Muenchiana używa kluczy do tworzenia unikalnej listy elementów z zestawu węzłów. Dla Twoich danych klucz wyglądałby tak:

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

Stamtąd osobiście użyłbym xsl:apply-templates, ale możesz użyć następującego atrybutu select w innych miejscach:

<!-- 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]" />

Dopasowanie do powyższego jest znacznie prostsze:

<xsl:template match="person/descriptive[@name = 'age']/value">
    <strong>Age: </strong><xsl:value-of select="." />
</xsl:template>
 2
Author: matpie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-11 00:08:14

Czy nie brakuje Ci odniesienia do 'opisowej' zaraz po poprzedzającej wartości? Coś takiego:

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

(nie testowałem)

 1
Author: JacobE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 22:29:52