Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

json_encode() removes attributes (PHP)

I am using json_encode(simplexml_load_string($xml)) in PHP 7.0.10 to convert some XML-Code into JSON. The following XML

<?xml version="1.0" encoding="UTF-8"?>
<comments count="6">
<comment id="1" active="1" object="1" user="1" created="1473776866" updated="1473776866">Something</comment>
<comment id="2" active="1" object="1" user="2" created="1473776866" updated="1473776866">Hello</comment>
<comment id="3" active="1" object="1" user="3" created="1473776866" updated="1473776866">Just a comment</comment>
<comment id="6" active="0"/>
</comments>

creates the following result:

{"comments":{"@attributes":{"count":"6"},"comment":    
["Something","Hello","Just a comment", {"@attributes":{"id":"6","active":"0"}}]}}

Can someone explain me what's happening with all the attributes of the <comment>s?

Thanks, I appreciate any help!

EDIT: I figured out that all the attributes of an XML element are dropped whenever the given node has just a text value: <something attribute="will be dropped">just text</something>. So for the moment I am using an ugly workaround: I've modified the code in a way that it replaces all the strings occurrences with <text>string</text> before giving the XML to simplexml_load_string(). This solution works fine for the moment, but I'm still interested in a cleaner one …

like image 375
MW. Avatar asked Jan 21 '26 18:01

MW.


1 Answers

SimpleXML is not built for this kind of blind conversion. It doesn't create a neat array that you can convert into JSON, and actually creating a JSON format that neatly encapsulates all the possible structures of XML is tricky (and IMHO pretty pointless).

The method invoked when you run json_encode like this is mostly intended for debugging (note that @attributes is not something that you ever use when interacting with the object itself).

The specific problem here is that it's trying to be helpful by choosing how best to represent the content of each element, such as a) just a string, b) an array of child elements, c) an object with an '@attributes' property contain attribute key-value pairse, etc. It doesn't have a format that contains both string content and attributes, so you don't get both in the output.

The solution, as JustOnUnderMillions rightly says, is to parse out the data you actually want into a structure of your choosing, which you can then json_encode. Something like this:

$comments = [];
$sx = simplexml_parse_string($xml);
foreach ( $sx->comment as $sx_comment ) {
    $comments[] = [
         // Extract text attributes as appropriate types
         'id' => (int)$sx_comment['id'],
         'user_id' => (int)$sx_comment['user'],
         // Make this one a boolean
         'active' => ( (int)$sx_comment['active'] == 1 ),
         // Maybe you want to format these as ISO 8601...
         'created_ts' => (int)$sx_comment['created'],
         'updated_ts' => (int)$sx_comment['updated'],
         // Extract text content as a string
         'text' => (string)$sx_comment
    ];
}
echo json_encode($comments);
like image 69
IMSoP Avatar answered Jan 23 '26 08:01

IMSoP



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!