Konstantinos
Konstantinos

Reputation: 29

parse xmlsimple to array

I have the following :

function Recurse1($xml, $array, $i){
    $a = array();
    foreach($xml - > children() as $key => $child) {
        $array[$key][$i] = $child - > attributes() - > role;
        $i++;
        $a = array_merge($array, Recurse1($child, $array, $i));
    }
    return $a;
}

var_dump(Recurse1($xml, array(), 0));
$xml = new SimpleXMLElement(
'<person>
    <child role="son1">
        <child role="daughter1"/>
    </child>
    <child role="daughter2">
        <child role="son2">
            <child role="son3"/>
        </child>
    </child>
</person>'
);

I get the following:

array(1) { 
  ["child"]=> array(4) { 
    [0]=> object(SimpleXMLElement)#59 (1) { 
      [0]=> string(4) "son1" 
    } 
    [1]=> object(SimpleXMLElement)#71 (1) { 
      [0]=> string(9) "daughter2" 
    } 
    [2]=> object(SimpleXMLElement)#77 (1) { 
      [0]=> string(4) "son2" 
    } 
    [3]=> object(SimpleXMLElement)#83 (1) { 
      [0]=> string(4) "son3" 
    } 
  } 
}

I am trying to get daughter1 but no vail. Any suggestion?I can;t see the error. Thanks in advance!

Upvotes: 0

Views: 62

Answers (2)

Nigel Ren
Nigel Ren

Reputation: 57121

The problem is that you are storing the attribute element and not the actual value, all you need to do is cast it to a string by adding (string)...

$array[$key][$i] = (string)$child->attributes()->role;

Which gives...

array(1) {
  'child' =>
  array(4) {
    [0] =>
    string(4) "son1"
    [1] =>
    string(9) "daughter2"
    [2] =>
    string(4) "son2"
    [3] =>
    string(4) "son3"
  }
}

Edit:

To get all of the child nodes, I've reworked most of the code to simplify how it works.

function Recurse1($xml)
{
    $array = [(string)$xml['role']];
    foreach ($xml->children() as $child)
    {
        $array = array_merge($array, Recurse1($child));
    }

    return array_filter($array);
}

$xml = new SimpleXMLElement(
    '<person>
<child role="son1">
<child role="daughter1"/>
</child>
<child role="daughter2">
<child role="son2">
<child role="son3"/>
</child>
</child>
</person>');
var_dump(Recurse1($xml));

As you can see, Recurse1() now just takes the XML and first outputs the value attribute, then repeats this for any child nodes. Sometimes nodes don't have a value attribute, which is why there it returns array_filter($array), which just removes any empty values.

Edit 2:

If you want a non recursive solution, using DOMDocument has an easy way of fetching all the <child> elements using $doc->getElementsByTagName("child");, it's best to check if it has a role attribute, but if it has it just adds it to the list...

$doc = new DOMDocument();
$doc->loadXML($xml);

$childE = $doc->getElementsByTagName("child");
$list = [];
foreach ( $childE as $child )   {
    if ( $child->hasAttribute("role") )     {
        $list[] = $child->getAttribute("role");
    }
}

print_r($list);

Upvotes: 2

mickmackusa
mickmackusa

Reputation: 47899

If you are merely looking for a 1-dimensional array containing all of the role values, you can dispense with recursive convolution, and just let DomDocument & Xpath do all the work for you with a single, easy-to-read query (easier for you, and easy for the next developer that wants to look at your code):

Code: (Demo)

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
foreach ($xpath->evaluate('//child/@role') as $attr) {
    $result[] = $attr->value;
}
var_export($result);

Output:

array (
  0 => 'son1',
  1 => 'daughter1',
  2 => 'daughter2',
  3 => 'son2',
  4 => 'son3',
)

Alternatively, if you want to maintain hierarchy in the output array, you can use this existing StackOverflow solution like this: Demo

Upvotes: 1

Related Questions