Как получить первый уровень элементов dom Domodocument PHP?

Как получить первый уровень элементов dom Domodocument PHP?

Пример с кодом, который не работает - взят из Q & A: http://stackoverflow.com/info/1540302/how-to-get-nodes-in-first-level-using-php-domdocument

<?php
$str=<<< EOD
<div id="header">
</div>
<div id="content">
    <div id="sidebar">
    </div>
    <div id="info">
    </div>
</div>
<div id="footer">
</div>
EOD;

$doc = new DOMDocument();
$doc->loadHTML($str);
$xpath = new DOMXpath($doc);
$entries = $xpath->query("/");
foreach ($entries as $entry) {
    var_dump($entry->firstChild->nodeValue);
}
?>

Спасибо, Йосеф

Ответ 1

Первый уровень элементов ниже корня node можно получить с помощью

$dom->documentElement->childNodes

Свойство childNodes содержит DOMNodeList, который вы можете выполнять с помощью foreach.

См. DOMDocument::documentElement

Это атрибут удобства, который обеспечивает прямой доступ к дочернему элементу node, который является элементом документа документа.

и DOMNode::childNodes

DOMNodeList, содержащий все дочерние элементы этого node. Если детей нет, это пустой список DOMNodeList.

Так как childNodes является свойством DOMNode, то любой класс, расширяющий DOMNode (который является большинством классов в DOM), обладает этим свойством, поэтому для получения первого уровня элементов ниже a DOMElement необходимо получить доступ это свойство дочернего узла DOMElement.


Обратите внимание: если вы используете DOMDocument::loadHTML() для недопустимых HTML или частичных документов, модуль парсера HTML добавит скелет HTML с тегами html и body, поэтому в дереве DOM HTML в вашем примере будет

<!DOCTYPE html … ">
<html><body><div id="header">
</div>
<div id="content">
    <div id="sidebar">
    </div>
    <div id="info">
    </div>
</div>
<div id="footer">
</div></body></html>

которые вы должны учитывать при прохождении или использовании XPath. Следовательно, используя

$dom = new DOMDocument;
$dom->loadHTML($str);
foreach ($dom->documentElement->childNodes as $node) {
    echo $node->nodeName; // body
}

будет выполнять только итерацию <body> DOMElement node. Зная, что libxml добавит скелет, вам придется перебирать дочерниеNodes элемента <body>, чтобы получить элементы div из вашего примерного кода, например.

$dom->getElementsByTagName('body')->item(0)->childNodes

Однако при этом будут учитываться любые узлы пробела, поэтому вам нужно либо установить preserveWhiteSpace на false, либо запросить правильный элемент nodeType, если вы хотите получить только узлы DOMElement, например

foreach ($dom->getElementsByTagName('body')->item(0)->childNodes as $node) {
    if ($node->nodeType === XML_ELEMENT_NODE) {
        echo $node->nodeName;
    }
}

или используйте XPath

$dom->loadHTML($str);
$xpath = new DOMXPath($dom);
foreach ($xpath->query('/html/body/*') as $node) {
    echo $node->nodeName;
}

Дополнительная информация: