I am not much familiar with XML. can you guys please help me with convering this xml to json using php?. this is an API response.
<?xml version="1.0" encoding="utf-8"?>
<ecomexpress-objects version="1.0">
<object pk="1" model="awb">
<field type="BigIntegerField" name="awb_number">115979601</field>
<field type="CharField" name="orderid">001</field>
<field type="FloatField" name="actual_weight">0.8</field>
<field type="CharField" name="origin">DELHI-DLW</field>
<field type="CharField" name="destination">DELHI-DLW</field>
<field type="CharField" name="current_location_name">DELHI-DLW</field>
<field type="CharField" name="current_location_code">DLW</field>
<field type="CharField" name="customer">Freshbells - 471459</field>
<field type="CharField" name="consignee">Forward</field>
<field type="CharField" name="pickupdate"></field>
<field type="CharField" name="status">Shipment Uploaded</field>
<field type="CharField" name="tracking_status">Shipment Not Handed over</field>
<field type="CharField" name="reason_code"></field>
<field type="CharField" name="reason_code_description"></field>
<field type="CharField" name="reason_code_number">001</field>
<field type="CharField" name="receiver"></field>
<field type="CharField" name="lat">0.0000000</field>
<field type="CharField" name="long">0.0000000</field>
<field type="CharField" name="rev_pickup_signature" ></field>
<field type="CharField" name="rev_pickup_packed_image" ></field>
<field type="CharField" name="rev_pickup_open_image" ></field>
</ecomexpress-objects>
I have tried with so many solution found here. but that doesn't work.
CodePudding user response:
This XML seems to serialize data model objects. It is fairly easy to read them into stdClass
objects.
// bootstrap DOM Xpath
$document = new DOMDocument();
$document->loadXML(getXMLString());
$xpath = new DOMXpath($document);
$objects = [];
// iterate object elements
foreach ($xpath->evaluate('/ecomexpress-objects/object') as $objectNode) {
$object = new stdClass();
// iterate field elements
foreach ($xpath->evaluate('field', $objectNode) as $fieldNode) {
// read attributes
$name = $fieldNode->getAttribute('name');
$type = $fieldNode->getAttribute('type');
// read field content and cast according to type
switch ($type) {
case 'BigIntegerField':
$object->{$name} = (int)$fieldNode->textContent;
break;
case 'FloatField':
$object->{$name} = (float)$fieldNode->textContent;
break;
default:
$object->{$name} = $fieldNode->textContent;
}
}
$objects[] = $object;
}
echo json_encode($objects, JSON_PRETTY_PRINT);
function getXMLString(): string {
return <<<'XML'
<?xml version="1.0" encoding="utf-8"?>
<ecomexpress-objects version="1.0">
<object pk="1" model="awb">
<field type="BigIntegerField" name="awb_number">115979601</field>
<field type="CharField" name="orderid">001</field>
<field type="FloatField" name="actual_weight">0.8</field>
<field type="CharField" name="origin">DELHI-DLW</field>
<field type="CharField" name="destination">DELHI-DLW</field>
<field type="CharField" name="current_location_name">DELHI-DLW</field>
<field type="CharField" name="current_location_code">DLW</field>
<field type="CharField" name="customer">Freshbells - 471459</field>
<field type="CharField" name="consignee">Forward</field>
<field type="CharField" name="pickupdate"></field>
<field type="CharField" name="status">Shipment Uploaded</field>
<field type="CharField" name="tracking_status">Shipment Not Handed over</field>
<field type="CharField" name="reason_code"></field>
<field type="CharField" name="reason_code_description"></field>
<field type="CharField" name="reason_code_number">001</field>
<field type="CharField" name="receiver"></field>
<field type="CharField" name="lat">0.0000000</field>
<field type="CharField" name="long">0.0000000</field>
<field type="CharField" name="rev_pickup_signature" ></field>
<field type="CharField" name="rev_pickup_packed_image" ></field>
<field type="CharField" name="rev_pickup_open_image" ></field>
</object>
</ecomexpress-objects>
XML;
}
Output:
[
{
"awb_number": 115979601,
"orderid": "001",
"actual_weight": 0.8,
"origin": "DELHI-DLW",
"destination": "DELHI-DLW",
"current_location_name": "DELHI-DLW",
"current_location_code": "DLW",
"customer": "Freshbells - 471459",
"consignee": "Forward",
"pickupdate": "",
"status": "Shipment Uploaded",
"tracking_status": "Shipment Not Handed over",
"reason_code": "",
"reason_code_description": "",
"reason_code_number": "001",
"receiver": "",
"lat": "0.0000000",
"long": "0.0000000",
"rev_pickup_signature": "",
"rev_pickup_packed_image": "",
"rev_pickup_open_image": ""
}
]
This approach could be extended with actual model classes in your code. Here is a very basic approach for this (without error handling):
// define a class for the model
class AWB implements JsonSerializable {
public readonly int $awb_number;
public readonly string $orderid;
public readonly float $actual_weight;
public function __construct(stdClass $values) {
foreach ((array)$values as $name => $value) {
if (property_exists($this, $name)) {
$this->{$name} = $value;
}
}
}
public function jsonSerialize(): mixed {
return get_object_vars($this);
}
}
// mapping array
$models = [
'awb' => AWB::class
];
$document = new DOMDocument();
$document->loadXML(getXMLString());
$xpath = new DOMXpath($document);
$objects = [];
foreach ($xpath->evaluate('/ecomexpress-objects/object') as $objectNode) {
$object = new stdClass();
foreach ($xpath->evaluate('field', $objectNode) as $fieldNode) {
// read field values - just like the previous example
}
// map model name to class
$class = $models[$objectNode->getAttribute('model')];
$objects[] = new $class($object);
}
echo json_encode($objects, JSON_PRETTY_PRINT);
Output:
[
{
"awb_number": 115979601,
"orderid": "001",
"actual_weight": 0.8
}
]
Also PHP attributes could be used to map field names to properties.