PHP convert XML with mixed array children to JSON keeping the child order
$xml = <<<'XML'
<root>
<a id="0"></a>
<b id="0"></b>
<b id="1"></b>
<a id="1"></a>
<a id="2"></a>
</root>
XML;
$xe = simplexml_load_string($xml);
$a = $xe->xpath('*');
$a = array_map(function ($e) {
$item = (array) $e;
$item['tag'] = $e->getName();
return $item;
}, $a);
echo json_encode($a, JSON_PRETTY_PRINT);
Output
[
{
"@attributes": {
"id": "0"
},
"tag": "a"
},
{
"@attributes": {
"id": "0"
},
"tag": "b"
},
{
"@attributes": {
"id": "1"
},
"tag": "b"
},
{
"@attributes": {
"id": "1"
},
"tag": "a"
},
{
"@attributes": {
"id": "2"
},
"tag": "a"
}
]
PHP convert XML to JSON
I figured it out. json_encode handles objects differently than strings. I cast the object to a string and it works now.
foreach($xml->children() as $state)
{
$states[]= array('state' => (string)$state->name);
}
echo json_encode($states);
PHP Converting from XML to JSON with a SimpleXML object. Array with items tag causing issues
A generic conversion has no possibility to know that a single element should be an array in JSON.
SimpleXMLElement
properties can be treated as an Iterable to traverse sibling with the same name. They can be treated as an list or a single value.
This allows you to build up your own array/object structure and serialize it to JSON.
$xml = <<<'XML'
<apns>
<item>
<apn>apn1</apn>
</item>
<item>
<apn>apn2</apn>
</item>
</apns>
XML;
$apns = new SimpleXMLElement($xml);
$json = [
'apns' => []
];
foreach ($apns->item as $item) {
$json['apns'][] = ['apn' => (string)$item->apn];
}
echo json_encode($json, JSON_PRETTY_PRINT);
This still allows you to read/convert parts in a general way. Take a more in deep look at the SimpleXMLElement class. Here are method to iterate over all children or to get the name of the current node.
When converting xml to json , several objects name change to @attributes
When you json_encode()
XML with attributes, this will create the @attributes
elements your getting. The only way round this is to remove them as you expand them. I've changed the routine, the first thing is that I've put the part that processes the attributes first, this ensures that the root node gets processed as well.
The main thing is that I've changed the way it works to use XPath to retrieve the attributes, this then encodes them as you have, but also allows you to remove the attribute from the original node (using unset($attribute[0]);
)...
function xml_expand_attributes($node)
{
foreach ($node->xpath("@*") as $attribute) {
$node->addChild($node->getName()."@".$attribute->getName(), (string)$attribute);
unset($attribute[0]);
}
if($node->count() > 0) {
foreach($node->children() as $child)
{
xml_expand_attributes($child); // 再帰呼出
}
}
}
Converting XML to JSON using PHP while preserving Arrays
I had to deal with the same situation. Here is a quick first solution to the problem - works fine for your example.
class JsonWithArrays
{
protected $root, $callback;
public function __construct( SimpleXMLElement $root )
{
$this->root = $root;
}
/**
* Set a callback to return if a node should be represented as an array
* under any circumstances.
*
* The callback receives two parameters to react to: the SimpleXMLNode in
* question, and the nesting level of that node.
*/
public function use_callback_forcing_array ( $callback )
{
$this->callback = $callback;
return $this;
}
public function to_json ()
{
$transformed = $this->transform_subnodes( $this->root, new stdClass(), 0 );
return json_encode( $transformed );
}
protected function transform_subnodes ( SimpleXMLElement $parent, stdClass $transformed_parent, $nesting_level )
{
$nesting_level++;
foreach( $parent->children() as $node )
{
$name = $node->getName();
$value = (string) $node;
if ( count( $node->children() ) > 0 )
{
$transformed_parent->$name = new stdClass();
$this->transform_subnodes( $node, $transformed_parent->$name, $nesting_level );
}
elseif ( count( $parent->$name ) > 1 or $this->force_array( $node, $nesting_level ) )
{
$transformed_parent->{$name}[] = $value;
}
else
{
$transformed_parent->$name = $value;
}
}
return $transformed_parent;
}
protected function force_array ( $node, $nesting_level )
{
if ( is_callable( $this->callback ) )
{
return call_user_func( $this->callback, $node, $nesting_level );
}
else
{
return false;
}
}
}
$xml = <<<END
<xml>
<TESTS>
<TEST>TEXT HERE</TEST>
</TESTS>
</xml>
END;
$xml2 = <<<END
<xml>
<TESTS>
<TEST>TEXT HERE</TEST>
<TEST>MORE TEXT HERE</TEST>
</TESTS>
</xml>
END;
// Callback using the node name. Could just as well be done using the nesting
// level.
function cb_testnode_as_array( SimpleXMLElement $node, $nesting_level )
{
return $node->getName() == 'TEST';
}
$transform = new JsonWithArrays( new SimpleXMLElement($xml, LIBXML_NOCDATA) );
echo $transform
->use_callback_forcing_array( 'cb_testnode_as_array' )
->to_json();
echo PHP_EOL;
$transform2 = new JsonWithArrays( new SimpleXMLElement($xml2, LIBXML_NOCDATA) );
echo $transform2
->use_callback_forcing_array( 'cb_testnode_as_array' )
->to_json();
PHP complex XML to JSON parsing
Generic conversion from XML to JSON fails for more complex XML. XML has attributes as an additional dimension, repeated nodes with the same name or mixed child nodes. JSON based formats like JsonML are possible, but that's not the JSON most people want or expect.
Try a different approach. Read values from the XML using Xpath (and DOM or SimpleXML methods). Build up the variables/data structures just as needed. You can then encode them as JSON.
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$items = [];
// iterate the Table nodes
foreach ($xpath->evaluate('//NewDataSet/Table') as $tableNode) {
$items[] = [
// read CMan_Code as string
'code' => trim($xpath->evaluate('string(CMan_Code)', $tableNode)),
// read CMan_Name as string
'name' => trim($xpath->evaluate('string(CMan_Name)', $tableNode))
];
}
var_dump($items);
// encode the array variable as JSON
var_dump(json_encode($items, JSON_PRETTY_PRINT));
Related Topics
Pdo Error: SQLstate[Hy000]: General Error: 2031
Overwrite Line in File with PHP
Call to Undefined Method Maatwebsite\Excel\Excel::Load()
PHP Try-Catch Blocks: Are They Able to Catch Invalid Arg Types
MySQL Error When Inserting Data Containing Apostrophes (Single Quotes)
Laravel Livewire Component Not Refreshing/Reloading Automatically After Refreshing It
Jquery: Running Ajax Locally Without a Webserver
Pdo Prepared Statement Fetch() Returning Double Results
PHP on Godaddy Linux Shared Trying to Send Through Gmail Smtp
Mod_Rewrite, PHP and the .Htaccess File
How to Install Composer on App Service
Disable Add to Cart Button for an Array of Products Ids in Woocommerce