2013-08-08 11 views
6

Unten habe ich ein PHP-Skript, das ich suchen muss durch eine XML-Datei und finde die ID für <AnotherChild>. Aus irgendeinem Grund gibt es im Moment 0 Ergebnisse und ich kann nicht herausfinden warum. Wenn jemand sehen kann, warum es 0 Ergebnisse zurückgibt, würde ich es wirklich schätzen, wenn sie mich wissen lassen könnten, warum.PHP XPath Suche zurück 0 Ergebnisse

XML:

<TransXChange xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.transxchange.org.uk/" xsi:schemaLocation="http://www.transxchange.org.uk/ http://www.transxchange.org.uk/schema/2.1/TransXChange_general.xsd" CreationDateTime="2013-07-12T18:12:21.8122032+01:00" ModificationDateTime="2013-07-12T18:12:21.8122032+01:00" Modification="new" RevisionNumber="3" FileName="swe_44-611A-1-y10.xml" SchemaVersion="2.1"> 
    <Node1>...</Node1> 
    <Node2>...</Node2> 
    <Node3>...</Node3> 
    <Node4>...</Node4> 
    <Node5>...</Node5> 
    <Node6>...</Node6> 
    <Node7> 
     <Child> 
      <id>ABCDEFG123</id> 
     </Child> 
     <AnotherChild> 
      <id>ABCDEFG124</id> 
     </AnotherChild> 
    </Node7> 
    <Node8>...</Node8> 
</TransXChange> 

PHP:

<?php 

    $xmldoc = new DOMDocument(); 
    $xmldoc->load("directory1/directory2/file.xml"); 

    $xpathvar = new DOMXPath($xmldoc); 
    $xpathvar->registerNamespace('transXchange', 'http://www.transxchange.org.uk/'); 

    $queryResult = $xpathvar->query('//AnotherChild/id'); 
    foreach($queryResult as $result) { 
    echo $result->textContent; 
    } 
?> 

Dank

+0

möglich Duplikat [XPath mit Namespace] (http: // stackoverflow.com/questions/9827685/xpath-with-namespace) – Wrikken

+0

[dieser kann jedoch besser sein] (http://stackoverflow.com/questions/6475394/php-xpath-query-on-xml-with-default- Namespace-Bindung) – Wrikken

+0

@Wrikken Ich habe mir nur diese beiden Antworten angesehen und kann nicht sehen, wie ich meinen Code anpassen würde, um mein Problem zu beheben? – jskidd3

Antwort

9

Die zwei Fragen in den Kommentaren verbunden sind eigentlich diese Frage zu beantworten, aber sie nicht ganz klar genug warum sie beantworten es IMO, so werde ich das folgende my answer in chat hinzufügen.


Betrachten Sie das folgende XML-Dokument:

<root> 
    <child> 
    <grandchild>foo</grandchild> 
    </child> 
</root> 

Dies hat keine xmlns an alle Attribute, die bedeutet, dass Sie //grandchild abfragen und erhalten das Ergebnis Sie erwarten. Jeder Knoten befindet sich im Standard-Namespace, sodass alles adressiert werden kann, ohne einen Namespace in XPath zu registrieren.

Nun ist diese betrachten:

<root xmlns="http://www.bar.com/"> 
    <child> 
    <grandchild>foo</grandchild> 
    </child> 
</root> 

Dieser einen Namespace von http://www.bar.com/ erklärt und als Ergebnis Sie müssen diesen Namespace verwenden, um einen Mitgliedsknoten zu adressieren.

Wie Sie bereits herausgefunden haben, die Art und Weise, dies zu tun ist DOMXPath::registerNamespace() zu verwenden - aber der entscheidende Punkt, die Sie verpasst ist, dass (in PHP XPath-Implementierung) jeder Namespace muss mit einem Präfix registriert werden, und Sie müssen verwenden Dieses Präfix adressiert Knoten, die zu ihm gehören. Es ist nicht möglich, einen Namespace in XPath mit einem leeren Präfix zu registrieren.

So, das zweite Beispiel oben gegeben, sehen wir uns an, wie wir die ursprüngliche //grandchild Abfrage ausführen würde:

<?php 

    $doc = new DOMDocument(); 
    $doc->loadXML($xml); 

    $xpath = new DOMXPath($doc); 
    $xpath->registerNamespace('bar', 'http://www.bar.com/'); 

    $nodes = $xpath->query('//bar:grandchild'); 
    foreach($nodes as $node) { 
     // do stuff with $node 
    } 

Hinweis, wie wir den Namespace registriert unter Verwendung ihrer URI, und wir spezifiziert ein Präfix. Obwohl das ursprüngliche XML dieses Präfix nicht enthielt, verwenden wir das Präfix in der Abfrage - example.

Um zu verstehen, warum, an einem anderen Stück XML aussehen läßt:

<baz:root xmlns:baz="http://www.bar.com/"> 
    <baz:child> 
    <baz:grandchild>foo</baz:grandchild> 
    </baz:child> 
</baz:root> 

Dieses Dokument semantisch identisch mit dem zweiten ist - das Codebeispiel würde gleich gut funktionieren entweder (proof). Das Präfix ist vom Namespace getrennt. Beachten Sie, dass der XPath das Präfix verwendet, obwohl dieses ein baz:-Präfix in dem Dokument verwendet. Dies liegt daran, dass das Think, das den Namespace identifiziert, die URI nicht das Präfix ist.

Also, wenn ein Dokument einen Namespace verwendet, müssen wir mit den Namespace arbeiten, nicht gegen sie, durch den Namespace in XPath Registrierung und mit dem Präfix wir es gegen registrierten beliebigen Knoten zu verweisen, die zu diesem Namespace gehören.

Für Vollständigkeit, wenn wir diese Prinzipien auf das Originaldokument gelten, die Abfrage, die Sie mit dem Code in der Frage verwenden würde, ist:

//transXchange:AnotherChild/transXchange:id 
+0

Danke für das Verlassen einer so tollen, detaillierten Antwort! – jskidd3

+0

@JoelKidd Kein Problem, es gibt ein paar Stammgäste im PHP-Raum im Chat, die ziemlich vertraut sind mit XML und XPath, wenn Sie weitere Fragen haben, hakre [Blogs] (http://hakre.wordpress.com/) über einige der Feinheiten regelmäßig, wenn Sie es auschecken wollen :-) – DaveRandom

+0

Das ist super! Ich werde gelesen, den Blog mit einem Lesezeichen versehen. Danke noch einmal. – jskidd3

2

um dieses Problem zu beheben ich zuerst den Namespace registriert:

$xpathvar->registerNamespace('transXchange', 'http://www.transxchange.org.uk/'); 

und modifiziert dann die Abfrage wie Also:

$queryResult = $xpathvar->query('//transXchange:AnotherChild/transXchange:id'); 

Die ID wurde erfolgreich zurückgegeben.