xml to json with attributes for php or python -
i'm trying convert xml json, easy enough php
$file = file_get_contents('data.xml' ); $a = json_decode(json_encode((array) simplexml_load_string($file)),1); print_r($a);
taking following xml
<?xml version="1.0" encoding="utf-8"?> <foo> <bar> <one lang="fr" type="bar">test</one> <one lang="fr" type="foo">test</one> <one lang="fr" type="baz">test</one> </bar> <thunk> <thud> <bar lang="fr" name="bob">test</bar> <bar lang="bz" name="frank">test</bar> <bar lang="ar" name="alive">test</bar> <bar lang="fr" name="bob">test</bar> </thud> </thunk> </foo>
and paring through simplexml produces
array ( [bar] => array ( [one] => array ( [0] => test [1] => test [2] => test ) ) [thunk] => array ( [thud] => array ( [bar] => array ( [0] => test [1] => test [2] => test [3] => test ) ) ) )
where ideally output this
{ "foo": { "bar": { "one": [ { "_lang": "fr", "_type": "bar", "__text": "test" }, { "_lang": "fr", "_type": "foo", "__text": "test" }, { "_lang": "fr", "_type": "baz", "__text": "test" } ] }, "thunk": { "thud": { "bar": [ { "_lang": "fr", "_name": "bob", "__text": "test" }, { "_lang": "bz", "_name": "frank", "__text": "test" }, { "_lang": "ar", "_name": "alive", "__text": "test" }, { "_lang": "fr", "_name": "bob", "__text": "test" } ] } } } }
trouble output doesn't contain attributes child elements, of these elements contain 2 or more attributes, there way transform xml php or python , include attributes found in children?
thanks
in answer i'll cover php, simplexmlelement part of code.
the basic way json encode xml simplexmlelement similar have in question. instantiate xml object , json_encode (demo):
$xml = new simplexmlelement($buffer); echo json_encode($xml, json_pretty_print);
this produces output close not you're looking already. here simplexml change standard way how json_encode
encode xml object.
this can done new subtype of simplexmlelement implementing jsonserializable interface. here such class has default way how php json-serialize object:
class jsonserializer extends simplexmlelement implements jsonserializable { /** * simplexmlelement json serialization * * @return null|string * * @link http://php.net/jsonserializable.jsonserialize * @see jsonserializable::jsonserialize */ function jsonserialize() { return (array) $this; } }
using produce exact same output (demo):
$xml = new jsonserializer($buffer); echo json_encode($xml, json_pretty_print);
so comes interesting part change serialization these bits output.
first of need differ between whether it's element carrying other elements (has children) or leaf-element of want attributes , text value:
if (count($this)) { // serialize children if there children ... } else { // serialize attributes , text leaf-elements foreach ($this->attributes() $name => $value) { $array["_$name"] = (string) $value; } $array["__text"] = (string) $this; }
that's done if/else. if-block children , else-block leaf-elements. leaf-elements easier, i've kept them in example above. can see in else-block iterates on attributes , adds name prefixed "_
" , "__text
" entry casting string.
the handling of children bit more convoluted need differ between single child element it's name or multiple children same name require additional array inside:
// serialize children if there children foreach ($this $tag => $child) { // child single-named element -or- child multiple elements same name - needs array if (count($child) > 1) { $child = [$child->children()->getname() => iterator_to_array($child, false)]; } $array[$tag] = $child; }
now there special case serialization needs deal with. encode root element name. routine needs check condition (being called document-element) (compare simplexml type cheatsheet) , serialize name under occasion:
if ($this->xpath('/*') == array($this)) { // root element needs named $array = [$this->getname() => $array]; }
finally left done return array:
return $array;
compiled jsonserializer done in simplexml tailored needs. here class , it's invocation @ once:
class jsonserializer extends simplexmlelement implements jsonserializable { /** * simplexmlelement json serialization * * @return null|string * * @link http://php.net/jsonserializable.jsonserialize * @see jsonserializable::jsonserialize */ function jsonserialize() { if (count($this)) { // serialize children if there children foreach ($this $tag => $child) { // child single-named element -or- child multiple elements same name - needs array if (count($child) > 1) { $child = [$child->children()->getname() => iterator_to_array($child, false)]; } $array[$tag] = $child; } } else { // serialize attributes , text leaf-elements foreach ($this->attributes() $name => $value) { $array["_$name"] = (string) $value; } $array["__text"] = (string) $this; } if ($this->xpath('/*') == array($this)) { // root element needs named $array = [$this->getname() => $array]; } return $array; } } $xml = new jsonserializer($buffer); echo json_encode($xml, json_pretty_print);
output (demo):
{ "foo": { "bar": { "one": [ { "_lang": "fr", "_type": "bar", "__text": "test" }, { "_lang": "fr", "_type": "foo", "__text": "test" }, { "_lang": "fr", "_type": "baz", "__text": "test" } ] }, "thunk": { "thud": { "bar": [ { "_lang": "fr", "_name": "bob", "__text": "test" }, { "_lang": "bz", "_name": "frank", "__text": "test" }, { "_lang": "ar", "_name": "alive", "__text": "test" }, { "_lang": "fr", "_name": "bob", "__text": "test" } ] } } } }
i hope helpful. it's perhaps little @ once, find jsonserializable interface documented in php manual well, can find more example there. example here on stackoverflow kind of xml json conversion can found here: xml json conversion in php simplexml.
Comments
Post a Comment