0

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!

2
  • 1
    So what exactly is your desired output? Do you want to maintain the hierarchy of the elements or do you want to have a flattened or semi-flattened array? I'd like to post an answer, but your question is a bit Unclear. Commented Oct 28, 2018 at 6:21
  • You are getting daughter1, you're just overwriting it. Commented Oct 28, 2018 at 6:52

2 Answers 2

2

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);
Sign up to request clarification or add additional context in comments.

3 Comments

I need to take the daughter1 value
@Konstantinos More importantly than marking accepted answers is writing a clear question. Please clarify your exact desired output. From your wording some people may think that you ONLY want daughter1. I am more interested in the depth of your data structure.
@mickmackusa, the point about accepting the answer is more about the general idea of accepting answers, they have several questions which they seem to have an answer to and left comments to that effect, but they have not accepted any of them (at this point). Also (only a minor thing) but would the request for clarification of the question be better placed on the question itself?
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.