在PHP中将XML转换为JSON

异步JavaScript + XML(Ajax)的出现使Web应用程序开发产生了新的热情,并使许多架构师和开发人员重新考虑他们创建Web应用程序的方式。 JavaScript对象表示法(JSON)是一种数据交换格式,用于表示在浏览器上运行的业务逻辑中的数据。 许多Ajax开发人员更喜欢在浏览器端JavaScript代码中直接使用JSON处理数据。 随着JSON的使用增加,中间件服务器程序将有必要以JSON格式而不是XML格式向浏览器提供企业应用程序数据。 这意味着开发人员需要将以XML编码的现有服务器端企业数据转换为JSON,然后再将其发送到浏览器。 本文向您展示了如何在将基于XML的应用程序数据发送到浏览器应用程序之前,使用基于PHP的服务器程序将XML格式的应用程序数据转换为JSON格式。

XML基础

XML是定义标记的标准。 基于XML的标记用于描述通过不需要预定义的标签表示的数据。 XML是高度可扩展的,因为您可以根据需要发明新的标签。 清单1显示了以XML表示的数据结构的示例。

清单1. XML数据的简单示例
<?xml version="1.0" encoding="UTF-8"?>
<contacts>
    <contact id="1">
        <name>John Doe</name>
        <phone>123-456-7890</phone>
        <address>
            <street>123 JFKStreet</street>
            <city>Any Town</city>
            <state>Any State</state>
            <zipCode>12345</zipCode>
        </address>
    </contact>
</contacts>

第一行是XML声明,它指定使用的XML版本和字符编码。 随后是根元素<contacts> ,其中包含几个子元素。 子元素的嵌套结构组合在一起以定义联系人的数据。 注意, <address>元素包括在<contact>元素下形成子树结构的子元素。 XML还允许开始标记具有提供有关元素的附加信息的属性。 <contact>元素具有为该元素分配id属性的属性。 XML文档的结尾元素是</contacts> ,它是根元素的结束标记。

JSON基础

JSON不是像XML这样的标记语言。 相反,它是基于文本的数据交换格式。 它是JavaScript对象和数组的数据语法。 简而言之,JSON使您可以简单地表示数据。 例如,将对象括在大括号({})中,并将数组括在方括号([])中。 一段JavaScript代码可以很容易地使用JSON编码的数据,而无需进行任何特殊的解析或其他数据转换。 清单2显示了以JSON格式表示的数据结构。

清单2. JSON数据的简单示例
{
   "contacts" : {
      "contact" : {
         "@attributes" : {
            "id" : "1"
         }, 
         "name" : "John Doe", 
         "phone" : "123-456-7890", 
         "address" : {
            "street" : "123 JFK Street", 
            "city" : "Any Town", 
            "state" : "Any State", 
            "zipCode" : "12345"
         }
      }
   }
}

您可以看到清单1的XML示例中显示的每条数据也在清单2的JSON示例中也存在。 但是,不同之处在于JSON如何使用JavaScript对象和数组数据类型对数据进行编码。 数据结构从一个对象开始,该对象包括一个名为"contacts"的属性,该属性本身就是一个对象。 该对象具有一个名为"contact"属性,它也是一个对象。 该对象包括几个属性,这些属性构成了联系人的详细信息。 注意, "contact"对象包括另一个名为"address" (嵌套)对象,该对象描述了地址的详细信息。 与XML一样,JSON格式的数据是自描述的,因此人和机器都可以轻松读取它。

浏览器端数据处理

现在让我们看一下如何在浏览器端代码中处理数据。 当服务器将XML数据发送到浏览器时,将使用文档对象模型(DOM)API处理该XML数据。 但是,JavaScript开发人员必须学习XML处理的所有复杂性,并编写大量其他代码来解析XML数据,然后才能对该数据进行任何处理。 但是,随着JSON的出现,服务器端代码可以打包和发送JSON编码的应用程序数据,以响应浏览器的请求。 如果服务器端代码将JSON格式的数据发送到浏览器,则JavaScript开发人员无需编写任何其他复杂的逻辑即可解析XML。 另外,以JSON格式接收的数据将很容易在浏览器端代码中视为JavaScript本机数据结构。 清单3中的代码片段显示,处理JSON格式的数据不需要任何额外的工作。

清单3.用于处理从服务器接收的JSON格式的数据的代码片段
var result = httpRequest.responseText;
jsonResponse = eval('(' + result + ')');

清单3的浏览器端代码片段中, result是从服务器接收到的JSON格式的字符串。 通过使用eval语句评估JSON格式的字符串,只需一行代码即可将字符串数据转换为本地JavaScript数据类型。 您可以看到,在浏览器端处理JSON数据要容易得多。 JSON的使用为浏览器端代码带来了简单性和价值。

清单3中eval语句将执行服务器返回的所有代码,因此这里存在安全风险。 风险是有限的,因为浏览器安全策略将JavaScript中的HTTP请求限制为原始加载代码的服务器。 但是,在某些情况下,在将其传递到eval语句之前,可能要谨慎地验证从服务器接收到的数据是否符合期望(也许使用正则表达式)。

XML到JSON的转换

越来越多的应用程序需要将XML数据转换为JSON。 已经出现了几种基于Web的服务来进行此类转换。 IBM TJ Watson研究中心开发了一种特殊的方法,该方法使用PHP进行转换。 这种方法接受XML字符串数据作为输入,并将其转换为JSON格式的数据输出。 这种基于PHP的解决方案具有以下优点:

  • 它可以以独立模式运行,可以从命令行执行。
  • 它可以包含在现有的服务器端代码工件中。
  • 它可以轻松地作为Web服务托管在Web上。

XML到JSON的转换需要几个PHP核心功能:

  • SimpleXMLElement
  • 来自http://pear.php.net的Services_JSON有关详细信息,请参阅参考资料

PHP 5及更高版本支持SimpleXMLElement 。 它是一个对象,其属性包含XML文档中保存的数据。 Services_JSON是PHP开源提案,于2005年底获得批准。它提供JSON特定的编码器(PHP数据到JSON)和解码器(JSON到PHP数据)功能。 现在可以通过PEAR网站获得此开放源代码PHP类库(请参阅参考资料 )。

通过仅使用PHP的这两个核心功能,可以将任意XML数据转换为JSON。 首先,您需要使用SimpleXMLElement将XML内容转换为合适PHP数据类型。 然后,将PHP数据提供给Services_JSON编码器,后者再产生最终的JSON格式的输出。

了解PHP代码

xml2json实现包含三个部分:

  • xml2json.php-具有两个静态函数PHP类
  • xml2json_test.php-行使xml2json转换功能的测试驱动程序
  • test1.xml,test2.xml,test3.xml,test4.xml-具有不同复杂度的XML文件

为简单起见,本文未在代码中显示详细注释。 但是,附加的源文件中的代码确实包含完整的注释。 有关程序逻辑的完整详细信息,请参阅随附的源文件(请参阅下载 )。

清单4定义了一些有用的常量。 代码的第一行导入Services_JSON实现。

清单4.在xml2json.php中定义常量
require_once 'json/JSON.php';
// Internal program-specific Debug option.
define ("DEBUG", false);
// Maximum Recursion Depth that we can allow.
define ("MAX_RECURSION_DEPTH_ALLOWED", 25);
// An empty string
define ("EMPTY_STR", "");
// SimpleXMLElement object property name for attributes
define ("SIMPLE_XML_ELEMENT_OBJECT_PROPERTY_FOR_ATTRIBUTES", "@attributes");
// SimpleXMLElement object name.
define ("SIMPLE_XML_ELEMENT_PHP_CLASS", "SimpleXMLElement");

清单5中显示的代码段是xml2json转换器的入口函数。 它以XML数据作为输入,并将XML字符串转换为SimpleXMLElement对象,该对象作为输入发送到此类中的另一个(递归)函数。 然后,此函数将XML元素转换为PHP关联数组。 然后将该数组作为输入传递到Services_JSON编码器,该编码器为您提供JSON格式的输出。

清单5.在xml2json.php中使用Services_JSON
public static function transformXmlStringToJson($xmlStringContents) {
    $simpleXmlElementObject = simplexml_load_string($xmlStringContents);
if ($simpleXmlElementObject == null) { return(EMPTY_STR); }
$jsonOutput = EMPTY_STR;
// Let us convert the XML structure into PHP array structure. $array1 = xml2json::convertSimpleXmlElementObjectIntoArray($simpleXmlElementObject);
if (($array1 != null) && (sizeof($array1) > 0)) { // Create a new instance of Services_JSON $json = new Services_JSON(); // Let us now convert it to JSON formatted data. $jsonOutput = $json->encode($array1); } // End of if (($array1 != null) && (sizeof($array1) > 0))
return($jsonOutput); } // End of function transformXmlStringToJson

清单6中显示的冗长的代码段使用了一种受PHP开源社区启发的递归技术(请参阅参考资料 )。 它接受SimpleXMLElement对象作为输入,并在嵌套的XML树中进行递归树遍历。 它将所有访问的XML元素存储在PHP关联数组中。 您可以通过更改清单4中定义的常量来调整递归深度限制。

清单6. xml2json.php中的转换逻辑
public static function convertSimpleXmlElementObjectIntoArray($simpleXmlElementObject,
&$recursionDepth=0) { 
  // Keep an eye on how deeply we are involved in recursion.
if ($recursionDepth > MAX_RECURSION_DEPTH_ALLOWED) { // Fatal error. Exit now. return(null); }
if ($recursionDepth == 0) { if (get_class($simpleXmlElementObject) != SIMPLE_XML_ELEMENT_PHP_CLASS) { // If the external caller doesn't call this function initially // with a SimpleXMLElement object, return now. return(null); } else { // Store the original SimpleXmlElementObject sent by the caller. // We will need it at the very end when we return from here for good. $callerProvidedSimpleXmlElementObject = $simpleXmlElementObject; } } // End of if ($recursionDepth == 0) {
if (get_class($simpleXmlElementObject) == SIMPLE_XML_ELEMENT_PHP_CLASS) { // Get a copy of the simpleXmlElementObject $copyOfsimpleXmlElementObject = $simpleXmlElementObject; // Get the object variables in the SimpleXmlElement object for us to iterate. $simpleXmlElementObject = get_object_vars($simpleXmlElementObject); }
// It needs to be an array of object variables. if (is_array($simpleXmlElementObject)) { // Initialize the result array. $resultArray = array(); // Is the input array size 0? Then, we reached the rare CDATA text if any. if (count($simpleXmlElementObject) <= 0) { // Let us return the lonely CDATA. It could even be // an empty element or just filled with whitespaces. return (trim(strval($copyOfsimpleXmlElementObject))); }
// Let us walk through the child elements now. foreach($simpleXmlElementObject as $key=>$value) { // When this block of code is commented, XML attributes will be // added to the result array. // Uncomment the following block of code if XML attributes are // NOT required to be returned as part of the result array. /* if((is_string($key)) && ($key == SIMPLE_XML_ELEMENT_OBJECT_PROPERTY_FOR_ATTRIBUTES)) { continue; } */
// Let us recursively process the current element we just visited. // Increase the recursion depth by one. $recursionDepth++; $resultArray[$key] = xml2json::convertSimpleXmlElementObjectIntoArray($value, $recursionDepth);
// Decrease the recursion depth by one. $recursionDepth--; } // End of foreach($simpleXmlElementObject as $key=>$value) {
if ($recursionDepth == 0) { // That is it. We are heading to the exit now. // Set the XML root element name as the root [top-level] key of // the associative array that we are going to return to the caller of this // recursive function. $tempArray = $resultArray; $resultArray = array(); $resultArray[$callerProvidedSimpleXmlElementObject->getName()] = $tempArray; }
return ($resultArray); } else { // We are now looking at either the XML attribute text or // the text between the XML tags. return (trim(strval($simpleXmlElementObject))); } // End of else } // End of function convertSimpleXmlElementObjectIntoArray.

在成功完成XML树遍历后,此函数将转换所有XML元素(根元素和所有子元素)并将其存储在PHP关联数组中。 对于复杂的XML文档,生成PHP数组将同样复杂。 一旦完全构建了PHP数组,然后Services_JSON编码器就可以轻松将其转换为JSON格式的数据。 要了解此递归逻辑,请签出已记录的源文件。

为xml2json实现测试驱动程序

清单7中显示的代码片段是一个测试驱动程序,它练习xml2json转换器逻辑。

清单7. xml2json_test.php
<?php
    require_once("xml2json.php");
// Filename from where XML contents are to be read. $testXmlFile = "";
// Read the filename from the command line. if ($argc <= 1) { print("Please provide the XML filename as a command-line argument:\n"); print("\tphp -f xml2json_test.php test1.xml\n"); return; } else { $testXmlFile = $argv[1]; }
//Read the XML contents from the input file. file_exists($testXmlFile) or die('Could not find file ' . $testXmlFile); $xmlStringContents = file_get_contents($testXmlFile);
$jsonContents = ""; // Convert it to JSON now. // xml2json simply takes a String containing XML contents as input. $jsonContents = xml2json::transformXmlStringToJson($xmlStringContents);
echo("JSON formatted output generated by xml2json:\n\n"); echo($jsonContents); ?>

您可以使用XML文件名作为命令行参数从命令行运行程序:

php -f xml2json_test.php test2.xml

从命令行执行时,程序将从文件中读取XML内容到字符串变量中。 然后,它在xml2json类中调用静态函数以获取JSON格式的结果。 除了从命令行运行程序之外,还可以修改此源文件中的逻辑,以使用简单对象访问协议(SOAP)或表示状态传输(REST)访问协议将xml2json转换器公开为可远程调用的Web服务。 如果需要,您可以用最少的工作在PHP中轻松执行该操作。

清单8显示了本文提供的用于测试xml2json实现的四个测试XML文件xml2json 。 复杂程度因一个测试文件而异。 您可以将这些文件之一作为命令行参数传递给测试驱动程序xml2json_test.php。

清单8.使用test2.xml测试xml2json实现
<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book id="1">
        <title>Code Generation in Action</title>
        <author><first>Jack</first><last>Herrington</last></author>
        <publisher>Manning</publisher>
    </book>
<book id="2"> <title>PHP Hacks</title> <author><first>Jack</first><last>Herrington</last></author> <publisher>O'Reilly</publisher> </book>
<book id="3"> <title>Podcasting Hacks</title> <author><first>Jack</first><last>Herrington</last></author> <publisher>O'Reilly</publisher> </book> </books>

当您使用test2.xml作为测试驱动程序xml2json_test.php的命令行参数时, 清单9中显示的代码段是JSON格式的结果。

清单9. test2.xml的JSON格式结果
{
   "books" : {
      "book" : [ {
         "@attributes" : {
            "id" : "1"
         }, 
         "title" : "Code Generation in Action", 
         "author" : {
            "first" : "Jack", "last" : "Herrington"
         }, 
         "publisher" : "Manning"
      }, {
         "@attributes" : {
            "id" : "2"
         }, 
         "title" : "PHP Hacks", "author" : {
            "first" : "Jack", "last" : "Herrington"
         }, 
         "publisher" : "O'Reilly"
      }, {
         "@attributes" : {
            "id" : "3"
         }, 
         "title" : "Podcasting Hacks", "author" : {
            "first" : "Jack", "last" : "Herrington"
         }, 
         "publisher" : "O'Reilly"
      }
   ]}
}

请注意, <book>元素的XML属性id作为"@attributes"对象属性存储在JSON数据中,而<book>元素作为对象数组存储在JSON数据中。 可以使用eval语句在JavaScript代码中轻松使用此JSON输出。

结论

JSON在Web开发人员中才刚刚开始兴起。 它的成功(主要在JavaScript开发人员中看到)是由于其优雅和简单。 在某些情况下,JSON可以替代XML。 本文总结了在中间件服务器层进行XML到JSON转换的需求。 它进一步强调了将现有的XML编码的企业数据作为JSON格式的数据加以利用的基本原理,以便浏览器端程序可以轻松使用它。 它提供了可以执行XML到JSON转换PHP代码。 (请参阅下载 。)

您可以通过多种方式使用本文中提供的源代码-作为独立工具,作为要在现有服务器端程序中使用的共享类库,或者作为参与企业的SOAP / REST Web服务功能面向服务的体系结构(SOA)。


翻译自: https://www.ibm.com/developerworks/opensource/library/x-xml2jsonphp/index.html

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值