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? 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)]
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
- powyższe wyszukiwanie
key()
w szablonie dlaitem
zwraca nodeset zawierający wszystkie elementyitem
z tą samą wartością łańcuchową co węzeł kontekstowy. - 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.
- wszystkie połączenia do
generate-id()
są gwarantowane generuje ten sam ID dla danego węzła podczas pojedynczego przejścia przez dokument. - dlatego test będzie prawdziwy, jeśli węzeł kontekstowy jest tym samym węzłem, co pierwszy zwrócony przez wywołanie
key()
.
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) "
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>
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)
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