PHP DOMElement :: getElementsByTagName - В любом случае, чтобы получить только непосредственные совпадающие дочерние элементы? - PullRequest
7 голосов
/ 16 июня 2010

Есть ли способ получить только непосредственных потомков, найденных при вызове 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?

Ответы [ 4 ]

15 голосов
/ 16 июня 2010

Боюсь, что нет. Вам придется перебирать детей или использовать 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.

11 голосов
/ 16 июня 2010

Что-то подобное должно сделать

/**
 * 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

2 голосов
/ 16 июня 2010

Я не использую PHP, но если PHP фактически реализует API DOM, так как указывает W3C , то для любого объекта Node должно быть свойство childNodes. Вы должны иметь возможность перебирать всех прямых потомков и проверять их имена тегов, чтобы увидеть, являются ли они теми, кого вы ищете. В зависимости от того, как выглядит ваше дерево, это может быть медленнее, чем получение всех элементов по имени тега и проверка их позиции в дереве, или это может быть значительно быстрее.

0 голосов
/ 23 января 2015

Вы можете сравнивать элементы, используя ===. Это позволит избежать создания экземпляра объекта 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 может работать лучше. Однако с точки зрения элегантности это решение чище.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...