John Davidson

php - Question amout mtownsend/request-xml (XML to array) plugin

0 comments
Message:


Have a question about mtownsend/request-xml (XML to array) plugin.
So, plugin makes XML file to array.
I use it in my Laravel projects and there is several reason, because I need exact it, but here is one problem.


Have two simple XML files


first file oneitem.xml with one item <flat> into <post>


<?xml version="1.0" encoding="UTF-8"?>
<data>
<post>
<flat>
<roms>4</roms>
<baths>2</baths>
</flat>
</post>
</data>

second file severalitems.xml one with several items <flat> into <post>:


<?xml version="1.0" encoding="UTF-8"?>
<data>
<post>
<flat>
<roms>4</roms>
<baths>2</baths>
</flat>
<flat>
<roms>5</roms>
<baths>1</baths>
</flat>
<flat>
<roms>7</roms>
<baths>3</baths>
</flat>
</post>
</data>

Then, I use a simple code to make an array from this files, and show the result array for each:


$xmlone = XmlToArray::convert(file_get_contents('public/xml/test/oneitem.xml'));
$oneflat = $xmlone['post'];
print_r($oneflat);

$xmlseveral = XmlToArray::convert(file_get_contents('public/xml/test/severalitems.xml'));
$severalflats = $xmlseveral['post'];
print_r($severalflats);

If we try to make an array from first file (with one flat), and find all we have in posts we have this result:


Array ( [flat] => Array ( [roms] => 4 [baths] => 2 ) )


If we do the same in second file (with several `flat), we have this result


Array ( [flat] => Array ( [0] => Array ( [roms] => 4 [baths] => 2 ) [1] => Array ( [roms] => 5 [baths] => 1 ) [2] => Array ( [roms] => 7 [baths] => 3 ) )


So, if we have several items, plugin adds a additional arrays with keys, [0], [1], [2]....
I need to do it the same, even there is just one item flat into posts. So the results have same formats.


I know, that it makes plugin. If plugin see, that there is just one flat in post, he makes result array simple.


The code of main file of plugin is here, but I cant understand, which lines do it...


Thanks for your help


public static function convert($xml, $outputRoot = false)
{
$array = self::xmlStringToArray($xml);
if (!$outputRoot && array_key_exists('@root', $array)) {
unset($array['@root']);
}
return $array;
}

protected static function xmlStringToArray($xmlstr)
{
$doc = new DOMDocument();
$doc->loadXML($xmlstr);
$root = $doc->documentElement;
$output = self::domNodeToArray($root);
$output['@root'] = $root->tagName;
return $output;
}

protected static function domNodeToArray($node)
{
$output = [];
switch ($node->nodeType) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
$child = $node->childNodes->item($i);
$v = self::domNodeToArray($child);
if (isset($child->tagName)) {
$t = $child->tagName;
if (!isset($output[$t])) {
$output[$t] = [];
}
$output[$t][] = $v;
} elseif ($v || $v === '0') {
$output = (string) $v;
}
}
if ($node->attributes->length && !is_array($output)) { // Has attributes but isn't an array
$output = ['@content' => $output]; // Change output into an array.

}
if (is_array($output)) {
if ($node->attributes->length) {
$a = [];
foreach ($node->attributes as $attrName => $attrNode) {
$a[$attrName] = (string) $attrNode->value;


}
$output['@attributes'] = $a;

}
foreach ($output as $t => $v) {

if (is_array($v) && count($v) == 1 && $t != '@attributes') {
$output[$t] = $v[0];
}
}
}
break;
}
return $output;
}
}

** Thanks for your help!**



My Answer:
It looks like the issue you are facing is with the way the plugin handles the conversion of XML to an array when there is only one item present. The plugin is designed to create a simple array structure when there is only one item, but you want it to always create a nested array structure even if there is only one item.

To achieve this, you can modify the `domNodeToArray` method in the plugin code. Specifically, you can remove the condition that checks if the count of the child nodes is 1 and the tag name is not an attribute. By removing this condition, the plugin will always create a nested array structure even if there is only one item present.

Here is the modified code snippet for the `domNodeToArray` method:

php
protected static function domNodeToArray($node)
{
$output = [];
switch ($node->nodeType) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
$child = $node->childNodes->item($i);
$v = self::domNodeToArray($child);
$t = $child->tagName;
if (!isset($output[$t])) {
$output[$t] = [];
}
$output[$t][] = $v;
}
if ($node->attributes->length && !is_array($output)) { // Has attributes but isn't an array
$output = ['@content' => $output]; // Change output into an array.
}
if (is_array($output)) {
if ($node->attributes->length) {
$a = [];
foreach ($node->attributes as $attrName => $attrNode) {
$a[$attrName] = (string) $attrNode->value;
}
$output['@attributes'] = $a;
}
}
break;
}
return $output;
}


By making this modification, the plugin will always create a nested array structure for the XML data, even if there is only one item present. This should give you the desired result for both cases.

Rate this post

5 of 5 based on 1172 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us