Mercurial > judyates
view e2gallerypro/php/xmlparse.v4.php @ 17:46fdf059b154 judyates
preparing to add google analytics
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 11 Jul 2011 02:43:59 -0400 |
parents | 3f6b44aa6b35 |
children |
line wrap: on
line source
1 <?php2 /**3 This program is free software; you can redistribute it and/or modify4 it under the terms of the GNU General Public License as published by5 the Free Software Foundation; either version 2 of the License, or6 (at your option) any later version.8 This program is distributed in the hope that it will be useful,9 but WITHOUT ANY WARRANTY; without even the implied warranty of10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11 GNU General Public License for more details.13 For Support, please visit http://www.criticaldevelopment.net/xml/14 */16 /**17 * XML Parser Class (php4)18 *19 * Parses an XML document into an object structure much like the SimpleXML extension.20 *21 * @author Adam A. Flynn <adamaflynn@criticaldevelopment.net>22 * @copyright Copyright (c) 2005-2007, Adam A. Flynn23 *24 * @version 1.3.025 */26 class XMLParser27 {28 /**29 * The XML parser30 *31 * @var resource32 */33 var $parser;35 /**36 * The XML document37 *38 * @var string39 */40 var $xml;42 /**43 * Document tag44 *45 * @var object46 */47 var $document;49 /**50 * Current object depth51 *52 * @var array53 */54 var $stack;55 /**56 * Whether or not to replace dashes and colons in tag57 * names with underscores.58 *59 * @var bool60 */61 var $cleanTagNames;64 /**65 * Constructor. Loads XML document.66 *67 * @param string $xml The string of the XML document68 * @return XMLParser69 */70 function XMLParser($xml = '', $cleanTagNames = true)71 {72 //Load XML document73 $this->xml = $xml;75 // Set stack to an array76 $this->stack = array();78 //Set whether or not to clean tag names79 $this->cleanTagNames = $cleanTagNames;80 }82 /**83 * Initiates and runs PHP's XML parser84 */85 function Parse()86 {87 //Create the parser resource88 $this->parser = xml_parser_create();90 //Set the handlers91 xml_set_object($this->parser, $this);92 xml_set_element_handler($this->parser, 'StartElement', 'EndElement');93 xml_set_character_data_handler($this->parser, 'CharacterData');95 //Error handling96 if (!xml_parse($this->parser, $this->xml))97 $this->HandleError(xml_get_error_code($this->parser), xml_get_current_line_number($this->parser), xml_get_current_column_number($this->parser));99 //Free the parser100 xml_parser_free($this->parser);101 }103 /**104 * Handles an XML parsing error105 *106 * @param int $code XML Error Code107 * @param int $line Line on which the error happened108 * @param int $col Column on which the error happened109 */110 function HandleError($code, $line, $col)111 {112 trigger_error('XML Parsing Error at '.$line.':'.$col.'. Error '.$code.': '.xml_error_string($code));113 }116 /**117 * Gets the XML output of the PHP structure within $this->document118 *119 * @return string120 */121 function GenerateXML()122 {123 return $this->document->GetXML();124 }126 /**127 * Gets the reference to the current direct parent128 *129 * @return object130 */131 function GetStackLocation()132 {133 $return = '';135 foreach($this->stack as $stack)136 $return .= $stack.'->';138 return rtrim($return, '->');139 }141 /**142 * Handler function for the start of a tag143 *144 * @param resource $parser145 * @param string $name146 * @param array $attrs147 */148 function StartElement($parser, $name, $attrs = array())149 {150 //Make the name of the tag lower case151 $name = strtolower($name);153 //Check to see if tag is root-level154 if (count($this->stack) == 0)155 {156 //If so, set the document as the current tag157 $this->document = new XMLTag($name, $attrs);159 //And start out the stack with the document tag160 $this->stack = array('document');161 }162 //If it isn't root level, use the stack to find the parent163 else164 {165 //Get the name which points to the current direct parent, relative to $this166 $parent = $this->GetStackLocation();168 //Add the child169 eval('$this->'.$parent.'->AddChild($name, $attrs, '.count($this->stack).', $this->cleanTagNames);');171 //If the cleanTagName feature is on, replace colons and dashes with underscores172 if($this->cleanTagNames)173 $name = str_replace(array(':', '-'), '_', $name);176 //Update the stack177 eval('$this->stack[] = $name.\'[\'.(count($this->'.$parent.'->'.$name.') - 1).\']\';');178 }179 }181 /**182 * Handler function for the end of a tag183 *184 * @param resource $parser185 * @param string $name186 */187 function EndElement($parser, $name)188 {189 //Update stack by removing the end value from it as the parent190 array_pop($this->stack);191 }193 /**194 * Handler function for the character data within a tag195 *196 * @param resource $parser197 * @param string $data198 */199 function CharacterData($parser, $data)200 {201 //Get the reference to the current parent object202 $tag = $this->GetStackLocation();204 //Assign data to it205 eval('$this->'.$tag.'->tagData .= trim($data);');206 }207 }210 /**211 * XML Tag Object (php4)212 *213 * This object stores all of the direct children of itself in the $children array. They are also stored by214 * type as arrays. So, if, for example, this tag had 2 <font> tags as children, there would be a class member215 * called $font created as an array. $font[0] would be the first font tag, and $font[1] would be the second.216 *217 * To loop through all of the direct children of this object, the $children member should be used.218 *219 * To loop through all of the direct children of a specific tag for this object, it is probably easier220 * to use the arrays of the specific tag names, as explained above.221 *222 * @author Adam A. Flynn <adamaflynn@criticaldevelopment.net>223 * @copyright Copyright (c) 2005-2007, Adam A. Flynn224 *225 * @version 1.3.0226 */227 class XMLTag228 {229 /**230 * Array with the attributes of this XML tag231 *232 * @var array233 */234 var $tagAttrs;236 /**237 * The name of the tag238 *239 * @var string240 */241 var $tagName;243 /**244 * The data the tag contains245 *246 * So, if the tag doesn't contain child tags, and just contains a string, it would go here247 *248 * @var string249 */250 var $tagData;252 /**253 * Array of references to the objects of all direct children of this XML object254 *255 * @var array256 */257 var $tagChildren;259 /**260 * The number of parents this XML object has (number of levels from this tag to the root tag)261 *262 * Used presently only to set the number of tabs when outputting XML263 *264 * @var int265 */266 var $tagParents;268 /**269 * Constructor, sets up all the default values270 *271 * @param string $name272 * @param array $attrs273 * @param int $parents274 * @return XMLTag275 */276 function XMLTag($name, $attrs = array(), $parents = 0)277 {278 //Make the keys of the attr array lower case, and store the value279 $this->tagAttrs = array_change_key_case($attrs, CASE_LOWER);281 //Make the name lower case and store the value282 $this->tagName = strtolower($name);284 //Set the number of parents285 $this->tagParents = $parents;287 //Set the types for children and data288 $this->tagChildren = array();289 $this->tagData = '';290 }292 /**293 * Adds a direct child to this object294 *295 * @param string $name296 * @param array $attrs297 * @param int $parents298 * @param bool $cleanTagName299 */300 function AddChild($name, $attrs, $parents, $cleanTagName = true)301 {302 //If the tag is a reserved name, output an error303 if(in_array($name, array('tagChildren', 'tagAttrs', 'tagParents', 'tagData', 'tagName')))304 {305 trigger_error('You have used a reserved name as the name of an XML tag. Please consult the documentation (http://www.criticaldevelopment.net/xml/) and rename the tag named "'.$name.'" to something other than a reserved name.', E_USER_ERROR);307 return;308 }310 //Create the child object itself311 $child = new XMLTag($name, $attrs, $parents);313 //If the cleanTagName feature is on, replace colons and dashes with underscores314 if($cleanTagName)315 $name = str_replace(array(':', '-'), '_', $name);317 //Toss up a notice if someone's trying to to use a colon or dash in a tag name318 elseif(strstr($name, ':') || strstr($name, '-'))319 trigger_error('Your tag named "'.$name.'" contains either a dash or a colon. Neither of these characters are friendly with PHP variable names, and, as such, they cannot be accessed and will cause the parser to not work. You must enable the cleanTagName feature (pass true as the second argument of the XMLParser constructor). For more details, see http://www.criticaldevelopment.net/xml/', E_USER_ERROR);321 //If there is no array already set for the tag name being added,322 //create an empty array for it323 if(!isset($this->$name))324 $this->$name = array();326 //Add the reference of it to the end of an array member named for the tag's name327 $this->{$name}[] =& $child;329 //Add the reference to the children array member330 $this->tagChildren[] =& $child;331 }333 /**334 * Returns the string of the XML document which would be generated from this object335 *336 * This function works recursively, so it gets the XML of itself and all of its children, which337 * in turn gets the XML of all their children, which in turn gets the XML of all thier children,338 * and so on. So, if you call GetXML from the document root object, it will return a string for339 * the XML of the entire document.340 *341 * This function does not, however, return a DTD or an XML version/encoding tag. That should be342 * handled by XMLParser::GetXML()343 *344 * @return string345 */346 function GetXML()347 {348 //Start a new line, indent by the number indicated in $this->parents, add a <, and add the name of the tag349 $out = "\n".str_repeat("\t", $this->tagParents).'<'.$this->tagName;351 //For each attribute, add attr="value"352 foreach($this->tagAttrs as $attr => $value)353 $out .= ' '.$attr.'="'.$value.'"';355 //If there are no children and it contains no data, end it off with a />356 if(empty($this->tagChildren) && empty($this->tagData))357 $out .= " />";359 //Otherwise...360 else361 {362 //If there are children363 if(!empty($this->tagChildren))364 {365 //Close off the start tag366 $out .= '>';368 //For each child, call the GetXML function (this will ensure that all children are added recursively)369 foreach($this->tagChildren as $child)370 {371 if(is_object($child))372 $out .= $child->GetXML();373 }375 //Add the newline and indentation to go along with the close tag376 $out .= "\n".str_repeat("\t", $this->tagParents);377 }379 //If there is data, close off the start tag and add the data380 elseif(!empty($this->tagData))381 $out .= '>'.$this->tagData;383 //Add the end tag384 $out .= '</'.$this->tagName.'>';385 }387 //Return the final output388 return $out;389 }391 /**392 * Deletes this tag's child with a name of $childName and an index393 * of $childIndex394 *395 * @param string $childName396 * @param int $childIndex397 */398 function Delete($childName, $childIndex = 0)399 {400 //Delete all of the children of that child401 $this->{$childName}[$childIndex]->DeleteChildren();403 //Destroy the child's value404 $this->{$childName}[$childIndex] = null;406 //Remove the child's name from the named array407 unset($this->{$childName}[$childIndex]);409 //Loop through the tagChildren array and remove any null410 //values left behind from the above operation411 for($x = 0; $x < count($this->tagChildren); $x ++)412 {413 if(is_null($this->tagChildren[$x]))414 unset($this->tagChildren[$x]);415 }416 }418 /**419 * Removes all of the children of this tag in both name and value420 */421 function DeleteChildren()422 {423 //Loop through all child tags424 for($x = 0; $x < count($this->tagChildren); $x ++)425 {426 //Do this recursively427 $this->tagChildren[$x]->DeleteChildren();429 //Delete the name and value430 $this->tagChildren[$x] = null;431 unset($this->tagChildren[$x]);432 }433 }434 }435 ?>