Ishrak
Ishrak

Reputation: 71

XML to JSON conversion in PHP SimpleXML

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

Upvotes: 1

Views: 10272

Answers (2)

Rashiqul Rony
Rashiqul Rony

Reputation: 89

$fileContents= file_get_contents("https://www.feedforall.com/sample.xml");
$fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);
$fileContents = trim(str_replace('"', "'", $fileContents));
$simpleXml = simplexml_load_string($fileContents);
$json = json_encode($simpleXml);
$array = json_decode($json,TRUE); // convert the JSON-encoded string to a PHP variable
return $array;

I'ts Better example:

Upvotes: 0

hakre
hakre

Reputation: 197659

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:

Upvotes: 2

Related Questions