PHP Classes

File: XmlHelper.class.php

Recommend this page to a friend!
  Classes of Richard Williams   XML Helper   XmlHelper.class.php   Download  
File: XmlHelper.class.php
Role: Class source
Content type: text/plain
Description: Class
Class: XML Helper
Extract XML data into an array and vice-versa
Author: By
Last change:
Date: 13 years ago
Size: 8,762 bytes
 

Contents

Class file image Download
<?php
/**
 * Class of utility functions for XML manipulation.
 *
 * $array = xmlToArray($xmlString) Convert an XML string to an equivalent array.
 * $xmlString = arrayToXml($array) Convert an array to an equivalent XML string.
 *
 * See the accompanying doc file for details of use.
 * See the accompanying phpunit test file for examples of use.
 *
 * Please report any bugs to richard at roguewavelimited.com. If possible include
 * a sample data file and description of the bug.
 *
 * If you have any suggestions on how to improve this class, let me know.
 *
 * You are free to use this class in any way you see fit.
 *
 * Richard Williams
 * Rogue Wave Limited
 * Jan 2, 2011
 */

class XmlHelper {

   
// Name to use as name of attribute array.
   
private $attributesArrayName = 'attributes';
   
   
// Case folding (uppercasing of names) is on by default (just like normal parser)
   
private $foldCase = true;

   
// Turn off values returned as arrays and ignore attributes.
    // Attributes and value arrays are on by default.
   
private $noAttributes = false;

   
// If true, then leaing and trailing whitespace is removed from attributes and values.
    // Off by default.
   
private $trimText = false;

   
// Vals returned by DOM parser.
   
private $vals;

   
// Name to use as name of value array.
   
private $valueArrayName = 'value';

   
/**
     * Create XML from an array.
     *
     * @param <type> $array
     * @param <type> $numericName Name to be used for numeric array indexes.
     */
   
function arrayToXml ($array) {
       
$dom = new DOMDocument();
       
$dom->encoding = "ISO-8859-1";
// $dom->encoding = "UTF-8";

       
$each = each($array);
       
$root = $each[0];
       
$array = $each[1];

       
$rootNode = $dom->appendChild($dom->createElement($root));
       
$this->putChildren($dom, $array, $rootNode);

        return
$dom->saveXML();
    }
   

    private function
putChildren(DOMDocument &$dom, array $arr, DOMElement $node) {

       
/*
         * Each node can be one of three types. 'value', an array indicating a sub-node
         * 'and 'attributes' indicating an array of attributes.
         */

       
$arrayParent = null;
        foreach(
$arr as $name => $content) {

            if (
strtoupper($name) == 'ATTRIBUTES') {
                foreach(
$content as $n => $v) {
                   
$node->setAttribute($n, $v);
                }
           
            } else if (
strtoupper($name) == 'VALUE') {
               
$node->appendChild($dom->createTextNode($content));

            } else {

               
// An integer index means that this starts a set
                // of elements with the same name.

               
if (is_integer($name)) {

                   
// Get the parent node and remove the integer element.

                   
$child = $node;
                    if (
is_null($arrayParent)) {
                       
$arrayParent = $node->parentNode;
                       
$arrayParent->removeChild($child);

                    } else {
                       
$child = $dom->createElement($node->tagName, (is_array($content) ? null : htmlspecialchars($content)));
                    }

                   
$arrayParent->appendChild($child);

                } else {

                   
$child = $dom->createElement($name, (is_array($content) ? null : htmlspecialchars($content)));
                   
$node->appendChild($child);
                }
               
                if (
is_array($content)) {
                   
self::putChildren($dom, $content, $child);
                }
            }
        }
    }



    function
xmlToArray ($xmldata) {

       
$parser = xml_parser_create ('ISO-8859-1');
// $parser = xml_parser_create ('UTF-8');
       
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
       
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, $this->foldCase);

       
$vals = array();
        if (!
xml_parse_into_struct ($parser, $xmldata, $vals)) {
            throw new
Exception(sprintf("XML error: %s at line %d",
                           
xml_error_string(xml_get_error_code($parser)),
                           
xml_get_current_line_number($parser))); }
       
$folding = xml_parser_get_option($parser, XML_OPTION_CASE_FOLDING);
       
xml_parser_free ($parser);

       
$this->vals = $vals;

        if (
$folding) {
           
$this->valueArrayName = strtoupper($this->valueArrayName);
           
$this->attributesArrayName = strtoupper($this->attributesArrayName);
        }

       
// Trim attributes and values if option set.

       
if ($this->trimText) {
            foreach(
$vals as &$val) {
                if (
count($val['attributes']) > 0) {
                    foreach(
$val['attributes'] as $name => $att) {
                        if (
$this->trimText) $val['attributes'][$name] = trim($att);
                    }
                }
                if (isset(
$val['value'])) {
                    if (
$this->trimText) $val['value'] = trim($val['value']);
                }
            }
        }

       
$i = 0;
       
$children = $this->getChildren ($vals, $i, $vals[$i]['type']);

       
// Add value and attributes to if present.

       
$valatt = $this->addAttributesAndValue($vals, 0);
        if (! empty(
$valatt)) $children = array_merge($valatt, $children);

       
$result [$vals [$i]['tag']] = $children;
        return
$result;
    }


   
/*
     * Called recursively to parse the vals array.
     */
   
private function getChildren ($vals, &$i, $type) {

       
// If the type is 'complete' it means that there are no children of this element.

       
$children = array ();

        if (
$type != 'complete') {

            while (
$vals [++$i]['type'] != 'close') {
               
$type = $vals [$i]['type'];
               
$tag = $vals [$i]['tag'];

               
$valatt = $this->addAttributesAndValue($vals, $i);

               
// Check if we already have an element with this name and need to create an array

               
if (isset ($children [$tag])) {

                   
$temp = array_keys ($children [$tag]);

                    if (
is_string ($temp [0])) {
                       
$a = $children [$tag];
                        unset (
$children [$tag]);
                       
$children [$tag][0] = $a;
                    }

                   
$child = $this->getChildren($vals, $i, $type);
                    if (! empty(
$valatt)) $child = array_merge($valatt, $child);
                   
$children [$tag][] = $child;

                } else {

                   
$children [$tag] = $this->getChildren ($vals, $i, $type);

                   
// If a scalar is returned from addAttributeAndValue just set that as the return
                    // otherwise merge it with the existing children.

                   
if (! is_array($valatt)) {
                       
$children[$tag] = $valatt;
                    } else {
                        if (! empty(
$valatt)) $children[$tag] = array_merge($valatt, $children[$tag]);
                    }
                }
            }
        }

        return
$children;
    }

   
/**
     * Add any attributes or values from parser to the output array.
     *
     * @param array $vals Parser vals.
     * @param int $i Nesting level.
     * @return array.
     */
   
private function addAttributesAndValue($vals, $i) {

       
$array = array();
        if (
$this->noAttributes) {
            if (isset (
$vals[$i]['value'])) $array = $vals [$i]['value'];

        } else {
            if (isset (
$vals[$i]['value'])) $array = array($this->valueArrayName => $vals [$i]['value']);
            if (isset (
$vals[$i]['attributes']))
               
$array = array_merge($array, array($this->attributesArrayName => $vals[$i]['attributes']));
        }
        return
$array;
    }

   
/**
     * Provides access to the parser's vals array.
     * @return array of parser vals
     */
   
function getParserVals() {
        return
$this->vals;
    }

   
/**
     * If true then values are returned as raw values instead of as a 'VALUE' array.
     * Also attributes are ignored.
     * @param boolean $switch
     */
   
function setNoAttributes($switch) {
       
$this->noAttributes = $switch;
    }

   
/**
     * Set case folding (uppercasing) of all returned array names.
     * This includes any value and attribute arrays.
     * @param boolean $switch
     */
   
function setCaseFolding($switch) {
       
$this->foldCase = $switch;
    }

   
/**
     * If set, trims leading and trailing white space from attribute value and value text.
     * @param boolean $switch
     */
   
function setTrimText($switch) {
       
$this->trimText = $switch;
    }
}
?>