PHP SimpleXML中的XML到JSON转换 [英] XML to JSON conversion in PHP SimpleXML

查看:65
本文介绍了PHP SimpleXML中的XML到JSON转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

            $data = "<QRYRESULT>
            <ISSUCCESS>Y</ISSUCCESS>
            <EBLCUSTOMER ACCOUNTNO='11111'>
            <CUSTACCTNO>121212</CUSTACCTNO>
            <ACCTSTATUS>active</ACCTSTATUS>
            <CCYDESC>BDT</CCYDESC>
            <BALANCE>9999</BALANCE>
            <AVAILABLEBALANCE>99</AVAILABLEBALANCE>
            <CUSTOMERNAME>cus_name</CUSTOMERNAME>
            <AMOUNTONHOLD>1000</AMOUNTONHOLD>
            <ODLIMIT>99</ODLIMIT>
            </EBLCUSTOMER>
            </QRYRESULT>";

这是我要转换的XML字符串.我已经使用了以下代码.

           $result = str_replace(array("\n", "\r", "\t"), '', $data);
           $xml = simplexml_load_string($result);
           $object = new stdclass();
           $object->webservice[] = $xml;
           $result = json_encode($object);
           header('content-Type: application/json');
           echo $result;

我正在获取以下json数据.

  {
     "webservice": [
       {
        "ISSUCCESS": "Y",
        "CUSTSUMMARY": {
            "@attributes": {
                "ACCOUNT": "11111"
            },
            "IDACCOUNT": "1010101",
            "CODACCTCURR": "BDT",
            "NUMBALANCE": "99999",
            "ACCTDESC": "22222",
            "PRDNAME": "name"
            }
         }
      ]
   }

但是我不希望使用"@attributes".我想要类似以下的输出:

{
  "QRYRESULT": {
   "ISSUCCESS": "Y",
   "EBLCUSTOMER": {
    "-ACCOUNTNO": "11111",
    "CUSTACCTNO": "121212",
    "ACCTSTATUS": "active",
    "CCYDESC": "BDT",
    "BALANCE": "9999",
     "AVAILABLEBALANCE": "99",
     "CUSTOMERNAME": "cus_name",
     "AMOUNTONHOLD": "1000",
    "ODLIMIT": "99"
    }
   }
  }

我该怎么做?

解决方案

您不想在JSON中编码"@attributes"字段,但这是PHP JSON序列化SimpleXMLElement的标准方法. /p>

正如您所说要更改的那样,您需要更改PHP JSON序列化对象的方式.这可以通过使用实现 JsonSerializable 来实现. > SimpleXMLElement ,然后根据需要提供JSON序列化:

class JsonSerializer extends SimpleXmlElement implements JsonSerializable
{
    /**
     * SimpleXMLElement JSON serialization
     *
     * @return null|string
     *
     * @link http://php.net/JsonSerializable.jsonSerialize
     * @see JsonSerializable::jsonSerialize
     */
    function jsonSerialize()
    {
        // jishan's SimpleXMLElement JSON serialization ...

        return $serialized;
    }
}

例如通过将属性用作所有子元素之类的字段.

然后,您可以轻松地集成它,例如代替

$xml = simplexml_load_string($result);

您可以使用

$xml = simplexml_load_string($result, 'JsonSerializer');

或者只是

$xml = new JsonSerializer($result);

和其余功能相同,但只需要序列化即可.

示例:

$result = str_replace(array("\n", "\r", "\t"), '', $data);
$xml = new JsonSerializer($result);
$object = new stdclass();
$object->webservice[] = $xml;
$result = json_encode($object, JSON_PRETTY_PRINT);
header('content-Type: application/json');
echo $result;

输出:

{
    "webservice": [
        {
            "EBLCUSTOMER": {
                "ACCOUNTNO": "11111",
                "CUSTACCTNO": "121212",
                "ACCTSTATUS": "active",
                "CCYDESC": "BDT",
                "BALANCE": "9999",
                "AVAILABLEBALANCE": "99",
                "CUSTOMERNAME": "cus_name",
                "AMOUNTONHOLD": "1000",
                "ODLIMIT": "99"
            }
        }
    ]
}

以上示例的序列化功能为:

function jsonSerialize()
{
    // text node (or mixed node represented as text or self closing tag)
    if (!count($this)) {
        return $this[0] == $this
            ? trim($this) : null ;
    }

    // process all child elements and their attributes
    foreach ($this as $tag => $element) {
        // attributes first
        foreach ($element->attributes() as $name => $value) {
            $array[$tag][$name] = $value;
        }
        // child elements second
        foreach($element as $name => $value) {
            $array[$tag][$name] = $value;
        }
    }

    return $array;
}

这里有一些注释:

  • 在序列化中,您必须照顾自己的元素类型.对于没有子元素的单个元素,区分是最重要的.如果需要对这些属性进行处理,则需要添加它.
  • trim($this)可能已经为您省去了尝试使用$result = str_replace(array("\n", "\r", "\t"), '', $data);解决的问题.在任何情况下, SimpleXMLElement 都会以JSON序列化"\r"字符( SimpleXMLElement 使用"\n"作为中断).另外,您可能对 XML中的空白规范化的规则感兴趣.
  • 如果属性与子元素具有相同的名称,它将被子元素覆盖.
  • 如果子元素跟在另一个具有相同名称的子元素之后,它将被覆盖.

最后两点只是为了使示例代码保持简单.我的一系列博客文章中给出了一种与 SimpleXMLElement 的标准PHP JSON序列化相一致的方法.

此过程的基本知识和示例性 JsonSerialize 实现在第三篇文章中提供:当有一个孩子时,PHP将XML转换为JSON组

            $data = "<QRYRESULT>
            <ISSUCCESS>Y</ISSUCCESS>
            <EBLCUSTOMER ACCOUNTNO='11111'>
            <CUSTACCTNO>121212</CUSTACCTNO>
            <ACCTSTATUS>active</ACCTSTATUS>
            <CCYDESC>BDT</CCYDESC>
            <BALANCE>9999</BALANCE>
            <AVAILABLEBALANCE>99</AVAILABLEBALANCE>
            <CUSTOMERNAME>cus_name</CUSTOMERNAME>
            <AMOUNTONHOLD>1000</AMOUNTONHOLD>
            <ODLIMIT>99</ODLIMIT>
            </EBLCUSTOMER>
            </QRYRESULT>";

this is the XML string I am trying to convert. I have used the folloung code.

           $result = str_replace(array("\n", "\r", "\t"), '', $data);
           $xml = simplexml_load_string($result);
           $object = new stdclass();
           $object->webservice[] = $xml;
           $result = json_encode($object);
           header('content-Type: application/json');
           echo $result;

And I am getting the following json data.

  {
     "webservice": [
       {
        "ISSUCCESS": "Y",
        "CUSTSUMMARY": {
            "@attributes": {
                "ACCOUNT": "11111"
            },
            "IDACCOUNT": "1010101",
            "CODACCTCURR": "BDT",
            "NUMBALANCE": "99999",
            "ACCTDESC": "22222",
            "PRDNAME": "name"
            }
         }
      ]
   }

But i don't want the "@attributes". I want the output like below:

{
  "QRYRESULT": {
   "ISSUCCESS": "Y",
   "EBLCUSTOMER": {
    "-ACCOUNTNO": "11111",
    "CUSTACCTNO": "121212",
    "ACCTSTATUS": "active",
    "CCYDESC": "BDT",
    "BALANCE": "9999",
     "AVAILABLEBALANCE": "99",
     "CUSTOMERNAME": "cus_name",
     "AMOUNTONHOLD": "1000",
    "ODLIMIT": "99"
    }
   }
  }

How can I do that ?

解决方案

You don't want to have the "@attributes" field encoded in the JSON, however this is the standard way how PHP JSON serializes a SimpleXMLElement.

As you say you want to change that, you need to change the way how PHP JSON serializes the object. This is possible by implementing JsonSerializable with a SimpleXMLElement on your own and then provide the JSON serialization as you wish:

class JsonSerializer extends SimpleXmlElement implements JsonSerializable
{
    /**
     * SimpleXMLElement JSON serialization
     *
     * @return null|string
     *
     * @link http://php.net/JsonSerializable.jsonSerialize
     * @see JsonSerializable::jsonSerialize
     */
    function jsonSerialize()
    {
        // jishan's SimpleXMLElement JSON serialization ...

        return $serialized;
    }
}

E.g. by using the attributes as fields like all the child elements.

You can then just integrate it easily, e.g. instead of

$xml = simplexml_load_string($result);

you can use

$xml = simplexml_load_string($result, 'JsonSerializer');

or just

$xml = new JsonSerializer($result);

and the rest of your function works the same but just with your wishes serialization.

Example:

$result = str_replace(array("\n", "\r", "\t"), '', $data);
$xml = new JsonSerializer($result);
$object = new stdclass();
$object->webservice[] = $xml;
$result = json_encode($object, JSON_PRETTY_PRINT);
header('content-Type: application/json');
echo $result;

Output:

{
    "webservice": [
        {
            "EBLCUSTOMER": {
                "ACCOUNTNO": "11111",
                "CUSTACCTNO": "121212",
                "ACCTSTATUS": "active",
                "CCYDESC": "BDT",
                "BALANCE": "9999",
                "AVAILABLEBALANCE": "99",
                "CUSTOMERNAME": "cus_name",
                "AMOUNTONHOLD": "1000",
                "ODLIMIT": "99"
            }
        }
    ]
}

The serialization function for the example above is:

function jsonSerialize()
{
    // text node (or mixed node represented as text or self closing tag)
    if (!count($this)) {
        return $this[0] == $this
            ? trim($this) : null ;
    }

    // process all child elements and their attributes
    foreach ($this as $tag => $element) {
        // attributes first
        foreach ($element->attributes() as $name => $value) {
            $array[$tag][$name] = $value;
        }
        // child elements second
        foreach($element as $name => $value) {
            $array[$tag][$name] = $value;
        }
    }

    return $array;
}

Some notes here:

  • In the serialization you have to take care of the type of element your own. The differentiation is done on top for the single elements with no children. If you need attribute handling on these, you need to add it.
  • The trim($this) perhaps already spares you the issue you try to catch with $result = str_replace(array("\n", "\r", "\t"), '', $data);. SimpleXMLElement in any case would JSON serialize "\r" characters (SimpleXMLElement makes use of "\n" for breaks). Additionally you might be interested in the rules of whitespace normalization in XML.
  • In case an attribute has the same name as a child element, it will be overwritten by the child element.
  • In case a child element that follows another child element with the same name, it will be overwritten.

The two last points are just to keep the example code simple. A way that is aligned to standard PHP JSON serialization of a SimpleXMLElement is given in a series of blog posts of mine.

Basics of exactly this procedure and an exemplary JsonSerialize implementation is available in the third post: SimpleXML and JSON Encode in PHP – Part III and End.

Another related question is:

这篇关于PHP SimpleXML中的XML到JSON转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆