1<?php 2 3// 4// Based on code found online at: 5// http://php.net/manual/en/function.xml-parse-into-struct.php 6// 7// Author: Eric Pollmann 8// Released into public domain September 2003 9// http://eric.pollmann.net/work/public_domain/ 10// 2006-12-22, 2007-02-09: Patch for PHP 5 compatibility to fix handling 11// of tags with no properties, thanks to Jan De Luyck and 12// John McGuire (JDL + JM) 13// 2007-02-10: Preserve parent tag name if unclosed tag is present (EP) 14 15class XMLParser { 16 var $data; // Input XML data buffer 17 var $vals; // Struct created by xml_parse_into_struct 18 var $collapse_dups; // If there is only one tag of a given name, 19 // shall we store as scalar or array? 20 var $index_numeric; // Index tags by numeric position, not name. 21 // useful for ordered XML like CallXML. 22 23 // Read in XML on object creation. 24 // We can take raw XML data, a stream, a filename, or a url. 25 function XMLParser($data_source, $data_source_type='raw', $collapse_dups=0, $index_numeric=0) { 26 $this->collapse_dups = $collapse_dups; 27 $this->index_numeric = $index_numeric; 28 $this->data = ''; 29 if ($data_source_type == 'raw') 30 $this->data = $data_source; 31 32 elseif ($data_source_type == 'stream') { 33 while (!feof($data_source)) 34 $this->data .= fread($data_source, 1000); 35 36 // try filename, then if that fails... 37 } elseif (file_exists($data_source)) 38 $this->data = implode('', file($data_source)); 39 40 // try url 41 else { 42 $fp = fopen($data_source,'r'); 43 while (!feof($fp)) 44 $this->data .= fread($fp, 1000); 45 fclose($fp); 46 } 47 } 48 49 // Parse the XML file into a verbose, flat array struct. 50 // Then, coerce that into a simple nested array. 51 function getTree() { 52 $parser = xml_parser_create('UTF-8'); 53 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 54 xml_parse_into_struct($parser, $this->data, $vals, $index); 55 xml_parser_free($parser); 56 57 $i = -1; 58 return $this->getchildren($vals, $i); 59 } 60 61 // internal function: build a node of the tree 62 function buildtag($thisvals, $vals, &$i, $type) { 63 // JDL + JM: PHP 5 requires initialization 64 $tag = array(); 65 66 if (isset($thisvals['attributes'])) 67 $tag['ATTRIBUTES'] = $thisvals['attributes']; 68 69 // complete tag, just return it for storage in array 70 if ($type === 'complete') 71 $tag['VALUE'] = $thisvals['value']; 72 73 // open tag, recurse 74 else 75 $tag = array_merge($tag, $this->getchildren($vals, $i)); 76 77 return $tag; 78 } 79 80 // internal function: build an nested array representing children 81 function getchildren($vals, &$i) { 82 $children = array(); // Contains node data 83 84 // Node has CDATA before it's children 85 if ($i > -1 && isset($vals[$i]['value'])) 86 $children['VALUE'] = $vals[$i]['value']; 87 88 // Loop through children, until hit close tag or run out of tags 89 while (++$i < count($vals)) { 90 91 $type = $vals[$i]['type']; 92 93 // 'cdata': Node has CDATA after one of it's children 94 // (Add to cdata found before in this case) 95 if ($type === 'cdata') 96 $children['VALUE'] .= $vals[$i]['value']; 97 98 // 'complete': At end of current branch 99 // 'open': Node has children, recurse 100 elseif ($type === 'complete' || $type === 'open') { 101 // EP: Preserve parent tag name 102 $name = $vals[$i]['tag']; 103 $tag = $this->buildtag($vals[$i], $vals, $i, $type); 104 if ($this->index_numeric) { 105 $tag['TAG'] = $name; 106 $children[] = $tag; 107 } else 108 $children[$name][] = $tag; 109 } 110 111 // 'close: End of node, return collected data 112 // Do not increment $i or nodes disappear! 113 elseif ($type === 'close') 114 break; 115 } 116 if ($this->collapse_dups) 117 foreach($children as $key => $value) 118 if (is_array($value) && (count($value) == 1)) 119 $children[$key] = $value[0]; 120 return $children; 121 } 122} 123?> 124