PHP DOMElement :: getElementsByTagName – De todos modos para obtener solo los hijos coincidentes inmediatos?

¿Hay alguna manera de recuperar solo los hijos inmediatos que encuentra una llamada a DOMElement :: getElementsByTagName? Por ejemplo, tengo un documento XML que tiene un elemento de categoría. Ese elemento de categoría tiene elementos de subcategoría (que tienen la misma estructura), como:

 1 Top Level Category Name  2 Sub Category Name  ...  

Si tengo un DOMElement que representa la categoría de nivel superior,

 $topLevelCategoryElement->getElementsByTagName('id'); 

devolverá una lista con los nodos para todos los elementos ‘id’, donde solo quiero uno del nivel superior. ¿Alguna forma de hacer esto fuera de usar XPath?

Me temo que no. Tendrá que repetir iteraciones entre los niños o usar XPath.

 for ($n = $parent->firstChild; $n !== null; $n = $n->nextSibling) { if ($n instanceof DOMElement && $n->tagName == "xxx") { //... } } 

Ejemplo con XPath y su archivo 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; 

da 2 .

Algo como esto debería hacer

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

editar : instancia adicional de DOMElement check

No uso PHP, pero si PHP realmente implementa la DOM API como se especifica en el W3C , se requiere una propiedad childNodes en cualquier objeto Node. Debería poder iterar sobre todos los niños directos y probar su nombre de etiqueta para ver si son los que está buscando. Dependiendo de cómo se vea su árbol, esto puede ser más lento que obtener todos los elementos por nombre de etiqueta y probar la posición de su árbol, o puede ser significativamente más rápido.

Puedes comparar elementos usando ===. Esto evitará crear instancias de un objeto 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 

Dependiendo del tamaño de su documento XML, es posible que Xpath tenga un mejor rendimiento. Sin embargo, en términos de elegancia, esta solución es más limpia.