Json 编码或序列化 XML

Posted

技术标签:

【中文标题】Json 编码或序列化 XML【英文标题】:Json Encode or Serialize an XML 【发布时间】:2013-09-04 03:44:47 【问题描述】:

我有一些xml,这是一个简单的版本。

<xml>
<items>
  <item abc="123">item one</item>
  <item abc="456">item two</item>
</items>
</xml>

在内容上使用 SimpleXML,

 $obj = simplexml_load_string( $xml );

我可以使用$obj-&gt;xpath( '//items/item' ); 并访问@attributes。

我需要一个数组结果,所以我尝试了 json_decode(json_encode($obj),true) 技巧,但这似乎是删除对 @attributes 的访问(即 abc="123")。

是否有另一种方法可以提供对属性的访问并为我留下一个数组?

【问题讨论】:

“我需要一个数组结果” - 为什么?您需要它采用什么格式?如果您不介意它的格式,那么只需存储 $item-&gt;asXML(); 并下次重新解析即可。 我正在处理数据以期望标准数组格式的其他方法 那么任何内置的 php 函数如何知道“标准数组格式”需要是什么样的呢?您的代码需要将 you 期望的输入解析为 you 需要的输出。 IMSoP,我会通读你所有的 SimpleXML 主题,希望能得到一些指点。 【参考方案1】:

你需要调用 attributes() 函数。

示例代码:

$xmlString = '<xml>
<items>
  <item abc="123">item one</item>
  <item abc="456">item two</item>
</items>
</xml>';

$xml = new SimpleXMLElement($xmlString);

foreach( $xml->items->item as $value)
$my_array[] =  strval($value->attributes());


print_r($my_array);

Eval

【讨论】:

我需要一个数组结果,所以我猜我需要自己构建一个数组?因为 json_encode() 剥离了属性? 正如我所怀疑的那样。我希望也许有一些 json_encode() 技巧或相关函数可以在将对象转换为数组时保留属性。谢谢! 这个方法看起来不错,但是这段代码很奇怪。为什么你使用$xml-&gt;items-&gt;item[$i++] 而不是$value?为什么分配$xmlitems 只是为了循环它而foreach ( $xml-&gt;items-&gt;item as $value ) 也可以工作? 哦,另外,strval($foo-&gt;attributes()) 将始终返回字符串 'array'。我猜您的意图是将strval 应用于每个属性 而不是整个列表?【参考方案2】:

您可以使用json_encodejson_decode 进行路由,并且可以添加缺少的内容,因为json_encode-ing 遵循SimpleXMLElement 的一些特定规则。

如果您对规则及其详细信息感兴趣,我已经写了两篇关于它的博文:

SimpleXML and JSON Encode in PHP – Part I SimpleXML and JSON Encode in PHP – Part II

对你来说可能更有趣的是第三部分,它展示了如何修改 json 序列化并提供你自己的格式(例如,保留属性):

SimpleXML and JSON Encode in PHP – Part III and End

它附带了一个完整的示例,这里是代码的摘录:

$xml = '<xml>
<items>
  <item abc="123">item one</item>
  <item abc="456">item two</item>
</items>
</xml>';

$obj = simplexml_load_string($xml, 'JsonXMLElement');

echo $json = json_encode($obj, JSON_PRETTY_PRINT), "\n";

print_r(json_decode($json, TRUE));

JSON和数组的输出如下,注意属性是其中的一部分:


    "items": 
        "item": [
            
                "@attributes": 
                    "abc": "123"
                ,
                "@text": "item one"
            ,
            
                "@attributes": 
                    "abc": "456"
                ,
                "@text": "item two"
            
        ]
    

Array
(
    [items] => Array
        (
            [item] => Array
                (
                    [0] => Array
                        (
                            [@attributes] => Array
                                (
                                    [abc] => 123
                                )

                            [@text] => item one
                        )

                    [1] => Array
                        (
                            [@attributes] => Array
                                (
                                    [abc] => 456
                                )

                            [@text] => item two
                        )

                )

        )

)

【讨论】:

值得注意的是,第三部分中的递归函数与独立函数一样工作,无需任何 JSON 参考。使用 DOM 或 XMLReader API 看起来也差不多。我仍然不相信像这样的通用转换比使用可用的 API 以特定情况的方式遍历 XML 的价值。 好吧。第三部分顶部说该函数替换了数组强制转换,因此确保它在没有 JSON 序列化的情况下也能正常工作。如果您选择底部的装饰器(Cutting The Gordian Knot),并确保 $decorator 上的工作实际上也返回了数组(而不是仅仅对其进行分配),这就是这样做的。然后,您可以将其命名为 ArraySimpleXMLElementSerializer 或其他名称:) @hakre 是的;我认为将其呈现为 SimpleXML+json_encode 的 替代 会更强大,而不是暗示它以某种方式“修复”它。顺便说一句,我在这些帖子下方以我的真实姓名发布了几个 cmets(略显批评,但希望不会冒犯),但我认为它们已被垃圾邮件过滤器吃掉了。 @IMSoP:我在我的博客上找不到您的评论,无论是在垃圾邮件中还是在标准阵容中。对不起。还检查了我收到副本的邮件,但什么也没有。也许是错误的网站? @hakre 哦,好吧,也许 wordpress.com 默默地吃了它们;我听说它有时会这样做。感谢收看;也许我会在某个时候再试一次。【参考方案3】:
$xml = new SimpleXMLElement($xmlString);

$xml 现在是一个对象。获取属性值:

$xml->something['id'];

其中 'id' 是属性的名称。

【讨论】:

我需要一个数组结果。我将存储它并想在某个时候检索它。我希望属性在我 json_decode 或反序列化之后存在于数组中。【参考方案4】:

虽然理论上可以编写从 XML 到 PHP 或 JSON 结构的通用转换,但很难捕捉到所有可能存在的细微差别 - 子元素和属性之间的区别、文本内容与属性(如您所见)这里)甚至在子元素旁边,多个具有相同名称的子节点,子元素和文本节点的顺序是否重要(例如在 Xhtml 或 DocBook 中)等等。

如果您需要生成特定格式,通常使用 API(如 SimpleXML)来循环 XML 并生成您需要的结构会容易得多。

您没有指定要实现的结构,但给出输入的一般方法是遍历每个项目,并访问已知属性或遍历每个属性:

$sxml = simplexml_load_string( $xml );
$final_array = array();
foreach ( $sxml->items->item as $xml_item )

    $formatted_item = array();

    // Text content of item
    $formatted_item['content'] = (string)$xml_item;

    // Specifically get 'abc' attribute
    $formatted_item['abc'] = (string)$xml_item['abc'];
    // Maybe one of the attributes is an integer
    $formatted_item['foo_id'] = (int)$xml_item['foo_id'];

    // Or maybe you want to loop over lots of possible attributes
    foreach ( $xml_item->attributes() as $attr_name => $attr_value )
    
         $formatted_item['attrib:' . $attr_name] = (string)$attr_value;
    

    // Add it to a final list
    $final_array[] = $formatted_item;
    // Or maybe you want that array to be keyed on one of the attributes
    $final_array[ (string)$xml_item['key'] ] = $formatted_item;

【讨论】:

【参考方案5】:

这是我发现的一个类,它能够很好地将 XML 处理成数组:http://outlandish.com/blog/xml-to-json/ (backup)。转换为 json 是一个 json_encode() 调用的问题。

【讨论】:

以上是关于Json 编码或序列化 XML的主要内容,如果未能解决你的问题,请参考以下文章

.net JSON 或 XML 对象序列化和包含字段类型的创建

Json或XML快速反序列化类(Visual Studio 2012以上)

GoLang读写数据---下

Json和Xml序列化,啥性能更好?

模块 序列化 json pickle shelv xml

是否有一个 XML 或 JSON 序列化器知道使用哪个构造函数来填充不可变对象并序列化 IEnumerable<> 属性? [关闭]