I need to fetch all the node keys in xml. I converted to array and then done with the following code,
<?php
$array='<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<country>
<id>18</id>
<id_zone xlink:href="https://www.example.com/api/zones/299">299</id_zone>
<id_currency>0</id_currency>
<call_prefix>469</call_prefix>
<iso_code>SE</iso_code>
<active>1</active>
<contains_states>0</contains_states>
<need_identification_number>0</need_identification_number>
<need_zip_code>1</need_zip_code>
<zip_code_format>NNN NN</zip_code_format>
<display_tax_label>1</display_tax_label>
<name><language id="1" xlink:href="https://www.example.com/api/languages/1">Suède</language><language id="2" xlink:href="https://www.example.com/api/languages/2">Sweden</language></name>
</country>
</prestashop>';
$array1=json_decode(json_encode((array)simplexml_load_string($array,'SimpleXMLElement',LIBXML_NOCDATA)),1);
//print_r($array1);die();
function getUniqueObjectKeyPaths(array $array, $parentKey = "") {
$keys = [];
foreach ($array as $parentKey => $v) {
if (!is_numeric($parentKey) && !is_array($v)) {
$keys[] = $parentKey;
}
if (is_array($v)) {
$nestedKeys = getUniqueObjectKeyPaths($v, $parentKey);
foreach($nestedKeys as $index => $key) {
if (!is_numeric($parentKey) && !is_numeric($key)) {
$nestedKeys[$index] = $parentKey . "->" . $key;
}
}
$keys = array_merge($keys, $nestedKeys);
}
}
return $keys;
}
$k=getUniqueObjectKeyPaths($array1);
print_r($k);
I got the result as follows,
Array (
[0] => country->id
[1] => country->id_zone
[2] => country->id_currency
[3] => country->call_prefix
[4] => country->iso_code
[5] => country->active
[6] => country->contains_states
[7] => country->need_identification_number
[8] => country->need_zip_code
[9] => country->zip_code_format
[10] => country->display_tax_label
)
The expected result is,
I also need the key country->name->language->0,country->name->language->1.
Any quick help would be greatly appreciated.
Thanks, Rekha
CodePudding user response:
You were on the right track with using a recursive function. You needed to add the $keys
as a function argument alongside the $parentKey
.
function getUniqueObjectKeyPaths(array $array, $parentKey = '', $keys = [])
{
foreach ($array as $key => $value) {
if (!empty($parentKey))
$key = $parentKey . '->' . $key;
if (is_array($value))
return getUniqueObjectKeyPaths($value, $key, $keys);
$keys[] = $key;
}
return $keys;
}
CodePudding user response:
I don't think there's a need for the json_decode(json_encode())
stuff and casting SimpleXMLElement
to an array adds an [@attributes]
index as well. You can traverse a SimpleXMLElement
object by itself:
Function:
function getUniqueObjectKeyPaths(SimpleXMLElement $el, array $trail = []) : array {
// intialize collected paths
$paths = [];
// keep track of identically named children
$sameNameIndices = [];
foreach($el as $child) {
// store child's name
$name = $child->getName();
// we can count how may identically named children with $name there are in element by using count($el->childName)
// and with the special syntax $el->{$name} we can use the name stored in the variabel $name
$sameNameCount = count($el->{$name});
// if we have multiple identically named children...
if($sameNameCount > 1) {
// initialize or increment identically named child index
$sameNameIndices[$name] = !isset($sameNameIndices[$name]) ? 0 : $sameNameIndices[$name] 1;
// add name with its index to trail
$trail[] = $name . '->' . $sameNameIndices[$name];
}
// else...
else {
// only add name
$trail[] = $name;
}
// since we only want leaves, recurse if this child has children of its own
if(count($child)) {
// push recursed paths to our local paths collection
array_push($paths, ...getUniqueObjectKeyPaths($child, $trail));
}
// else add our path to the paths collection
else {
$paths[] = implode('->', $trail);
}
// remove name from the trail again
array_pop($trail);
}
// return collected paths
return $paths;
}
Usage:
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<country>
<id>18</id>
<id_zone xlink:href="https://www.example.com/api/zones/299">299</id_zone>
<id_currency>0</id_currency>
<call_prefix>469</call_prefix>
<iso_code>SE</iso_code>
<active>1</active>
<contains_states>0</contains_states>
<need_identification_number>0</need_identification_number>
<need_zip_code>1</need_zip_code>
<zip_code_format>NNN NN</zip_code_format>
<display_tax_label>1</display_tax_label>
<name>
<language id="1" xlink:href="https://www.example.com/api/languages/1"><test>Suède</test></language>
<test id="2" xlink:href="https://www.example.com/api/languages/2">Sweden</test>
<language id="2" xlink:href="https://www.example.com/api/languages/2">Sweden</language>
</name>
</country>
</prestashop>';
$el = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
print_r(getUniqueObjectKeyPaths($el));
...prints:
Array
(
[0] => country->id
[1] => country->id_zone
[2] => country->id_currency
[3] => country->call_prefix
[4] => country->iso_code
[5] => country->active
[6] => country->contains_states
[7] => country->need_identification_number
[8] => country->need_zip_code
[9] => country->zip_code_format
[10] => country->display_tax_label
[11] => country->name->language->0
[12] => country->name->language->1
)