Reputation: 29
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
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
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