How to distinguish SimpleXML objects from element and attribute?

I need to print arbitrary SimpleXML objects in a specific way with special handling of attribute nodes.

The problem is that the SimpleXML elements and attributes seem to use the exact same class, the node attribute even claims to support the attributes() method, and SimpleXML hides its internal functions, so there seems to be no way to tell the node type (except XML generation and its repair).

Both give the same result:

 $element = new SimpleXMLElement('<foo>test</foo>'); echo $element; print_r($element); $element = new SimpleXMLElement('<foo attr="test" />'); echo $element['attr']; print_r($element['attr']); 

Is there a hidden property / method to identify the type of node in SimpleXML? DOM equivalent $node->nodeType or $node instanceof DOMAttr ? (I cannot use the DOM instead, SimpleXML support is a basic requirement).

+3
reflection php simplexml
Apr 07 '09 at 10:12
source share
6 answers

SimpleXMLElement no built-in properties that allow you to talk about this separately.

As others suggested dom_import_simplexml , it may be advisable, however, that a function can change nodes on the fly sometimes, for example, if you go to the list of child nodes or named child nodes, it will take them and turn them into the first element.

If this is an empty list, for example, no attributes returned from attributes() or nonexistent named child nodes, it will warn you that you were given an invalid node type:

Warning: dom_import_simplexml (): invalid Nodetype type for import

So, if you need this precision with snappy boolean true / false , here is how it works with Simplexml:

 $isElement = $element->xpath('.') == array($element); $isAttribute = $element[0] == $element and $element->xpath('.') != array($element); 

It works similar to attribute lists and element lists, I just wrote about it in the morning , you need to have some knowledge about what to evaluate for what, so I created a cheat sheet for it:

 +------------------+---------------------------------------------+ | TYPE | TEST | +------------------+---------------------------------------------+ | Element | $element->xpath('.') == array($element) | +------------------+---------------------------------------------+ | Attribute | $element[0] == $element | | | and $element->xpath('.') != array($element) | +------------------+---------------------------------------------+ | Attributes | $element->attributes() === NULL | +------------------+---------------------------------------------+ | Elements | $element[0] != $element | | | and $element->attributes() !== NULL | +------------------+---------------------------------------------+ | Single | $element[0] == $element | +------------------+---------------------------------------------+ | Empty List | $element[0] == NULL | +------------------+---------------------------------------------+ | Document Element | $element->xpath('/*') == array($element) | +------------------+---------------------------------------------+ 
+3
Feb 12 '13 at 9:29
source share

Yes, there is a way. Well, there’s nothing elegant that you can get through the API, but somewhere in the gut SimpleXML keeps track of what it is and it makes a difference, for example, when you call functions like getName () or asXML ().

 $element = new SimpleXMLElement('<foo>test</foo>'); print_r($element->getName()); print_r($element->asXML()); echo "------------------\n"; $element = new SimpleXMLElement('<foo attr="test" />'); $at = $element['attr']; print_r($at->getName()); print_r($at->asXML()); foo <?xml version="1.0"?> <foo>test</foo> ------------------ attr attr="test" 

Your code will not win the beauty contest, but at least you can do it.

+2
May 15, '09 at 20:40
source share

Using what palako pointed out, this function might work:

 function is_attribute($node) { return !($node->asXML()[0] == "<") } 
+2
May 18 '09 at 3:04
source share

You need SimpleXMLElement :: attributes :

 function xml_out($el) { $name = $el->getName(); echo '<'. $name; if (count($el->attributes())) { foreach ($el->attributes() as $a=>$v) { echo ' '. ((string)$a) . '="' . htmlspecialchars((string)$v) . '"'; } } echo '>'. (string)$el; if (count($el->children())) { foreach($el->children() as $c) { xml_out($c); } } echo '</'. $name . '>'; } 

A little tweak may be required.

+1
Apr 07 '09 at 10:29
source share

Is there a hidden property / method to identify the type of node in SimpleXML? Equivalent to DOM $ node → nodeType or $ node instanceof DOMAttr? (I cannot use the DOM instead, SimpleXML support is a basic requirement)

The answer is no ... and yes. SimpleXML does not have this property, but the good news here is: SimpleXML and DOM are two faces of the same coin. (coin - libxml;)) You do not need to choose one or the other, you can use both! You can turn SimpleXMLElement into a DOMNode and vice versa. In your case, you can do something like:

 $element = new SimpleXMLElement('<foo attr="test" />'); $is_attr = (dom_import_simplexml($element['attr'])->nodeType === XML_ATTRIBUTE_NODE); 

If you often do something or don’t want to handle DOM / SimpleXML juggling, you can take a look at SimpleDOM .

 $element = new SimpleDOM('<foo attr="test" />'); $is_attr = ($element['attr']->nodeType() === XML_ATTRIBUTE_NODE); 
+1
Nov 15 '09 at 4:49
source share

Unfortunately, there is no hidden property or method that allows you to identify the type of node in SimpleXML. SimpleXML uses only one class, and the elements do not have anything that would indicate their parents. If you try the reflection below, you will see that there is nothing to distinguish an element or attribute.

 $element = new SimpleXMLElement('<foo>test</foo>'); echo ReflectionObject::export($element); $element = new SimpleXMLElement('<foo attr="test">test</foo>'); echo ReflectionObject::export($element['attr']); 

However, if an element has attributes, you may find this. Thus, you would have to assume that all elements that have passed through have attributes. With this assumption, you could tell them apart.

 $element = new SimpleXMLElement('<foo attr="test">test</foo>'); echo ReflectionObject::export($element); echo ReflectionObject::export($element['attr']); 

This is the best I can think of. Remember that an element with no attributes should return false with this.

 function isNotAttribute($simpleXML) { return (count($simpleXML->attributes()) > 0); } $element = new SimpleXMLElement('<foo attr="test">test</foo>'); var_dump(isNotAttribute($element)); var_dump(isNotAttribute($element['attr'])); // returns bool(true) bool(false) 
0
May 15, '09 at 15:54
source share



All Articles