Colin
Colin

Reputation: 113

PHP XML DomDocument - Pulling attributes and child attributes

<tle-type name="Channel" tag="47" mt="true">
  <tle-field name="ChannelId" tag="1" type="String" minOccurs="1" maxOccurs="1">
    Description 1.
  </tle-field>           
  <tle-field name="resultCode" tag="2" enum="true" type="ChannelResult" minOccurs="1" maxOccurs="1">     
    Description 2.
  </tle-field>
  <tle-field name="jid" tag="3" type="String" minOccurs="0"  maxOccurs="1">
    Description 3.
  </tle-field>
  <tle-field name="thing" tag="4" type="String" minOccurs="0"  maxOccurs="1">
    Description 5.
  </tle-field>
</tle-type>

Above is a section of XML that I am dealing with. The 'tag' attribute under 'tle-type' is the unique identifier and then in it's children 'tle-field' will be another 'tag' attribute. I'm essentially looking for a way to identify the first 'tag' 'tle-type', then create a $attribute = "value" out of 'tle-field', with the description in $desc.

While I can pull out the 'tle-type' attribute with tag="x", I cannot seem to pull the child attributes out where the tag = 'y'. I can just print all the attributes.

foreach ($xml->getElementsByTagName('tle-type') as $tag) {
        if($tag->getAttribute('tag') === '47') {
                foreach ($tag->childNodes as $child ) { 
                        foreach ($child->attributes as $t ) {                                                                                        
                                echo "<BR>".$t->nodeName." = ".$t->nodeValue;

                        }   
                }   
        }   
}

With the above, I end up with Warning: Invalid argument supplied for foreach() in file.php on line 4:

foreach ($child->attributes as $t)

Yet the attribute names and values show up, minus the description, of course. I hope I've explained this alright...

Any assistance would be appreciated!

Upvotes: 1

Views: 1272

Answers (1)

ThW
ThW

Reputation: 19482

The childnodes, are not only elements, but text nodes, too. So you get the whitespace text nodes. They have no attributes and an error is thrown.

I modified your source to show the classes: https://eval.in/112204

$dom = new DOMDocument();
$dom->loadXml($xml);

foreach ($dom->getElementsByTagName('tle-type') as $tag) {
  if($tag->getAttribute('tag') === '47') {
    foreach ($tag->childNodes as $child) { 
      var_dump(get_class($child));
    }   
  }   
}

So you would have to check if the child is an instance of DOMElement. But here is an easier way. Create an Xpath object and use expressions:

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);

$result = [];
foreach ($xpath->evaluate('//tle-type[@tag = "47"]/tle-field') as $field) {
  $result[$field->getAttribute('name')] = $field->nodeValue;   
}

var_dump($result);

Output: https://eval.in/112222

array(4) {
  ["ChannelId"]=>
  string(22) "
    Description 1.
  "
  ["resultCode"]=>
  string(27) "     
    Description 2.
  "
  ["jid"]=>
  string(22) "
    Description 3.
  "
  ["thing"]=>
  string(22) "
    Description 5.
  "
}

Upvotes: 3

Related Questions