2011-08-19 13 views
7

I mają strukturę podobną do następującej:XPath: Wybierz węzeł, ale nie konkretne elementy potomne

<page id='1'> 
    <title>Page 1</title>  
    <page id='2'> 
    <title>Sub Page 1</title> 
    </page> 
    <page id='3'> 
    <title>Sub Page 2</title> 
    </page>  
</page> 
<page id='4'> 
    <title>Page 2</title> 
</page> 

muszę wybrać stronę przez ID, ale jeśli ta strona ma potomka strony nie chcę, aby powrócić te elementy, ale chcę inne elementy tej strony. Jeśli wybiorę Strona 1 Chcę wrócić, ale nie tytuł strony dziecko ...

//page[@id=1] 

Powyższy dostaje mi strona 1, ale jak mogę wykluczyć, że podstron? Ponadto na stronie może znajdować się dowolna liczba elementów.

//page[@id=1]/*[not(self::page)] 

I odkryli, że ten dostaje mi dane chcę. Jednak dane te powracają jako tablica obiektów z jednym obiektem na element i najwyraźniej wykluczają nazwy elementów ???. Korzystam z PHP SimpleXML na ile to jest warte.

+0

Dobre pytanie, +1. Zobacz moją odpowiedź na krótkie i proste rozwiązanie. :) –

+1

"Jednak dane powracają jako tablica obiektów z jednym obiektem na element." Czym różni się to od tego, co chcesz/potrzebujesz? – LarsH

+0

Dane wraca w innym formacie, w zależności od zapytania xpath, otrzymuję tablicę SimpleXMLElement z jednym ciągiem w każdym i brakuje im nazwy elementów. Pierwszy przypadek zwraca pojedynczy obiekt SimpleXMLElement ze wszystkimi oczekiwanymi parami wartości klucza. Nie rozumiem dlaczego, może otworzę kolejne pytanie. – Ben

Odpowiedz

7

Używaj:

//page[@id=$yourId]/node()[not(self::page)] 

ten wybiera wszystkie węzły, które nie są page i że są dziećmi dowolnym page w dokumencie, wartość ciągu znaków, którego atrybut id jest równa ciągowi zawartemu w $yourId (najprawdopodobniej zastąpi się powyższym numerem $yourId specyficzny, pożądany ciąg, taki jak '1').

Oto prosty XSLT opartego Weryfikacja:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:param name="pId" select="3"/> 

<xsl:template match="/"> 
    <xsl:copy-of select="//page[@id=$pId]/node()[not(self::page)]"/> 
</xsl:template> 
</xsl:stylesheet> 

kiedy ta transformacja jest stosowane na dostarczonym dokumencie XML (zawinięte w jednym górnym węźle, aby go dobrze uformowane):

<pages> 
    <page id='1'> 
     <title>Page 1</title> 
     <page id='2'> 
      <title>Sub Page 1</title> 
     </page> 
     <page id='3'> 
      <title>Sub Page 2</title> 
     </page> 
    </page> 
    <page id='4'> 
     <title>Page 2</title> 
    </page> 
</pages> 

poszukiwany, poprawny wynik jest produkowany:

<title>Sub Page 2</title> 

Należy pamiętać: Jedno założenie, że wartość id jednoznacznie identyfikuje page. Jeśli tak nie jest, proponowane wyrażenie XPath wybierze elementy, których atrybut id ma wartość ciągu $yourId.

W takim przypadku i tylko jeden element page musi zostać wybrany, OP musi określić, który z wielu elementów page z tym id powinien zostać wybrany.

Na przykład, może to być pierwszy:

(//page[@id=$yourId]/node()[not(self::page)])[1] 

lub ostatni:

(//page[@id=$yourId]/node()[not(self::page)])[last()] 

lub ...

+0

Chociaż wygląda to dokładnie dobrze, to tak naprawdę nie działa. Nie jestem pewien, czy coś jest nie tak z xpath w prostym xml PHP, ale to zwraca wiele kopii żądanej strony ??? – Ben

+0

@Ben: To może się zdarzyć tylko wtedy, gdy więcej niż jedna "strona" może mieć tę samą wartość atrybutu "id". Zaktualizowałem swoją odpowiedź, aby objąć tę sprawę. Zapewniam również prostą weryfikację pokazującą, że początkowe wyrażenie XPath wybiera dokładnie jeden element 'page', jeśli wartość' id' jednoznacznie identyfikuje 'stronę'. –

1

Jeśli jesteś zainteresowany tylko w elemencie tytuł, to będzie działać:

//page[@id=1]/title 

Jeśli jednak trzeba inne elementy podrzędne strony, nie jestem pewien, XPath jest odpowiednim narzędziem dla Ciebie. Brzmi bardziej jak coś, do czego nadaje się XSLT, ponieważ to, co naprawdę robisz, przekształca twoje dane.

+0

Niestety potrzebuję dowolnej liczby dowolnych elementów oprócz strony ... – Ben

+0

Zaktualizowana odpowiedź z dodatkowymi informacjami. Zachęcamy do przegłosowania, jeśli będzie to pomocne. :) –

+0

Dzięki, zaczynam myśleć, że Xpath może tego nie robić. Zawsze mogę napisać coś, aby przetworzyć dane, które chcę, ale miałem nadzieję, że zrobię to na poziomie danych. – Ben

0

Jeśli strona zawsze ma tytuł:

//page[@id='1']/*[not(boolean(./title))] 
Powiązane problemy