9

I am trying to get a child of a PHP DOMDocument. Say I have a DOM document like this:

<div>
   <h1 ></h1>
   <div id=2></div>
   <div class="test"></div>
...
</div>

I have a index number 3. Then I need to get the element <div class="test"></div>. In the DOMDocument API, there isn't a method like children(3). Is there? How can I get a child with an index?

hakre
  • 193,403
  • 52
  • 435
  • 836
bingjie2680
  • 7,643
  • 8
  • 45
  • 72
  • you need to use getElementByTag('div') and then use the getAttribute ('class') and put that in if condition to match class='test'. it does require bit of RnD – Khurram Ijaz May 18 '11 at 07:14
  • *(related)* [Best Methods to parse HTML](http://stackoverflow.com/questions/3577641/best-methods-to-parse-html/3577662#3577662) and [Noob Question about DOMDocument in PHP](http://stackoverflow.com/questions/4979836/noob-question-about-domdocument-in-php/4983721#4983721) – Gordon May 18 '11 at 07:17
  • possible duplicate of [How get first level of dom elements by Domdocument PHP?](http://stackoverflow.com/questions/5882433/how-get-first-level-of-dom-elements-by-domdocument-php) – Gordon May 18 '11 at 07:22
  • @Gordon.I am actually using HTML dom parser. but it seems not robust when document is big. I will look at those post you refer to..thank you very much for you help. – bingjie2680 May 18 '11 at 07:57

4 Answers4

19

You can use childNodes. This is a property of a DOM element that contains a NodeList containing all the element's children. Ideally you'd be able to do $el->childNodes->item(2) (note that it's 0-based, not 1-based, so 2 is the third item). However, this includes text nodes. So it's hard to predict what number your node will be. This probably isn't the best solution.

You could go with alexn's solution (getElementsByTagName('*')->item(2)), but again this has its drawbacks. If your nodes have child nodes, they will also be included in the selection. This could throw your calculation off.

My preferred solution would be to use XPath: it's probably the most stable solution, and not particularly hard.

You'll need to have created an XPath object with $xpath = new DOMXPath($document) somewhere, where $document is your DOMDocument instance. I'm going to assume that $el is the parent div node, the "context" that we're searching in.

$node = $x->query('*', $el)->item(2);

Note that, again, we're using a 0-based index to find which element in the selection it is. Here, we're looking at child nodes of the top level div only, and * selects only element nodes, so the calculations with text nodes are unnecessary.

Community
  • 1
  • 1
lonesomeday
  • 233,373
  • 50
  • 316
  • 318
  • hi, thanks for you answer. I tried $el->childNode->item(2). it striped off all the html tags. I also tried $x->query('/div/*', $el)->item(2);but notice that the child node is not fixed with div... I need to dynamiclly to get a child level by level down with a serial index like 1 3 4 0. – bingjie2680 May 18 '11 at 07:52
  • @Yijie Yes, it should have been just `query('*', $el)`. See updated answer. – lonesomeday May 18 '11 at 07:53
5

If you use DOMDocument you can use getElementsByTagName('*') which returns a DomNodeList with all elements in your document. You can then invoke the item function which takes an index as a parameter:

$nodes = $dom->getElementsByTagName('*');
$targetNode = $nodes->item(3);
alexn
  • 57,867
  • 14
  • 111
  • 145
  • Hi, thank you for the answer, your solution gets all the element from all descendent nodes. and all html tags are striped off. my intention is to get a child level by level down with a serials of index like 1 3 4 0. Hope this is clear. – bingjie2680 May 18 '11 at 07:46
1

try this

 foreach($dom->getElementsByTagName('div') as $div) { 
        $class = $div->getAttribute('class');
    } 

now you can match the class or id attribute of that particular div and do what ever. this is not the solution but helps you find the contents and attributes with all divs' . hope it helps.

Khurram Ijaz
  • 1,844
  • 5
  • 24
  • 43
1

Try this:

$dom->childNodes->item(3)
Steven Vachon
  • 3,814
  • 1
  • 30
  • 30