Calling addChild with an empty string as the value (or even with whitespace) seems to cause a redundant SimpleXml node to be added inside the node instead of adding just the node with no value. Does anyone know of a workaround for this?
Maybe I'm not understanding the question right but, it seems to me that when you use the addChild method, you're required to have a string as an argument for the name of the node regardless of what content is in the node. The value (second argument) is optional and can be left blank to add and empty node.
Let me know if that helps.
Sorry if I wasn't clear enough... here's a quick demo of what happens if you call addChild without an empty string:
[description] => !4jh5jh1uio4jh5ij14j34io5j!
And here's with an empty string:
[description] => SimpleXMLElement Object ( [0] => )
The workaround I'm using at the moment is pretty horrible - I'm doing a str_replace on the final JSON to replace !4jh5jh1uio4jh5ij14j34io5j! with an empty string. Yuck. Perhaps the only answer at this point is 'submit a bug report to simplexml'... :(
Horrible kludge is horrible. Would appreciate if anyone figures out a solution to this. :)
I think I figured out what is going on. Given code like this:
$xml = new SimpleXMLElement('<xml></xml>');
$xml->addChild('node','value');
print_r($xml);
$xml = new SimpleXMLElement('<xml></xml>');
$xml->addChild('node','');
print_r($xml);
$xml = new SimpleXMLElement('<xml></xml>');
$xml->addChild('node');
print_r($xml);
The output is this:
SimpleXMLElement Object
(
[node] => value
)
SimpleXMLElement Object
(
[node] => SimpleXMLElement Object
(
[0] =>
)
)
SimpleXMLElement Object
(
[node] => SimpleXMLElement Object
(
)
)
So, to make it so that in case #2 the empty element isn't created (i.e. if you don't know if the second argument is going to be an empty string or not), you could just do something like this:
$mystery_string = '';
$xml = new SimpleXMLElement('<xml></xml>');
if (preg_match('#\S#', $mystery_string)) // Checks for non-whitespace character
$xml->addChild('node', $mystery_string);
else
$xml->addChild('node');
print_r($xml);
echo "\nOr in JSON:\n";
echo json_encode($xml);
To output:
SimpleXMLElement Object
(
[node] => SimpleXMLElement Object
(
)
)
Or in JSON:
{"node":{}}
Is that what you want?
Personally, I never use SimpleXML, and not only because of this sort of weird behavior -- it is still under major development and in PHP5 is missing like 2/3 of the methods you need to do DOM manipulation (like deleteChild, replaceChild etc).
I use DOMDocument (which is standardized, fast and feature-complete, since it's an interface to libxml2).
Close, but still not right unfortunately - there's still a node where there should simply be a value.
I think using DOMDocument is looking to be the only solution here - thanks for trying :)
I've created an Xml library to which extends the simpleXml object to include all of the functionally that is present in the DOMDocument but is missing an interface from SimpleXml (as the two functions interact with the same underlying libxml2 object --by reference). It also has niceties such as AsArray() or AsJson() to output your object in one of those formats.
I've just updated the library to work as you expect when outputting JSON. You can do the following:
$xml = new bXml('<xml></xml>');
$xml->addChild('node', '');
$json_w_root = $xml->asJson(); // is { 'xml': {'node':'' } }
$json = $xml->children()->asJson(); // is { 'node' : '' } as expected.
The library is hosted on google code at http://code.google.com/p/blibrary/
With SimpleXML, what you get if you use print_r(), or var_dump(), serialize(), or similar, does not correspond to what is stored internally in the object. It is a 'magical' object which overloads the way PHP interates its contents.
You get the true representation of the element with AsXML() only.
When something like print_r() iterates over a SimpleXML element or you access its properties using the -> operator, you get a munged version of the object. This munged version allows you to do things like "echo $xml->surname" or $xml->names[1] as if it really had these as properties, but is separate to the true XML contained within: in the munged representation elements are not necessarily in order, and elements whose names are PHP reserved words (like "var") aren't presented as properties, but can be accessed with code like $xml["var"] - as if the object is an associative array. Where multiple sibling elements have the same name they are presented like arrays. I guess an empty string is also presented like an array for some reason. However, when output using AsXML() you get the real representation.