Giải quyết Vấn đề 1:
Các W3C defines: ý nghĩa của các thuộc tính xml:id
như một thuộc tính ID trong tài liệu XML và xác định xử lý của thuộc tính này để xác định ID trong không có xác nhận hợp lệ, mà không tìm nạp tài nguyên bên ngoài và không phụ thuộc vào một tập hợp con bên trong.
Nói cách khác, khi bạn sử dụng
$element->setAttribute('xml:id', 'test');
bạn không cần phải gọi setIdAttribute
, cũng không phải chỉ định một DTD hay Schema. DOM sẽ nhận ra thuộc tính xml:id
khi được sử dụng với getElementById
mà không cần phải xác thực tài liệu hoặc bất kỳ thứ gì. Đây là cách tiếp cận ít nỗ lực nhất. Tuy nhiên, lưu ý rằng tùy thuộc vào hệ điều hành và phiên bản libxml của bạn, bạn sẽ không nhận được getElementById
để hoạt động.
Giải quyết Problem2:
Ngay cả với ID không được fetchable với getElementById
, bạn có thể vẫn còn rất nhiều lấy chúng với XPath:
$xpath->query('/pages/page[@id=1]');
chắc chắn sẽ làm việc. Và bạn cũng có thể lấy trẻ em sản phẩm cho một trang cụ thể trực tiếp:
$xpath->query('//pages/page[@id=1]/products');
Ngoài ra, có rất ít bạn có thể làm để làm cho DOM đang nhìn ít tiết, bởi vì nó thực sự là một giao diện verbose. Nó phải là, bởi vì DOM is a language agnostic interface, again defined by the W3C.
EDIT sau khi bình luận dưới đây
Nó đang làm việc như tôi đã giải thích ở trên. Đây là một trường hợp thử nghiệm đầy đủ cho bạn. Phần đầu tiên là dành cho viết tệp XML mới với DOM. Đó là nơi bạn cần đặt thuộc tính xml:id
. Bạn sử dụng tùy chọn này thay vì thuộc tính id, không phải không gian tên thông thường.
// Setup
$dom = new DOMDocument;
$dom->formatOutput = TRUE;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML('<pages/>');
// How to set a valid id attribute when not using a DTD or Schema
$page1 = $dom->createElement('page');
$page1->setAttribute('xml:id', 'p1');
$page1->appendChild($dom->createElement('product', 'foo1'));
$page1->appendChild($dom->createElement('product', 'foo2'));
// How to set an ID attribute that requires a DTD or Schema when reloaded
$page2 = $dom->createElement('page');
$page2->setAttribute('id', 'p2');
$page2->setIdAttribute('id', TRUE);
$page2->appendChild($dom->createElement('product', 'bar1'));
$page2->appendChild($dom->createElement('product', 'bar2'));
// Appending pages and saving XML
$dom->documentElement->appendChild($page1);
$dom->documentElement->appendChild($page2);
$xml = $dom->saveXML();
unset($dom, $page1, $page2);
echo $xml;
này sẽ tạo ra một file XML như thế này:
<?xml version="1.0"?>
<pages>
<page xml:id="p1">
<product>foo1</product>
<product>foo2</product>
</page>
<page id="p2">
<product>bar1</product>
<product>bar2</product>
</page>
</pages>
Khi bạn đọc trong XML một lần nữa, ví dụ DOM mới không còn biết bạn đã tuyên bố không namespaced id
thuộc tính như Thuộc tính ID với setIdAttribute
. Nó sẽ vẫn nằm trong XML, nhưng thuộc tính id sẽ chỉ là một thuộc tính thông thường. You have to be aware that ID attributes are special in XML.
// Load the XML we created above
$dom = new DOMDocument;
$dom->loadXML($xml);
Bây giờ cho một số xét nghiệm:
echo "\n\n GETELEMENTBYID RETURNS ELEMENT WITH XML:ID \n\n";
foreach($dom->getElementById('p1')->childNodes as $product) {
echo $product->nodeValue; // Will output foo1 and foo2 with whitespace
}
Các công trình trên, bởi vì một DOM phân tích cú pháp phù hợp có nhận xml:id
là một thuộc tính ID, không phân biệt bất kỳ DTD hay Schema. Điều này được giải thích trong các thông số kỹ thuật được liên kết ở trên. Lý do kết quả đầu ra khoảng trắng là do đầu ra được định dạng có các nút DOMText giữa thẻ mở, hai thẻ sản phẩm và thẻ đóng, vì vậy chúng tôi đang lặp qua năm nút. Khái niệm nút là rất quan trọng để hiểu khi làm việc với XML.
echo "\n\n GETELEMENTBYID CANNOT FETCH NORMAL ID \n\n";
foreach($dom->getElementById('p2')->childNodes as $product) {
echo $product->nodeValue; // Will output a NOTICE and a WARNING
}
Ở trên sẽ không hoạt động, vì id
không phải là thuộc tính ID. Để trình phân tích cú pháp DOM nhận ra nó như vậy, bạn cần một DTD hoặc Schema và XML phải được xác nhận hợp lệ với nó.
echo "\n\n XPATH CAN FETCH NORMAL ID \n\n";
$xPath = new DOMXPath($dom);
$page2 = $xPath->query('/pages/page[@id="p2"]')->item(0);
foreach($page2->childNodes as $product) {
echo $product->nodeValue; // Will output bar1 and bar2
}
XPath mặt khác là theo nghĩa đen về các thuộc tính, có nghĩa là bạn có thể truy vấn DOM cho các phần tử trang với thuộc tính id
nếu getElementById
không có sẵn. Lưu ý rằng để truy vấn trang có ID p1, bạn phải bao gồm không gian tên, ví dụ: @xml:id="p1"
.
echo "\n\n XPATH CAN FETCH PRODUCTS FOR PAGE WITH ID \n\n";
$xPath = new DOMXPath($dom);
foreach($xPath->query('/pages/page[@id="p2"]/product') as $product) {
echo $product->nodeValue; // Will output bar1 and bar2 w\out whitespace
}
Và như đã nói, bạn cũng có thể sử dụng XPath để truy vấn bất kỳ điều gì khác trong tài liệu.Điều này sẽ không xuất ra khoảng trắng, vì nó sẽ chỉ trả về các phần tử product
bên dưới trang có id p2.
Bạn cũng có thể duyệt toàn bộ DOM từ nút. Đó là một cấu trúc cây. Vì DOMNode là lớp quan trọng nhất trong DOM, bạn muốn làm quen với nó.
echo "\n\n TRAVERSING UP AND DOWN \n\n";
$product = $dom->getElementsByTagName('product')->item(2);
echo $product->tagName; // 'product'
echo $dom->saveXML($product); // '<product>bar1</product>'
// Going from bar1 to foo1
$product = $product->parentNode // Page Node
->parentNode // Pages Node
->childNodes->item(1) // Page p1
->childNodes->item(1); // 1st Product
echo $product->nodeValue; // 'foo1'
// from foo1 to foo2 it is two(!) nodes because the XML is formatted
echo $product->nextSibling->nodeName; // '#text' with whitespace and linebreak
echo $product->nextSibling->nextSibling->nodeName; // 'product'
echo $product->nextSibling->nextSibling->nodeValue; // 'foo2'
Trên sidenote, vâng, tôi có lỗi đánh máy trong mã gốc ở trên. Đó là product
không phải products
. Nhưng tôi thấy khó có thể khẳng định mã không hoạt động khi tất cả những gì bạn phải thay đổi là s
. Điều đó chỉ cảm thấy quá nhiều như muốn được spoonfed.
Tôi cho rằng bạn vừa đưa ra một phác thảo về cấu trúc của tài liệu XML của bạn? Bởi vì nó không phải là XML những gì bạn đã đăng (tôi chỉ muốn chắc chắn;)). –
Tất nhiên nó chỉ là một phác thảo. XML xác nhận tốt và có vẻ không giống mã của tôi: o – fabrik
các hàm simplexml có quá đơn giản cho các nhu cầu của bạn không? – stillstanding