/ / Jak wybrać unikalne węzły - xml, xslt

Jak wybrać unikalne węzły - xml, xslt

znalazłem ta strona opisując metodę Muenchian, ale myślę, że źle ją stosuję.

Załóżmy, że zwróci to zestaw wieków:

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

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

Ale chciałbym, aby węzeł składał się tylko z jednego węzła dla każdego wieku.

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

Każda 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)]

czego mi brakuje?

Odpowiedzi:

22 dla odpowiedzi nr 1

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

EDYTOWAĆ: Jak mousio skomentował to nie przechwytuje ostatniego elementu na liście, jeśli jest to jedyny czas, w którym się pojawia. Biorąc pod uwagę to i uwagę Fëanora, oto lepsze rozwiązanie:

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

14 dla odpowiedzi № 2

Oto mulczań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>

Ta transformacja daje

ZA
b
do
re

  1. The key() odnośnik powyżej w szablonie dla item zwraca zestaw węzłów zawierający wszystkie item elementy o takiej samej wartości ciągu, co węzeł kontekstu.
  2. Jeśli zastosujesz funkcję, która oczekuje pojedynczego węzła na zestaw węzłów, będzie działać na pierwszym węźle w tym zestawie węzłów.
  3. Wszystkie połączenia do generate-id() gwarantują generowanie tego samego identyfikatora dla danego węzła podczas pojedynczego przejścia przez dokument.
  4. Dlatego test będzie prawdą, jeśli węzeł kontekstu jest tym samym węzłem, co pierwszy zwracany przez key() połączenie.

3 dla odpowiedzi nr 3

Dla tych, którzy wciąż szukają odrębnego wyboru w XSLT:

Z XSLT 2.0, możesz użyć "odrębne wartości (/ doc / class / person / descriptive [(@ name =" age ")] / value)"


2 dla odpowiedzi № 4

Metoda Muenchiana wykorzystuje klucze do tworzenia unikatowej 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 skorzystam xsl:apply-templates ale możesz użyć następującego select atrybut 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 towarzyszące powyższym jest o wiele prostsze:

<xsl:template match="person/descriptive[@name = "age"]/value">
<strong>Age: </strong><xsl:value-of select="." />
</xsl:template>

1 dla odpowiedzi nr 5

Aren "t brakuje odniesienia do" opisowe "zaraz po wartości poprzedzającej? Niektóre rzeczy takie jak następujące:

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

(Haven "t przetestował to)