2008-12-10 5 views
5

Für ein Stylesheet, das ich schreibe (eigentlich für einen Satz von ihnen, die jeweils ein anderes Ausgabeformat erzeugen), muss ich auswerten, ob ein bestimmter Wert in einer Werteliste vorhanden ist. In diesem Fall wird der getestete Wert aus dem Attribut eines Elements genommen. Die Liste, gegen die getestet werden soll, stammt aus dem Aufruf des Stylesheets und wird als oberste Ebene <xsl:param> verwendet (wird in der Befehlszeile angegeben, wenn ich xsltproc oder einen sächsischen äquivalenten Aufruf aufrufen). Zum Beispiel kann der Eingabewert sein:Element-in-List-Test

v0_01,v0_10,v0_99 

während die Attributwerte jeweils sehr ähnlich wie ein solchen Wert zu suchen. (Ob ein Komma zum Trennen von Werten oder ein Leerzeichen verwendet wird, ist nicht wichtig - ich habe jetzt ein Komma gewählt, weil ich den Wert über den Befehlszeilenschalter an xsltproc übergeben möchte und für ein Leerzeichen das Argument angeben müsste. und ich bin faul - genug, um nicht die zusätzlichen zwei Zeichen einzugeben.)

Was ich suche ist etwas ähnlich wie Perls grep, wobei ich sehen kann, ob der Wert, den ich derzeit habe, in der Liste enthalten ist. Es kann mit Sub-String-Tests durchgeführt werden, aber dies müsste clever sein, um kein falsch-positives Ergebnis zu erhalten (v0_01 sollte nicht mit einem String übereinstimmen, der v0_011 enthält). Es scheint, dass der einzige nicht-skalare Datentyp, den XSL/XSLT unterstützt, ein Knotensatz ist. Ich nehme an, dass es möglich ist, die Liste in eine Reihe von Textknoten zu konvertieren, aber das scheint wie ein Über-Kill zu sein, sogar im Vergleich zu einem Unterstring-Test mit zusätzlichen Grenzen, um falsche Übereinstimmungen zu vermeiden.

Antwort

8

Tatsächlich ist die Verwendung von XPath-String-Funktionen der richtige Weg. Alles, was Sie sicherstellen müssen, ist, dass Sie auch die Begrenzer testen:

contains(concat(',' $list, ','), concat(',', $value, ',')) 

würde einen booleschen Wert zurückgeben. Oder Sie könnten eine davon verwenden:

substring-before(concat('|,' $list, ',|'), concat(',', $value, ',')) 

oder

substring-after(concat('|,' $list, ',|'), concat(',', $value, ',')) 

Wenn Sie eine leere Zeichenfolge als Ergebnis zu erhalten, $value ist nicht in der Liste.

EDIT:

@ Dimitre Kommentar korrekt ist: substring-before() (oder substring-after()) würde auch die leere Zeichenfolge zurück, wenn die Zeichenfolge gefunden ist die erste (oder letzte) in der Liste. Um das zu vermeiden, fügte ich am Anfang und am Ende der Liste etwas hinzu. Immer noch ist der empfohlene Weg, dies zu tun.

+0

Eigentlich enthalten ist, für meine Zwecke, es sieht so aus, als würde die "contains" -Funktion funktionieren (mit dem von Ihnen vorgeschlagenen Padding). Was mich auf die Palme brachte, war, dass ich nach dieser Funktionalität in XSLT selbst suchte, als ich in XPath hätte suchen sollen. – rjray

+0

Die contains() Funktion hinzugefügt, die mir entgangen ist. Vielen Dank. :-) – Tomalak

+0

@Tomalak: Der Ausdruck substring-before() wird zu '' ausgewertet, auch wenn der Wert in der Liste enthalten ist (wenn es der erste Wert ist). Entsprechend wird der Ausdruck substring-after() zu '' ausgewertet, wenn der Wert der letzte in der Liste ist. Daher ist nur der Ausdruck contains() korrekt –

4

Neben der Lösung von XPath 1.0 Tomalak bereitgestellt,

XPath Unter Verwendung von 2.0 man kann die Liste der Werte tokenize:

        exists(tokenize($list, ',')[. = $value])

ausgewertet true() wenn und nur wenn $value in der Werteliste $list

+0

Ist es nicht besser, so zu schreiben: tokenize ($ list, ',') = $ value – lagivan

+1

@lagivan, Es kommt darauf an, was wir besser verstehen. Ich denke, dann ist das Verwenden von "existiert" (als ein Wort oder ein Konzept) für Leute, die an die Abkürzungen von XPath nicht gewöhnt sind, sofort verständlicher und natürlicher. Auch die Funktion "exists()" könnte besser optimiert sein als ein allgemeiner Wertevergleich. –