I have a function who convert an array to XML but it doesn't work in any case.
public function array_to_xml($data, &$xml_data) {
foreach($data as $key => $value) {
if (is_numeric($key)) {
$key = 'item'.$key;
}
if (is_array($value)) {
$subnode = $xml_data->addChild($key);
$this->array_to_xml($value, $subnode);
} else {
$xml_data->addChild("$key",htmlspecialchars("$value"));
}
}
}
But if I send this array it will returns <item0...n> :
$xml = new \SimpleXMLElement('<?xml version="1.0"?><offices></offices>');
$first = array("id" => 1, "name" => "firstOffice");
$second = array("id" => 2, "name" => "secondOffice");
$offices = array("office" => array($first, $second));
return array_to_xml($data, $xml);
OUTPUT
<offices>
<office>
<item0>
<id>1</id>
<name>firstOffice</name>
</item0>
<item1>
<id>2</id>
<name>secondOffice</name>
</item1>
</office>
</offices>
How can I edit my function to get this result :
<offices>
<office>
<id>1</id>
<name>firstOffice</name>
</office>
<office>
<id>2</id>
<name>secondOffice</name>
</office>
</offices>
Actually I'll return JSON or XML based on the accept header then I have to use the same array for the JSON and the XML.
Here is a part of my current code :
public function getOffices() {
$tools = new Tools();
$accept = $this->request->getHeader('accept');
$xml = new \SimpleXMLElement('<?xml version="1.0"?><offices></offices>');
$offices = Offices::find(); // Find all offices, I'm using Phalcon PHP ORM
return $tools->formatAdapter($accept, array("office" => $offices->toArray()), 200, $xml);
}
Tools functions class
public function array_to_xml($data, &$xml_data) {
foreach($data as $key => $value) {
if (is_numeric($key)) {
$key = 'item'.$key;
}
if (is_array($value)) {
$subnode = $xml_data->addChild($key);
$this->array_to_xml($value, $subnode);
} else {
$xml_data->addChild("$key",htmlspecialchars("$value"));
}
}
}
public function formatAdapter($type, $data, $code, &$xml_data) {
if ($type == 'application/json') {
return $this->JSONBuilder($data, $code);
} else {
$this->array_to_xml($data, $xml_data);
return $this->XMLBuilder($xml_data->asXML(), $code);
}
}
public function JSONBuilder($data, $code) {
$response = new Response();
$message = $this->getResponseDescription($code);
$response->setHeader('Content-Type', 'application/json');
$response->setStatusCode($code, $message);
$response->setJsonContent($data);
return $response;
}
function XMLBuilder($xml, $code) {
$response = new Response();
$message = $this->getResponseDescription($code);
$response->setHeader('Content-Type', 'application/xml');
$response->setStatusCode($code, $message);
$response->setContent($xml);
return $response;
}
Edit formatAdapter function
public function formatAdapter($type, $data, $code, &$xml_data, $loop = false) {
if ($type == 'application/json') {
return $this->JSONBuilder($data, $code);
} else {
if ($loop) {
foreach ($data as $key => $value) {
foreach ($value as $obj) {
$this->array_to_xml(array($key => $obj), $xml_data);
}
}
} else {
$this->array_to_xml($data, $xml_data);
}
return $this->XMLBuilder($xml_data->asXML(), $code);
}
}
It works if I add this loop inside my function and $loop parameter. But as you can see I have 2 foreach loops. It's possible to avoid the first foreach loop ? Because I'll loop once everytime. I tried with array_value() but there it doesn't work.
EDIT FIX
Finally I found a solution for my formatAdapter function, but it will works just for the first object. If someone has a better solution :
public function formatAdapter($type, $data, $code, &$xml_data, $loop = false) {
if ($type == 'application/json') {
return $this->JSONBuilder($data, $code);
} else {
if ($loop) {
$key = key($data);
foreach ($data[$key] as $obj) {
$this->array_to_xml(array($key => $obj), $xml_data);
}
} else {
$this->array_to_xml($data, $xml_data);
}
return $this->XMLBuilder($xml_data->asXML(), $code);
}
}
Thanks to @iainn
<office>for each offices