Document Object Model (DOM)
Расширение DOM позволяет работать с XML-документами через DOM API.
Замечание: Расширение DOM использует кодировку UTF-8.
Создание и сохранение
Есть два способа загрузить XML документы в DOM:
- Из файла DomDocument::load():
$dom = new DomDocument(); $dom->load("library.xml");
- Из строки DomDocument::loadXML():
Так же можно импортировать HTML файлы и строки с помощью:$dom = new DomDocument(); $dom->loadXML($xml);
- DomDocument::loadHTMLFile()
- DomDocument::loadHTML()
Для сохранения документов:
- DomDocument::save() - XML в файл
- DomDocument::saveXML() - XML в строку
- DomDocument::saveHTML() - HTML в строку
- DomDocument:saveHTMLFile() - HTML в файл
$dom = new DomDocument();
$dom->load('library.xml');
// Do something with our XML here
// Save to file
if ($use_xhtml) {
$dom->save('library.xml');
} else {
$dom->saveHTMLFile('library.xml');
}
// Output the data
if ($use_xhtml) {
echo $dom->saveXML();
} else {
echo $dom->saveHTML();
}
Чтобы получить доступ к корневому элементу необходимо использовать свойство documentElement.
dom=new DomDocument;
$dom->Load("file.xml");
$root=$dom->documentElement; // Root node
XPath запросы
DomXPath гораздо мощнее чем эквивалент из SimpleXML. Для начала нужно создать объект класса DomXpath, которому передается объект документа DomDocument. Затем регистрируются только нужные пространства имен. В конце выполняется запрос и итерация по результатам.
$dom = new DomDocument();
$dom->load("library.xml");
$xpath = new DomXPath($dom);
$xpath->registerNamespace(
"lib", "http://example.org/library"
);
$result = $xpath->query("//lib:title/text()");
foreach ($result as $book) {
echo $book->data;
}
Вызов DomXpath::query() вернет объект DomNodeList, чтобы узнать сколько в нем элементов можно воспользоваться свойством length. А получить доступ к любому с помощью метода item(). Так же можно пройти по всем результам с помощью цикла foreach().
$result = $xpath->query("//lib:title/text()");
if ($result->length > 0) {
// Random access
$book = $result->item (0);
echo $book->data;
// Sequential access
foreach ($result as $book) {
echo $book->data;
}
}
Изменение XML документов
Чтобы добавить новые данные в загруженный документ, следует создать объект класса DomElement с помощью следующих методов:
- DomDocument::createElement()
- DomDocument::createElementNS()
- DomDocument::createTextNode()
$dom = new DomDocument();
$dom->load("library.xml");
$book = $dom->createElement("book");
$book->setAttribute("meta:isbn", "9781940111001");
$title = $dom->createElement("title");
$text = $dom->createTextNode("Mastering the SPL Library");
$title->appendChild($text);
$book->appendChild($title);
$author = $dom->createElement("author","Joshua Thijssen");
$book->appendChild($author);
$publisher = $dom->createElement(
"pub:publisher", "musketeers.me, LLC."
);
$book->appendChild($publisher);
$dom->documentElement->appendChild($book);
Чтобы добавить элементу атрибут используется метод DomElement::setAttribute(). Чтобы добавить потомка к элементу используется DomElement::appendChild().
Перемещение данных
Так как DOM расширение не заботится о целостности документа, то следует использовать комбинацию методов:
- DomNode::appendChild()
- DomNode::insertBefore()
$dom = new DOMDocument();
$dom->load("library.xml");
$xpath = new DomXPath($dom);
$xpath->registerNamespace(
"lib", "http://example.org/library"
);
$result = $xpath->query("//lib:book");
$result->item(1)->parentNode->insertBefore(
$result->item(1), $result->item(0)
);
В этом примере берется второй book элемент и ставится на место первого. Методы DomNode::appendChild() и DomNode::insertBefore() переносят элемент из одного места в другое. Если нужно копировать элемент, то сначала следует выполнить вызов DomNode::cloneNode():
$dom = new DOMDocument();
$dom->load("library.xml");
$xpath = new DomXPath($dom);
$xpath->registerNamespace(
"lib", "http://example.org/library"
);
$result = $xpath->query("//lib:book");
$clone = $result->item(0)->cloneNode();
$result->item(1)->parentNode->appendChild($clone);
Удаление данных
Возможны три типа данных, которые можно удалить из XML документа: атрибуты, элементы и CDATA. Для каждого типа DOM предоставляет отдельный метод:
- DomNode::removeAttribute()
- DomNode::removeChild()
- DomCharacterData::deleteData()
$xml = <<<XML
<xml>
<text type="misc">some text here</text>
<text type="misc">some more text here</text>
<text type="misc">yet more text here</text>
</xml>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DomXpath($dom);
$result = $xpath->query("//text");
$result->item(0)->parentNode->removeChild($result->item(0));
$result->item(1)->removeAttribute('type');
$result = $xpath->query('text()', $result->item(2));
$result->item(0)->deleteData(0, $result->item(0)->length);
echo $dom->saveXML();
В данном примере мы начинаем с того, что получаем все text элементы. Потом удаляется первый элемент из результата. Потом удаляется атрибут type.
Работа с пространствами имен
В большинстве случаев можно в функции DOM с помощью префиксов прямо передавать пространства имен:
$dom = new DomDocument();
$node = $dom->createElement('ns1:somenode');
$node->setAttribute('ns2:someattribute', 'somevalue');
$node2 = $dom->createElement('ns3:anothernode');
$node->appendChild($node2);
// Set xmlns:* attributes
$node->setAttribute('xmlns:ns1', 'http://example.org/ns1');
$node->setAttribute('xmlns:ns2', 'http://example.org/ns2');
$node->setAttribute('xmlns:ns3', 'http://example.org/ns3');
$dom->appendChild($node);
echo $dom->saveXML();
Можно упростить, используя DomDocument::createElementNS() и DomNode::setAttributeNS():
$dom = new DomDocument();
$node = $dom->createElementNS(
'http://example.org/ns1', 'ns1:somenode'
);
$node->setAttributeNS(
« 'http://example.org/ns2',
'ns2:someattribute',
'somevalue'
);
$node2 = $dom->createElementNS(
'http://example.org/ns3', 'ns3:anothernode'
);
$node3 = $dom->createElementNS(
'http://example.org/ns1', 'ns1:someothernode'
);
$node->appendChild($node2);
$node->appendChild($node3);
$dom->appendChild($node);
$dom->formatOutput = true;
echo $dom->saveXML();
Результат выполнения будет:
<?xml version="1.0"?>
<ns1:somenode xmlns:ns1="http://example.org/ns1"
xmlns:ns2="http://example.org/ns2"
xmlns:ns3="http://example.org/ns3"
ns2:someattribute="somevalue">
<ns3:anothernode xmlns:ns3="http://example.org/ns3"/>
<ns1:someothernode/>
</ns1:somenode>
Взаимодействие с SimpleXML
Можно легко обмениваться документами между SimpleXML и DOM:
- dom_import_simplexml()
- simplexml_import_dom()