1

My server code is like:

<?php
    $xml_data='<Player uID="p59936">
        <Name>Wojciech Szczesny</Name>
        <Position>Goalkeeper</Position>
        <Stat Type="first_name">Wojciech</Stat>
        <Stat Type="last_name">Szczesny</Stat>
        <Stat Type="birth_date">1990-04-18</Stat>
        <Stat Type="birth_place">Warszawa</Stat>
        <Stat Type="first_nationality">Poland</Stat>
        <Stat Type="weight">84</Stat>
        <Stat Type="height">196</Stat>
        <Stat Type="jersey_num">1</Stat>
        <Stat Type="real_position">Goalkeeper</Stat>
        <Stat Type="real_position_side">Unknown</Stat>
        <Stat Type="join_date">2008-07-01</Stat>
        <Stat Type="country">Poland</Stat>
        </Player>';
    $xml = simplexml_load_string($xml_data); 
    $array = json_decode(json_encode($xml),true);
    echo "<pre>";print_r($array);exit;
?>

But now I am getting result like:

Array
(
    [@attributes] => Array
        (
            [uID] => p59936
        )

    [Name] => Wojciech Szczesny
    [Position] => Goalkeeper
    [Stat] => Array
        (
            [0] => Wojciech
            [1] => Szczesny
            [2] => 1990-04-18
            [3] => Warszawa
            [4] => Poland
            [5] => 84
            [6] => 196
            [7] => 1
            [8] => Goalkeeper
            [9] => Unknown
            [10] => 2008-07-01
            [11] => Poland
        )

)

So instead of key like : first_name, last_name I am getting keys like 0,1,2...

So how to get key which specifies in XML?

rtruszk
  • 3,902
  • 13
  • 36
  • 53
Er.KT
  • 2,852
  • 1
  • 36
  • 70

3 Answers3

2

First off, you actually don't need to json_encode/decode that. You can already use SimpleXML to traverse those values that you want.

That print_r is misleading, you'd think that after that dump, those Type attributes are missing but they are there. Here's an eloquent answer that discusses that issue.

But if you want to get those values you can do it this way (note that there are numerous of ways of getting this):

$xml = simplexml_load_string($xml_data);
foreach($xml->Stat as $stat) {
    $type = (string) $stat->attributes()->Type;
    $node_value = (string) $stat;
    echo "$type: $node_value <br/>";
}

Sample Output

Community
  • 1
  • 1
Kevin
  • 41,694
  • 12
  • 53
  • 70
  • Thanks @Ghost its working, but now my question is whatever I have posted in question is just small part of whole xml. so how to convert whole xml data into php array with attribute ? – Er.KT Mar 20 '15 at 08:44
  • @Er.KT I don't see, how this can be done generally. I guess, you need to write a custom function to convert `$xml` into a PHP object. – Olaf Dietsche Mar 20 '15 at 09:07
  • 1
    It also works with [extending from SimpleXMLElement and overriding jsonSerialize and manipulate based on tagname (elaborated example)](http://stackoverflow.com/a/16938322/367456). – hakre Mar 20 '15 at 09:14
1

The reason for the missing attributes is json_encode. When you look at it closely, you will see, that encoding swallows the attribute Type

$json = json_encode($xml);
print_r($json);

will show

{"@attributes":{"uID":"p59936"},"Name":"Wojciech Szczesny","Position":"Goalkeeper","Stat":["Wojciech","Szczesny","1990-04-18","Warszawa","Poland","84","196","1","Goalkeeper","Unknown","2008-07-01","Poland"]}

See also this comment at the json_encode manual page.

But as @Ghost already pointed out, the attributes are still there in $xml, ready to be examined.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
1

This is either possible by changing the objects behavior on json_serialize, for example by looking for the tag-name and then change the returned data:

class MyJson extends SimpleXMLElement implements JsonSerializable
{

    public function jsonSerialize() {
        $name = $this->getName();

        if ($name !== 'Player') {
            return $this;
        }

        $data = [];
        foreach ($this as $name => $element) {
            if ($name === 'Stat') {
                $name = (string) $element['Type'];

            }
            $data[$name] = (string) $element;
        }

        return $data;
    }
}

$xml = simplexml_load_string($buffer, 'MyJson');
$array = json_decode(json_encode($xml), true);
print_r($array);

This produces the following output:

Array
(
    [Name] => Wojciech Szczesny
    [Position] => Goalkeeper
    [first_name] => Wojciech
    [last_name] => Szczesny
    [birth_date] => 1990-04-18
    [birth_place] => Warszawa
    [first_nationality] => Poland
    [weight] => 84
    [height] => 196
    [jersey_num] => 1
    [real_position] => Goalkeeper
    [real_position_side] => Unknown
    [join_date] => 2008-07-01
    [country] => Poland
)

Another alternative is to modify the document before you serialize it to JSON (and then back to an array).

The following example converts all <Stat> elements into elements named after the Type attribute containing the value of the original <Stat> element. The <Stat> elements are then removed:

$xml = simplexml_load_string($buffer);
foreach ($xml->xpath("//Player/Stat") as $stat) {
    $parent = $stat->xpath('..')[0];
    $parent->addChild((string) $stat["Type"])[0] = trim($stat);
    unset($stat[0]);
}

$array = json_decode(json_encode($xml), true);
print_r($array);

This example produces the following output:

Array
(
    [@attributes] => Array
        (
            [uID] => p59936
        )

    [Name] => Wojciech Szczesny
    [Position] => Goalkeeper
    [first_name] => Wojciech
    [last_name] => Szczesny
    [birth_date] => 1990-04-18
    [birth_place] => Warszawa
    [first_nationality] => Poland
    [weight] => 84
    [height] => 196
    [jersey_num] => 1
    [real_position] => Goalkeeper
    [real_position_side] => Unknown
    [join_date] => 2008-07-01
    [country] => Poland
)

These are just two examples. Both could create the same output, it's just showing two different places where you can place the logic to convert the document.

Related Resources:

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836