2010-10-03 11 views
8

Spójrz na dwóch poniższych przykładach:XSLT, dowiedzieć się, czy ostatni węzeł dziecko jest specyficznym elementem

<foo>some text <bar/> and maybe some more</foo> 

i

<foo>some text <bar/> and a last <bar/></foo> 

węzły tekstowe mieszany i bar elementy wewnątrz elementu foo. Teraz jestem w foo i chcę się dowiedzieć, czy ostatnie dziecko to bar. Pierwszy przykład powinien okazać się fałszywy, ponieważ istnieje tekst po bar, ale drugi przykład powinien być prawdziwy.

Jak mogę to zrobić za pomocą XSLT?

+0

Dobre pytanie (+1). Zobacz moją odpowiedź na krótkie rozwiązanie i propozycję stylu pisania. :) –

Odpowiedz

12

Wystarczy wybrać ostatni węzeł elementu <foo>, a następnie użyć osi self, aby rozwiązać typ węzła.

/foo/node()[position()=last()]/self::bar 

To wyrażenie XPath zwraca pusty zestaw (co równa się false boolean), jeśli ostatni węzeł nie jest elementem. Jeśli chcesz konkretnie uzyskać wartość true lub false, zawiń to wyrażenie w funkcji XPath boolean(). Użyj self::* zamiast self::bar, aby dopasować dowolny element jako ostatni węzeł.

Wejście dokument XML:

<root> 
    <foo>some text <bar/> and maybe some more</foo> 
    <foo>some text <bar/> and a last <bar/></foo> 
</root> 

przykład dokument XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output method="text"/> 

<xsl:template match="foo"> 
    <xsl:choose> 
     <xsl:when test="node()[position()=last()]/self::bar"> 
      <xsl:text>bar element at the end&#10;</xsl:text> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:text>text at the end&#10;</xsl:text> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

</xsl:stylesheet> 

Wyjście arkusza stylów:

text at the end 
bar element at the end 
+1

Możesz także uprościć predykat '/ foo/node() [last()]/self :: bar' –

+0

jasso: +1 Dobra odpowiedź. Myślę też, że predykat "[last()]" jest lepszy. –

7

Teraz jestem w foo, a chcesz znaleźć się, jeśli l ast dziecko jest bar

Zastosowanie:

node()[last()][self::bar] 

Wartość logiczna wartość dowolnego niepustego zestaw węzłów jest true() i jest false() inaczej. Możesz użyć powyższego wyrażenia bezpośrednio (niezmodyfikowanego) jako wartość atrybutu test dowolnej wartości <xsl:if> lub <xsl:when>.

Lepiej użyj:

foo/node()[last()][self::bar] 

jako atrybut wystąpienia <xsl:template>match - w ten sposób pisać w czystym stylu "push".

5

Aktualizacja:Ta odpowiedź dotyczy wymagania określonego w oryginalnym tytule pytania: "ustalenie, czy ostatni węzeł podrzędny jest węzłem tekstowym." Ale ciało pytania sugeruje inny wymóg i wydaje się, że ten ostatni wymóg był tym, który jest zamierzony przez PO.

Dwie poprzednie odpowiedzi wyraźnie testują, czy ostatnie dziecko jest elementem bar, zamiast bezpośrednio testować, czy jest to węzeł tekstowy. Jest to poprawne, jeśli foo zawiera tylko "węzły tekstu mieszanego i elementy prętów" i nigdy nie ma zerowych potomków.

Ale może chcesz przetestować bezpośrednio czy ostatnie dziecko jest węzłem text:

  1. Dla czytelności logiki stylesheet
  2. W przypadku element zawiera inne dzieci oprócz elementów i tekstu: np komentarze lub instrukcje przetwarzania
  3. W przypadku element nie ma dzieci

Może wiesz dwa ostatnie nigdy nie pojawią się w twoim przypadku (ale z pytaniem chciałbym domyślać, że nr 3 mógł). A może tak myślisz, ale nie jesteś pewien, a może nie myślałeś o tym. W obu przypadkach jest to bezpieczniejsze przetestować bezpośrednio na to, co rzeczywiście chcesz wiedzieć:

 test="node()[last()]/self::text()" 

Tak więc, opierając się na @ przykładowym kodem Dimitre i wejścia następujące wejścia XML:

<root> 
    <foo>some text <bar/> and maybe some more</foo> 
    <foo>some text <bar/> and a pi: <?foopi param=yes?></foo> 
    <foo>some text <bar/> and a comment: <!-- baz --></foo> 
    <foo>some text and an element: <bar /></foo> 
    <foo noChildren="true" /> 
</root> 

Dzięki tej XSLT szablon:

<xsl:template match="foo"> 
     <xsl:choose> 
     <xsl:when test="node()[last()]/self::text()"> 
      <xsl:text>text at the end;&#10;</xsl:text> 
     </xsl:when> 
     <xsl:when test="node()[last()]/self::*"> 
      <xsl:text>element at the end;&#10;</xsl:text> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:text>neither text nor element child at the end;&#10;</xsl:text> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

plony:

text at the end; 
    neither text nor element child at the end; 
    neither text nor element child at the end; 
    element at the end; 
    neither text nor element child at the end; 
+2

Dobry dodatek. Ale poprzednie odpowiedzi nie zmieniały wymagań OP, ponieważ wydaje się sugerowane przez twoje pierwsze zdanie. Z pytania: "chcesz dowiedzieć się, czy ostatnie dziecko jest barem". –

+1

@Alejandro: dobra uwaga. Nie zauważyłem, że sam OP zmienił wymagania, między tytułem a zdaniem, które zacytowałeś. Przechodziłem po tytule. – LarsH

Powiązane problemy