在XML到PHP的数组中没有获取键


In XML to PHP array not getting keys

我的服务器代码如下:

<?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;
?>

但现在我得到的结果是:

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
        )
)

所以我得到的不是像first_namelast_name这样的密钥,而是像0,1,2... 这样的密钥

那么如何获取XML中指定的密钥呢?

首先,实际上不需要json_encode/解码。您已经可以使用SimpleXML遍历所需的值。

print_r是误导性的,你可能会认为在转储之后,那些Type属性就不见了,但它们仍然存在。这里有一个雄辩的答案来讨论这个问题。

但如果你想获得这些值,你可以这样做(注意有很多方法可以获得):

$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/>";
}

样本输出

缺少属性的原因是json_encode。当你仔细观察它时,你会发现,编码吞噬了属性Type

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

将显示

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

另请参阅json_encode手册页面上的此注释。

但正如@Ghost已经指出的那样,属性仍然存在于$xml中,随时可以检查。

这可以通过更改json_serialize上的对象行为来实现,例如,通过查找标记名称,然后更改返回的数据:

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);

这会产生以下输出:

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
)

另一种选择是在将文档序列化为JSON(然后返回到数组)之前修改文档。

以下示例将所有<Stat>元素转换为以包含原始<Stat>元素值的Type属性命名的元素。然后移除<Stat>元素:

$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);

此示例产生以下输出:

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
)

这只是两个例子。两者都可以创建相同的输出,它只是显示了两个不同的位置,您可以在其中放置转换文档的逻辑。

相关资源:

  • 当有一个子组时,PHP将XML转换为JSON组
  • 使用SimpleXMLElement从对象获取数组