Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP DOM: How to get child elements by tag name in an elegant manner?

Tags:

dom

php

xml

I'm parsing some XML with PHP DOM extension in order to store the data in some other form. Quite unsurprisingly, when I parse an element I pretty often need to obtain all children elements of some name. There is the method DOMElement::getElementsByTagName($name), but it returns all descendants with that name, not just immediate children. There is also the property DOMNode::$childNodes but (1) it contains node list, not element list, and even if I managed to turn the list items into elements (2) I'd still need to check all of them for the name. Is there really no elegant solution to get only the children of some specific name or am I missing something in the documentation?

Some illustration:

<?php

DOMDocument();
$document->loadXML(<<<EndOfXML
<a>
  <b>1</b>
  <b>2</b>
  <c>
    <b>3</b>
    <b>4</b>
  </c>
</a>
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

?>
like image 293
Kalmar Avatar asked Oct 24 '13 00:10

Kalmar


People also ask

How do I know if my DOM element has children?

HTML DOM Element hasChildNodes() The hasChildNodes() method returns true if the specified node has any child nodes, otherwise false.

Which property is used to find the child elements of an HTML element?

The children property returns a collection of an element's child elements.


2 Answers

simple iteration process

$parent = $p->parentNode;

foreach ( $parent->childNodes as $pp ) {

    if ( $pp->nodeName == 'p' ) {

        if ( strlen( $pp->nodeValue ) ) {
            echo "{$pp->nodeValue}\n";
        }

    }

}
like image 96
M.Z. Avatar answered Oct 20 '22 14:10

M.Z.


An elegant manner I can imagine would be using a FilterIterator that is suitable for the job. Exemplary one that is able to work on such a said DOMNodeList and (optionally) accepting a tagname to filter for as an exemplary DOMElementFilter from the Iterator Garden does:

$a = $doc->getElementsByTagName('a')->item(0);

$bs = new DOMElementFilter($a->childNodes, 'b');

foreach($bs as $b){
    echo $b->nodeValue . "\n";
}

This will give the results you're looking for:

1
2

You can find DOMElementFilter in the Development branch now. It's perhaps worth to allow * for any tagname as it's possible with getElementsByTagName("*") as well. But that's just some commentary.

Hier is a working usage example online: https://eval.in/57170

like image 4
hakre Avatar answered Oct 20 '22 14:10

hakre