2013-08-08 48 views
6

Dưới đây tôi có một tập lệnh PHP mà tôi cần tìm kiếm thông qua một tệp XML và tìm ID cho <AnotherChild>. Đối với một số lý do, tại thời điểm nó trả về 0 kết quả và tôi không thể hiểu tại sao. Nếu bất cứ ai có thể thấy lý do tại sao nó trả về 0 kết quả tôi thực sự đánh giá cao nếu họ có thể cho tôi biết lý do tại sao.Tìm kiếm XPath PHP trả về 0 kết quả

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; 
    } 
?> 

Cảm ơn

+0

thể trùng lặp của [xpath với namespace] (http: // stackoverflow.com/questions/9827685/xpath-with-namespace) – Wrikken

+0

[cái này có thể tốt hơn] (http://stackoverflow.com/questions/6475394/php-xpath-query-on-xml-with-default- không gian tên-ràng buộc) – Wrikken

+0

@Wrikken Tôi vừa xem xét cả hai câu trả lời đó và không thể xem cách tôi điều chỉnh mã của mình để khắc phục sự cố của mình như thế nào? – jskidd3

Trả lời

9

Hai câu hỏi được liên kết trong nhận xét thực sự trả lời câu hỏi này, nhưng chúng không hoàn toàn đủ rõ ràng lý do tại sao chúng trả lời IMO, vì vậy tôi sẽ thêm sau my answer in chat.


Hãy xem xét các tài liệu XML sau:

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

này không có xmlns thuộc tính ở tất cả, có nghĩa là bạn có thể truy vấn //grandchild và nhận được kết quả mà bạn mong đợi. Mỗi nút nằm trong không gian tên mặc định mặc định, vì vậy mọi thứ có thể được giải quyết mà không cần đăng ký không gian tên trong XPath.

Bây giờ xem xét việc này:

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

này tuyên bố một không gian tên của http://www.bar.com/ và kết quả là bạn phải sử dụng namespace rằng để giải quyết một nút thành viên.

Như bạn đã biết, cách thực hiện điều này là sử dụng DOMXPath::registerNamespace() - nhưng điểm quan trọng mà bạn bỏ lỡ là (trong thực thi XPath của PHP) mọi không gian tên phải được đăng ký bằng tiền tố và bạn phải sử dụng tiền tố đó để giải quyết các nút thuộc về nó. Không thể đăng ký một không gian tên trong XPath với một tiền tố trống.

Vì vậy, cho ví dụ thứ hai ở trên, cho phép xem làm thế nào chúng ta sẽ thực hiện ban đầu //grandchild truy vấn:

<?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 
    } 

Lưu ý cách chúng tôi đăng ký sử dụng tên miền không gian đó là URI, và chúng tôi chỉ định một tiền tố. Mặc dù XML ban đầu không chứa tiền tố này, chúng tôi sử dụng tiền tố trong truy vấn - example.

Để hiểu tại sao, cho phép nhìn vào một mảnh XML:

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

Tài liệu này là ngữ nghĩa giống hệt đến thứ hai - mẫu mã sẽ làm việc tốt như nhau với một trong hai (proof). Tiền tố tách biệt với không gian tên. Lưu ý rằng mặc dù điều này sử dụng tiền tố baz: trong tài liệu, XPath sử dụng tiền tố bar:. Điều này là do suy nghĩ xác định không gian tên là tiền tố URI, không phải là. Vì vậy, khi một tài liệu sử dụng không gian tên, chúng ta phải làm việc với không gian tên, không chống lại nó bằng cách đăng ký không gian tên trong XPath và sử dụng tiền tố mà chúng tôi đã đăng ký để chống lại bất kỳ nút nào thuộc về không gian tên đó.

Để hoàn chỉnh, khi chúng ta áp dụng những nguyên tắc này vào tài liệu ban đầu của bạn, truy vấn mà bạn sẽ sử dụng với mã trong câu hỏi là:

//transXchange:AnotherChild/transXchange:id 
+0

Cảm ơn bạn đã rời câu trả lời tuyệt vời, chi tiết như vậy! – jskidd3

+0

@ JoelKidd Không có vấn đề gì, có một vài quy tắc trong phòng PHP về trò chuyện khá quen thuộc với XML và XPath nếu bạn có thêm bất kỳ truy vấn nào, hakre [blogs] (http://hakre.wordpress.com/) về một số của các phức tạp định kỳ nếu bạn muốn kiểm tra nó ra :-) – DaveRandom

+0

Thật tuyệt vời! Tôi sẽ đọc, đánh dấu trang blog. Cảm ơn một lần nữa. – jskidd3

2

Để khắc phục vấn đề này đầu tiên tôi đăng ký tên miền không gian:

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

Và sau đó sửa đổi các truy vấn như như vậy:

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

Đã trả lại ID thành công.

Các vấn đề liên quan