Search code examples
phparraysxmlsimplexmlxmlelement

When converting an XML document to an Array in php, is there a way to convert it back and to save it as an XML file where attributes are elements?


I am trying to read an XML file in PHP, edit some values and save it back. I do it by opening the XML file in php. I then convert it using SimpleXML into an array. After doing the manipulation needed, I am struggling in returning that array into the XML file in the same format due to how my XML elements are converted into attributes. Hence when I go from array to XML, my elements (which are attributes now) are saved as attributes in the updated XML file.

I would like to know if it's possible to preserve XML elements when converting back from php array to XML.


A random XML example with two elements, lets call it myFile.xml

<XML>
   <Project Element1 = 'some random value' Element2='Will be stored as attribute instead'>
</XML>

The php code I would run to convert it into an array
<?php
    $xml = simplexml_load_file("myFile.xml") or die("Error: Cannot create object");
    $arrayXML = json_decode(json_encode((array)$xml), TRUE);
    $arrayXML["Project"]["attributes"]["Element1"] = "updated value"
// I will then run some array to XML converter code here found online
// took it from here https://stackoverflow.com/questions/1397036/how-to-convert-array-to-simplexml
    function array_to_xml( $data, &$xml_data ) {
        foreach( $data as $key => $value ) {
            if( is_array($value) ) {
                if( is_numeric($key) ){
                    $key = 'item'.$key; //dealing with <0/>..<n/> issues
                }
                $subnode = $xml_data->addChild($key);
                array_to_xml($value, $subnode);
            } else {
                $xml_data->addChild("$key",htmlspecialchars("$value"));
            }
         }
    }

    $xml_data = new SimpleXMLElement();
    array_to_xml($arrayNexus,$xml_data);
    saving generated xml file;
    $result = $xml_data->asXML('myFile.xml');
?>

Something like this would then generate an XML file like this
<XML>
     <Project>
          <attribute>
               <Element1>updated value</Element1>
               <Element2><Will be stored as attribute instead</Element2>
          </attribute>
     </Project>
</XML>

When the result I would like to have would be

<XML>
   <Project Element1 = 'updated value' Element2='Will be stored as attribute instead'>
</XML>

I could write my own XML converter but if there exist already methods out there, can someone show me the way?


Solution

  • Don't convert the XML - you will loose data if you don't use specific formats like JsonML. It is much easier to use DOM. Use Xpath expressions to fetch the nodes and modify them.

    $document = new DOMDocument();
    $document->loadXML($xml);
    $xpath = new DOMXpath($document);
    
    // iterate the first 'Project' element
    foreach($xpath->evaluate('(/XML/Project)[1]') as $project) {
        // change the attribute value
        $project->setAttribute('Element1', 'updated value');
    }
    
    echo $document->saveXML();
    

    Output:

    <?xml version="1.0"?>
    <XML>
       <Project Element1="updated value" Element2="Will be stored as attribute instead"/>
    </XML>
    

    Xpath

    • 'XML' document element
      /XML
    • 'Project' child elements
      /XML/Project
    • Limit to first found node
      (/XML/Project)[1]

    This example uses the position in the result list as a condition but if the project has an id attribute you could use this to find the element: /XML/Project[@id="example-id"].