2008-12-10 14 views
5

Dla arkusza stylów, który piszę (w rzeczywistości dla ich zestawu, z których każdy generuje inny format wyjściowy), muszę ocenić, czy pewna wartość jest obecna na liście wartości. W tym przypadku testowana wartość pochodzi z atrybutu elementu. Lista, która ma zostać przetestowana, pochodzi z inwokacji arkusza stylów i jest traktowana jako najwyższy poziom <xsl:param> (należy ją podać w linii poleceń, gdy wywołuję xsltproc lub wywołanie równoważne Saxon). Na przykład, wartość wejściowa może być:Testowanie elementu w liście

v0_01,v0_10,v0_99 

natomiast wartości atrybutów każdy będzie wyglądać bardzo podobnie jeden takiej wartości. (Nie ma znaczenia, czy przecinek służy do oddzielania wartości, czy spacji, nie jest ważne - na razie wybrałem przecinek, ponieważ zamierzam przekazać wartość przez przełącznik wiersza polecenia do xsltproc, a użycie spacji wymagałoby podania argumentu, i jestem leniwy - wystarczy, aby nie chcieć wpisywać dodatkowych dwóch znaków.)

Czego szukam to coś podobnego do Perla grep, w którym widzę, czy aktualnie posiadana wartość jest zawarta na liście. Można to zrobić za pomocą testów podłańcuchowych, ale musi to być sprytne, aby nie uzyskać fałszywego wyniku pozytywnego (v0_01 nie powinien pasować do ciągu zawierającego v0_011). Wydaje się, że jedynym nieskalarnym typem danych obsługiwanym przez XSL/XSLT jest zestaw węzłów. Przypuszczam, że możliwe jest przekonwertowanie listy na zbiór węzłów tekstowych, ale wydaje się to zbytnim zabijaniem, nawet w porównaniu do robienia testu podłańcuchowego z dodatkowymi sprawdzaniami granic, aby zapobiec fałszywym dopasowaniom.

Odpowiedz

8

W rzeczywistości używanie funkcji łańcuchowych XPath jest właściwą metodą. Wszystko, co musisz zrobić, to przetestować ograniczniki również:

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

zwróci wartość logiczną. Lub można użyć jednego z nich:

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

lub

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

Jeśli masz pusty ciąg W rezultacie $value nie ma na liście.

EDIT:

@ komentarz Dimitre jest poprawna: substring-before() (lub substring-after()) również zwraca pusty ciąg jeśli znaleziony tekst jest pierwszy (lub ostatni) na liście. Aby tego uniknąć, dodałem coś na początku i na końcu listy. Wciąż zalecany jest sposób: .

+0

Faktycznie, dla moich celów, wygląda na to, że zrobi to funkcja "zawiera" (używając sugerowanego wypełnienia). Wpadłem na to, że szukałem tej funkcjonalności w samym XSLT, kiedy powinienem był szukać XPath. – rjray

+0

Dodano funkcję contains(), która mi umknęła. Dzięki. :-) – Tomalak

+0

@ Tomalak: Wyrażenie substring-before() zostanie ocenione na '', nawet jeśli wartość jest zawarta na liście (gdy jest to pierwsza wartość). Podobnie wyrażenie substring-after() zwraca wartość ", gdy wartość jest ostatnią na liście. Dlatego tylko wyrażenie contains() jest poprawne. –

4

Oprócz XPath 1,0 rozwiązania polegającego Tomalak,

Stosując XPath 2.0 można tokenize listę wartości:

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

rozpoznawaną true() wtedy i tylko wtedy, gdy $value jest zawarty w liście wartości $list

+0

Czy nie lepiej napisać w ten sposób: tokenize ($ list, ',') = wartość $ – lagivan

+1

@agagan, To zależy od tego, co rozumiemy lepiej. Myślę, że używanie "istnieje" (jako słowo lub koncepcja) jest od razu bardziej zrozumiałe i naturalne dla ludzi, którzy nie są przyzwyczajeni do skrótów XPath. Również funkcja "exist()" może być lepiej zoptymalizowana niż ogólne porównanie wartości. –

Powiązane problemy