Search code examples
phpxmldomdocumentgetelementsbytagnamechild-nodes

PHP extracting getElementsByTagName from childNodes


This should all be very straight forward but for some reason it is escaping me.

Using the following XML structure imported from a file:

<locations>
  <devices>
    <entry>
      <serial>12345</serial>
      <hostname>FooBarA</hostname>
      <vsys>
        <entry>
          <displayname>CorpA</displayName>
          <tag>InternalA</tag>
        </entry>
      </vsys>
      </c>
    </entry>
    <entry>
      <serial>123456</serial>
      <hostname>FooBarB</hostname>
      <vsys>
        <entry>
          <displayname>CorpB</displayName>
          <tag>InternalB</tag>
        </entry>
      </vsys>
      </c>
    </entry>
  </devices>
</locations>

And extracting Parent and should be straight forward:

$devices = $dom->getElementsByTagName('devices');
$data = array();
foreach($devices as $node){  // each $node = <devices> == only ONE object
  foreach($node->childNodes as $child) {  // each $child is the ENTIRE <entry>, including <entry> tag
    // I would expect this to return the <serial> out of parent <entry>, but its not
    $serial = $child->getElementsByTagName('serial') ;
    echo "\n" . $count++ . ", a" .$serial->nodeName ;    
    if ($child->nodeName == "entry") {
      // as a secondary method, I then try to extra <serial> looping through the childNodes of the parent <entry> and again, this doesn't work.
      foreach ($child->childNodes as $kid) {
        $serial = $kid->getElementsByTagName('serial') ;
        echo ", b" .$serial->nodeName ;
      }
    }
  }
}

The above prints out:

1a, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b
2a, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b
3a, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b
4a, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b

My actual xml file has a lot more siblings at the serial level thus its printing out all the extra bs...thus that is telling me the basic foreach's are working and each is properly looping through each level - but I am not able to extract the nodeName or getElementsByTagName within each level.

I figured one of the two methods, at different nested levels, would have extracted <serial> but neither is working. What am I missing here?

My expectation is it would print:

1a 12345, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b
2a 123456, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b
3a 1234567, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b
4a 12345678, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b

Or at a miniumum:

1a, b 12345, b 12345, b 12345 ...
2a, b 123456, b 123456, b 123456 ...
3a, b 1234567, b 1234567, b 1234567 ...
etc etc.

Solution

  • getElementsByTagName returns a DOMNodeList, so you need to iterate it to get names of individual nodes:

    $serials = $child->getElementsByTagName('serial') ;
    foreach($serials as $serial) {
      echo "\n" . $count++ . ", a" .$serial->nodeName ;    
    }
    

    As a side node, the xml in the question is not valid:

    • <displayname> ... </displayName>
    • <vsys> <entry> ... </entry> </c>