Location: PHPKode > scripts > XML to from array > xml-to-from-array/arr2xml.class.php
<?php
// 
// Author: Mozart Fazito Rezende
// Email:  hide@address.com
// Copywright : Free under Open Source Software rules
// PHP Version: 5 with XML
//
// Purpose: Convert PHP type array to XML object and vice-versa.
//
class xml_to_from_array {
   //
   // Instructions:
   //
   // The method "array_to_xml()" converts an array into XML object.
   //          Notes:
   //          1. In order to satisfy the "unique root node" requirement of XML formalism, in the case
   //             of array with more than one key in the first dimension (vector), it will be created
   //             a node named "raiz" as root in the outcoming XML.
   //          2. In order to satisfy the "not numeric node name" requirement of XML formalism, the
   //             numeric keys in the array will receive the prefix "A_", before conversion to node
   //             names in the outcoming XML.
   //          3. The array keys, formed by number prefixed by "X_", will be converted to sequenced 
   //             nodes, without a node sibling. This behavior reverses the occurrence of multiple
   //             child nodes in XML, transformed by the "xml_to_array()" method.
   //          4. The array keys, named "valor" and "atributos", will be converted to a attributed 
   //             XML node, with node name formed by the value of the array cell 'valor' and 
   //             attributes generated from the array cell 'atributos'. This behavior reverses the
   //             conversion of attributed nodes made by the "xml_to_array()" method.
   //
   // The method "xml_to_array()" converts an XML object into array.
   //          Notes:
   //          1. If the XML root node is named "raiz", it will not be converted to the outcoming array.
   //             This behavior reverses the root node created by the "array_to_xml()" method when the
   //             first dimension of an array is a vector.
   //          2. If the XML node name is a number prefixed by "A_", it will be convert to a numeric 
   //             key in the outcoming array. This behavior restore the numbered key, converted by the
   //             "array_to_xml()" method.
   //          3. The multiple XML child nodes, with the same node Name, will be converted to numbered
   //             array keys prefixed by "X_", in the outcoming array.
   //          4. The atributed XML node will generate two array keys in the outcoming array: one, named
   //             "valor", to receive the node name and other named "atributos" to receive the atributes.
   //
   // Limitations:
   //          In order to guarantee the reversibility of the created XML back to array and vice-versa,
   //          the incoming array cannot use key names, and XML object cannot usenode names nor 
   //          attribute names like:
   //             . "raiz"
   //             . "atributos"
   //             . "valor"
   //             . number prefixed by "A_"
   //             . number prefixed by "X_".
   //           Note: Contributions attempting the elimination of these limitations will be well received.
   //
   // Test:
   //          Run the "arr2xm.example.php" file
   //
   var $arrXML = Array();
   var $arrObjXML = Array();
   var $msg = "";
   //
   function xml_to_array(&$dom){
      reset($this->arrXML);
      $this->parse_node($dom); 
      return ($this->arrXML);
   }

   private function parse_node($node, $s_arr='', $seq_dup=0) {
      $a_dup = Array();                         // Array with duplicated node names in a XML tree level
      $a_uni = Array();                         // Array with all node names in a XML tree level
      // Process the children of the current node
      if ($node->hasChildNodes()) { 
         //
         foreach($node->childNodes as $n) {
            // Skip the document root node:
            if ($node->nodeName == "#document" and strlen($s_arr) == 0){
               $s_arr = "\$this->arrXML";
               $this->parse_node($n, $s_arr);
               return;
            }
            // Create the two arrays in order to find multiple XML child nodes
            if(in_array($n->nodeName, $a_uni)){
               $a_dup[$n->nodeName] = 1;
            }else{
               $a_uni[] = $n->nodeName;
            }
         }
         // Eliminate the "A_" previx created by the array_to_xml() method
         $nodeName = utf8_decode($node->nodeName);
         $tam = strlen($nodeName);
         if ($tam > 2){
            $prefix = substr($nodeName, 0, 2);
            $sufix  = substr($nodeName, 2, ($tam-2));
            if ($prefix == "A_"){
               $nodeName = $sufix;
            }
         }
         // Skip the first XML node, if their name is 'raiz'
         if (! ($node->nodeName == "raiz" and $s_arr == "\$this->arrXML")){
            if ($seq_dup == 0){
               $s_arr .= "['" . $nodeName . "']";
            }else{
               $s_arr .= "['" . $nodeName . "']['X_" . $seq_dup . "']";
            }
         }
         // Process the attributes of a XML node
         if ($node->hasAttributes()) { 
            foreach ($node->attributes as $attr){
               $com = $s_arr . "['atributos']['" . utf8_decode($attr->name) . "'] = '"
                    . utf8_decode($attr->value) . "';";
               eval ($com);
            }
         }
         // Create the prefixed numbered array cells for multiple child nodes in this level
         foreach($node->childNodes as $n) {
            if ($n->nodeName == '#text') { 
               $this->cria_array($node, $s_arr);
               continue;
            }
            // Put the node name
            if ($a_dup[$n->nodeName] > 0){
               $this->parse_node($n, $s_arr, $a_dup[$n->nodeName]); 
               $a_dup[$n->nodeName] = $a_dup[$n->nodeName] + 1;
            }else{
               $this->parse_node($n, $s_arr); 
            }
         } 
      }
   } 

   function cria_array($node, $s_arr){
      if ($node->hasAttributes()) {
         foreach ($node->attributes as $attr){
            $com = $s_arr . "['atributos']['" . utf8_decode($attr->name) . "'] = '"
                 . utf8_decode($attr->value) . "';";
           eval ($com);
         }
         $com = $s_arr . "['valor'] = '" . utf8_decode($node->nodeValue) . "';";
      }else{
         $com = $s_arr . " = '" . utf8_decode($node->nodeValue) . "';";
      }
      eval ($com);
   }

   function array_to_xml(&$arr_xml){
      reset($this->arrObjXML);
      // Create the document.
      $this->arrObjXML[0] = new DOMDocument( "1.0", "ISO-8859-1" );
      $i = 0;
      if (count($arr_xml) > 1){
         $this->arrObjXML[1] = $this->arrObjXML[0]->createElement("raiz");
         $this->parse_arr($arr_xml, 2);
         $this->arrObjXML[0]->appendChild($this->arrObjXML[1]);
      }else{
         $this->parse_arr($arr_xml, 1);
      }
      return ($this->arrObjXML[0]);
   }

   private function parse_arr($arrCell, $i) {
      //
      if (is_array($arrCell)) { 
         foreach ($arrCell as $cellName => $cellValue){
            // Reverse the attributed node
            if ($cellName == "valor"){
               $this->arrObjXML[$i-1]->nodeValue = utf8_encode($cellValue);
               continue;
            }
            // The atributes
            if ($cellName == "atributos"){
               foreach ($cellValue as $attrName => $attrValue){
                  $this->arrObjXML[$i-1]->setAttribute( utf8_encode($attrName), utf8_encode($attrValue) );
               }
               continue;
            }
            // Create the prefixed cell for numbered key
            if (is_numeric($cellName)){
               $cellName = "A_" . $cellName;
            }
            // Reverse the prefixed numbered cell to multiple childs
            if (is_array($cellValue)){
               $ha_X = false;
               foreach ($cellValue as $subCellName => $subCellValue){
                  $tam = strlen($subCellName);
                  if ($tam > 2){
                     $prefix = substr($subCellName, 0, 2);
                     $sufix  = substr($subCellName, 2, ($tam-2));
                     if ($prefix == "X_"){
                        $this->arrObjXML[$i] = $this->arrObjXML[0]->createElement(utf8_encode($cellName));
                        $this->parse_arr($subCellValue, $i+1);
                        $this->arrObjXML[$i-1]->appendChild($this->arrObjXML[$i]);
                        $ha_X = true;
                     }
                  }
               }
               if ($ha_X == true){ continue; }
            }
            // Process the common array cell
            if (is_array($cellValue)){
               $this->arrObjXML[$i] = $this->arrObjXML[0]->createElement(utf8_encode($cellName));
               $this->parse_arr($cellValue, $i+1);
               $this->arrObjXML[$i-1]->appendChild($this->arrObjXML[$i]);
            }else{
               $this->arrObjXML[$i] = $this->arrObjXML[0]->createElement(utf8_encode($cellName), utf8_encode($cellValue) );
               $this->arrObjXML[$i-1]->appendChild($this->arrObjXML[$i]);
            }
         }
      }
   } 
}
?>
Return current item: XML to from array