Jason Z
Jason Z

Reputation: 265

PHP get XML node attributes when value exist

I want get the whole XML contents, but the results only show node value, node attributes are missing.

XML File:

<main>
    <people num="1">
        <name num1="1">Jack</name>
        <age num2="1">50</age>
    </people>   
</main>

The code is

$xml = simplexml_load_file("c:/www/Mongo/test2.xml");
$xml1=$xml->people;
var_dump($xml1);

Result:

object(SimpleXMLElement)#2 (3) { ["@attributes"]=> array(1) { ["num"]=>string(1) "1" } ["name"]=> string(4) "Jack" ["age"]=> string(2) "50" }

Name&Age node attributes are missing. I know the attributes could get by $xml->people->name, but how to get it only use $xml->people

Upvotes: 0

Views: 475

Answers (2)

mhall
mhall

Reputation: 3701

The problem is that leaf nodes (e.g. name) can have both attributes (num1 = "1") and a value ("Jack"). Just how should that be represented when converted into an array?

If we set $array['people']['name'] = "Jack", where would we store the attributes? We cannot use $array['people']['name']['@attributes'] = ['num1' => 1] as that would overwrite the "Jack" value.

The code below presents one solution, where each (leaf) value is wrapped in a 'value' element, e.g. $array['people']['name']['value'] = "Jack" and the attributes have the standard '@attributes' key, e.g. $array['people']['name']['@attributes'] = ['num1' => 1]. This would work for simple XML like the one in your question but may not be suitable for more complicated documents.

Reading the comments I understand that you actually want to convert the XML into JSON, so that is what the following code does in the end:

// Some example XML (some elements added)
$src = <<<EOS
<main>
    <people num="1">
        <name num1="1">Jack</name>
        <age num2="1">50</age>
        <skills what="ever">
            <skill type="minor">Cookie munching</skill>
            <skill type="major">Cake gobbling</skill>
            <skill>Candy gulping</skill>
        </skills>
    </people>
</main>
EOS;

// Create a DOM element from XML    
$dom = new DOMDocument();
$dom->loadXML($src);

// Use a XPath query to get all leaf nodes (elements without
// element child nodes)
$xpath = new DOMXPath($dom);
foreach ($xpath->query('//*[not(*)]') as $leaf) {
    // Create a new <value> element for each leaf node, moving
    // the leaf value (first child) into that node.
    // E.g. <name num1="1">Jack</name>
    //   => <name num1="1"><value>Jack</value></name>
    $value = $dom->createElement('value');
    $value->appendChild($leaf->firstChild);
    $leaf->insertBefore($value);
}

// Turn into SimpleXMLElement and covert to JSON
$xml  = simplexml_import_dom($dom);
$json = json_encode($xml, JSON_PRETTY_PRINT);
echo $json, PHP_EOL;

Output:

{
    "people": {
        "@attributes": {
            "num": "1"
        },
        "name": {
            "@attributes": {
                "num1": "1"
            },
            "value": "Jack"
        },
        "age": {
            "@attributes": {
                "num2": "1"
            },
            "value": "50"
        },
        "skills": {
            "@attributes": {
                "what": "ever"
            },
            "skill": [
                {
                    "@attributes": {
                        "type": "minor"
                    },
                    "value": "Cookie munching"
                },
                {
                    "@attributes": {
                        "type": "major"
                    },
                    "value": "Cake gobbling"
                },
                {
                    "value": "Candy gulping"
                }
            ]
        }
    }
}

Upvotes: 3

user789456
user789456

Reputation: 173

Here is a better solution using json_encode, json_decode

echo '<pre>';
$xml = simplexml_load_file("n.xml");
$xml=json_decode(json_encode($xml),TRUE);
$xml1=$xml['people'];
print_r($xml1);
echo '<br>';
print_r($xml['people']['@attributes']['num']);

Output:

Array
(
    [@attributes] => Array
        (
            [num] => 1
        )

    [name] => Jack
    [age] => 50
)

1

So one last suggestion , probably you can change your XML data something like this

<?xml version="1.0" encoding="UTF-8"?>
<main>
    <people num="1">
        <name num1="1"><first_name>Jack</first_name></name>
        <age num2="1"><years>50</years></age>
    </people>   
</main>

Output:

    Array
(
    [people] => Array
        (
            [@attributes] => Array
                (
                    [num] => 1
                )

            [name] => Array
                (
                    [@attributes] => Array
                        (
                            [num1] => 1
                        )

                    [first_name] => Jack
                )

            [age] => Array
                (
                    [@attributes] => Array
                        (
                            [num2] => 1
                        )

                    [years] => 50
                )

        )

)

this should work for you. :)

Upvotes: 0

Related Questions