| 
<?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;
 }
 }
 ?>
 
 |