есть способ получить только немедленных детей, найденных при вызове DOMElement :: getElementsByTagName? Например, у меня есть документ XML, который имеет элемент категории. Этот элемент категории имеет элементы подкатегории (которые имеют одинаковую структуру), например:
<category> <id>1</id> <name>Top Level Category Name</name> <subCategory> <id>2</id> <name>Sub Category Name</name> </subCategory> ... </category>
Если у меня есть DOMElement, представляющий категорию верхнего уровня,
$topLevelCategoryElement->getElementsByTagName('id');
вернет список с узлами для всех элементов «id», где я хочу только один из верхнего уровня. Любой способ сделать это за пределами использования XPath?
Боюсь, что нет. Вам придется проходить через детей или использовать XPath.
for ($n = $parent->firstChild; $n !== null; $n = $n->nextSibling) { if ($n instanceof DOMElement && $n->tagName == "xxx") { //... } }
Пример с XPath и вашим XML-файлом:
$xml = ...; $d = new DOMDocument(); $d->loadXML($xml); $cat = $d->getElementsByTagName("subCategory")->item(0); $xp = new DOMXpath($d); $q = $xp->query("id", $cat); //note the second argument echo $q->item(0)->textContent;
дает 2
.
Что-то вроде этого должно делать
/** * Traverse an elements children and collect those nodes that * have the tagname specified in $tagName. Non-recursive * * @param DOMElement $element * @param string $tagName * @return array */ function getImmediateChildrenByTagName(DOMElement $element, $tagName) { $result = array(); foreach($element->childNodes as $child) { if($child instanceof DOMElement && $child->tagName == $tagName) { $result[] = $child; } } return $result; }
edit : добавлен экземпляр проверки DOMElement
Я не использую PHP, но если PHP на самом деле реализует DOM API, как указано в W3C , для любого объекта Node требуется свойство childNodes. Вы должны иметь возможность перебирать всех прямых детей и тестировать их имя тега, чтобы узнать, является ли он тем, кого вы ищете. В зависимости от того, как выглядит ваше дерево, это может быть медленнее, чем получение всех элементов по имени тегов и проверка их позиции в дереве, или это может быть значительно быстрее.
Вы можете сравнивать элементы с помощью ===. Это позволит избежать создания экземпляра объекта Xpath.
$dom = new DOMDocument(); $dom->loadXML($xmlString); $return = array(); //find your top level element $topLevelElement = $dom->getElementsByTagName('category'); //find all `id` child elements recursively $idElements = $topLevelElement->getElementsByTagName('id'); if ($idElements->length > 0) { foreach ($idElements as $idElement) { if ($idElement->parentNode === $topLevelElement) { $return[] = $idElement; } } } //$return now holds non nested child elements
В зависимости от размера вашего документа XML вы можете обнаружить, что Xpath работает лучше. Однако с точки зрения элегантности это решение является более чистым.