PHP DOM: Como obter elementos filho por nome de etiqueta de forma elegante?

Estou analisando alguns XML com a extensão PHP DOM para armazenar os dados de alguma outra forma. Sem surpresa, quando analiso um elemento, costumo precisar de todos os elementos infantis de algum nome. Existe o método DOMElement::getElementsByTagName($name) , mas retorna todos os descendentes com esse nome, e não apenas filhos imediatos. Há também a propriedade DOMNode::$childNodes mas (1) contém lista de nós, não lista de elementos, e mesmo se eu conseguisse transformar os itens da lista em elementos (2) eu ainda precisaria verificar todos eles para o nome. Não há realmente nenhuma solução elegante para obter apenas os filhos de algum nome específico ou estou faltando alguma coisa na documentação?

Algumas ilustrações:

 loadXML(<<<EndOfXML  1 2  3 4   EndOfXML ); $bs = $document ->getElementsByTagName('a') ->item(0) ->getElementsByTagName('b'); foreach($bs as $b){ echo $b->nodeValue . "\n"; } // Returns: // 1 // 2 // 3 // 4 // I'd like to obtain only: // 1 // 2 ?> 

Uma maneira elegante que eu posso imaginar seria usar um FilterIterator que seja adequado para o trabalho. Um exemplar que é capaz de trabalhar em tal dito DOMNodeList e (opcionalmente) aceitando um título para filtrar como um exemplar DOMElementFilter do Iterator Garden faz:

 $a = $doc->getElementsByTagName('a')->item(0); $bs = new DOMElementFilter($a->childNodes, 'b'); foreach($bs as $b){ echo $b->nodeValue . "\n"; } 

Isso dará os resultados que você está procurando:

 1 2 

Você pode encontrar o DOMElementFilter no ramo de desenvolvimento agora. Talvez valha a pena permitir * para qualquer tipo de getElementsByTagName("*") possível com getElementsByTagName("*") também. Mas isso é apenas algum comentário.

Hier é um exemplo de uso útil em linha: https://eval.in/57170

processo de iteração simples

  $parent = $p->parentNode; foreach ( $parent->childNodes as $pp ) { if ( $pp->nodeName == 'p' ) { if ( strlen( $pp->nodeValue ) ) { echo "{$pp->nodeValue}\n"; } } } 

Minha solução usada em uma produção:

Encontra uma agulha (nó) em um palheiro (DOM)

 function getAttachableNodeByAttributeName(\DOMElement $parent = null, string $elementTagName = null, string $attributeName = null, string $attributeValue = null) { $returnNode = null; $needleDOMNode = $parent->getElementsByTagName($elementTagName); $length = $needleDOMNode->length; //traverse through each existing given node object for ($i = $length; --$i >= 0;) { $needle = $needleDOMNode->item($i); //only one DOM node and no attributes specified? if (!$attributeName && !$attributeValue && 1 === $length) return $needle; //multiple nodes and attributes are specified elseif ($attributeName && $attributeValue && $needle->getAttribute($attributeName) === $attributeValue) return $needle; } return $returnNode; } 

Uso:

 $countryNode = getAttachableNodeByAttributeName($countriesNode, 'country', 'iso', 'NL'); 

Retorna o elemento DOM do nó dos países-mãe pelo atributo especificado iso usando o código ISO do país ‘NL’, basicamente como uma pesquisa real faria. Encontre um determinado país por seu nome em uma matriz / object.

Outro exemplo de uso:

 $productNode = getAttachableNodeByAttributeName($products, 'partner-products'); 

Retorna o elemento de nó DOM contendo apenas um nó único (raiz), sem procurar por nenhum atributo. Nota: para isso, você deve certificar-se de que os nós raiz são únicos pelo nome da etiqueta dos elementos, por exemplo, país- countries->country[ISO] – o nó dos countries aqui é exclusivo e pai para todos os nós secundários.