diff e2gallerypro/php/xmlparse.v5.php @ 3:3f6b44aa6b35 judyates

[svn r4] added ability to buy stuff, from a Prints page, but it doesn't work well with the css, and it also has not been fitted into the perl make system.
author rlm
date Mon, 22 Feb 2010 08:02:39 -0500
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/e2gallerypro/php/xmlparse.v5.php	Mon Feb 22 08:02:39 2010 -0500
     1.3 @@ -0,0 +1,430 @@
     1.4 +<?php
     1.5 +/**
     1.6 +    This program is free software; you can redistribute it and/or modify
     1.7 +    it under the terms of the GNU General Public License as published by
     1.8 +    the Free Software Foundation; either version 2 of the License, or
     1.9 +    (at your option) any later version.
    1.10 +
    1.11 +    This program is distributed in the hope that it will be useful,
    1.12 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.13 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.14 +    GNU General Public License for more details.
    1.15 +
    1.16 +    For support, please visit http://www.criticaldevelopment.net/xml/
    1.17 +*/
    1.18 +
    1.19 +/**
    1.20 + * XML Parser Class (php5)
    1.21 + * 
    1.22 + * Parses an XML document into an object structure much like the SimpleXML extension.
    1.23 + *
    1.24 + * @author Adam A. Flynn <adamaflynn@criticaldevelopment.net>
    1.25 + * @copyright Copyright (c) 2005-2007, Adam A. Flynn
    1.26 + *
    1.27 + * @version 1.3.0
    1.28 + */
    1.29 +class XMLParser 
    1.30 +{
    1.31 +    /**
    1.32 +     * The XML parser
    1.33 +     *
    1.34 +     * @var resource
    1.35 +     */
    1.36 +    private $parser;
    1.37 +
    1.38 +    /**
    1.39 +    * The XML document
    1.40 +    *
    1.41 +    * @var string
    1.42 +    */
    1.43 +    private $xml;
    1.44 +
    1.45 +    /**
    1.46 +    * Document tag
    1.47 +    *
    1.48 +    * @var object
    1.49 +    */
    1.50 +    public $document;
    1.51 +
    1.52 +    /**
    1.53 +    * Current object depth
    1.54 +    *
    1.55 +    * @var array
    1.56 +    */
    1.57 +    private $stack;
    1.58 +    
    1.59 +    /**
    1.60 +     * Whether or not to replace dashes and colons in tag
    1.61 +     * names with underscores.
    1.62 +     * 
    1.63 +     * @var bool
    1.64 +     */
    1.65 +    private $cleanTagNames;
    1.66 +
    1.67 +    
    1.68 +    /**
    1.69 +     * Constructor. Loads XML document.
    1.70 +     *
    1.71 +     * @param string $xml The string of the XML document
    1.72 +     * @return XMLParser
    1.73 +     */
    1.74 +    function __construct($xml = '', $cleanTagNames = true)
    1.75 +    {
    1.76 +        //Load XML document
    1.77 +        $this->xml = $xml;
    1.78 +
    1.79 +        //Set stack to an array
    1.80 +        $this->stack = array();
    1.81 +        
    1.82 +        //Set whether or not to clean tag names
    1.83 +        $this->cleanTagNames = $cleanTagNames;
    1.84 +    }
    1.85 +
    1.86 +    /**
    1.87 +     * Initiates and runs PHP's XML parser
    1.88 +     */
    1.89 +    public function Parse()
    1.90 +    {
    1.91 +        //Create the parser resource
    1.92 +        $this->parser = xml_parser_create();
    1.93 +        
    1.94 +        //Set the handlers
    1.95 +        xml_set_object($this->parser, $this);
    1.96 +        xml_set_element_handler($this->parser, 'StartElement', 'EndElement');
    1.97 +        xml_set_character_data_handler($this->parser, 'CharacterData');
    1.98 +
    1.99 +        //Error handling
   1.100 +        if (!xml_parse($this->parser, $this->xml))
   1.101 +            $this->HandleError(xml_get_error_code($this->parser), xml_get_current_line_number($this->parser), xml_get_current_column_number($this->parser));
   1.102 +
   1.103 +        //Free the parser
   1.104 +        xml_parser_free($this->parser);
   1.105 +    }
   1.106 +    
   1.107 +    /**
   1.108 +     * Handles an XML parsing error
   1.109 +     *
   1.110 +     * @param int $code XML Error Code
   1.111 +     * @param int $line Line on which the error happened
   1.112 +     * @param int $col Column on which the error happened
   1.113 +     */
   1.114 +    private function HandleError($code, $line, $col)
   1.115 +    {
   1.116 +        trigger_error('XML Parsing Error at '.$line.':'.$col.'. Error '.$code.': '.xml_error_string($code));
   1.117 +    }
   1.118 +
   1.119 +    
   1.120 +    /**
   1.121 +     * Gets the XML output of the PHP structure within $this->document
   1.122 +     *
   1.123 +     * @return string
   1.124 +     */
   1.125 +    public function GenerateXML()
   1.126 +    {
   1.127 +        return $this->document->GetXML();
   1.128 +    }
   1.129 +
   1.130 +    /**
   1.131 +     * Gets the reference to the current direct parent
   1.132 +     *
   1.133 +     * @return object
   1.134 +     */
   1.135 +    private function GetStackLocation()
   1.136 +    {
   1.137 +        //Returns the reference to the current direct parent
   1.138 +        return end($this->stack);
   1.139 +    }
   1.140 +
   1.141 +    /**
   1.142 +     * Handler function for the start of a tag
   1.143 +     *
   1.144 +     * @param resource $parser
   1.145 +     * @param string $name
   1.146 +     * @param array $attrs
   1.147 +     */
   1.148 +    private function StartElement($parser, $name, $attrs = array())
   1.149 +    {
   1.150 +        //Make the name of the tag lower case
   1.151 +        $name = strtolower($name);
   1.152 +        
   1.153 +        //Check to see if tag is root-level
   1.154 +        if (count($this->stack) == 0) 
   1.155 +        {
   1.156 +            //If so, set the document as the current tag
   1.157 +            $this->document = new XMLTag($name, $attrs);
   1.158 +
   1.159 +            //And start out the stack with the document tag
   1.160 +            $this->stack = array(&$this->document);
   1.161 +        }
   1.162 +        //If it isn't root level, use the stack to find the parent
   1.163 +        else
   1.164 +        {
   1.165 +            //Get the reference to the current direct parent
   1.166 +            $parent = $this->GetStackLocation();
   1.167 +            
   1.168 +            $parent->AddChild($name, $attrs, count($this->stack), $this->cleanTagNames);
   1.169 +
   1.170 +            //If the cleanTagName feature is on, clean the tag names
   1.171 +            if($this->cleanTagNames)
   1.172 +                $name = str_replace(array(':', '-'), '_', $name);
   1.173 +
   1.174 +            //Update the stack
   1.175 +            $this->stack[] = end($parent->$name);        
   1.176 +        }
   1.177 +    }
   1.178 +
   1.179 +    /**
   1.180 +     * Handler function for the end of a tag
   1.181 +     *
   1.182 +     * @param resource $parser
   1.183 +     * @param string $name
   1.184 +     */
   1.185 +    private function EndElement($parser, $name)
   1.186 +    {
   1.187 +        //Update stack by removing the end value from it as the parent
   1.188 +        array_pop($this->stack);
   1.189 +    }
   1.190 +
   1.191 +    /**
   1.192 +     * Handler function for the character data within a tag
   1.193 +     *
   1.194 +     * @param resource $parser
   1.195 +     * @param string $data
   1.196 +     */
   1.197 +    private function CharacterData($parser, $data)
   1.198 +    {
   1.199 +        //Get the reference to the current parent object
   1.200 +        $tag = $this->GetStackLocation();
   1.201 +
   1.202 +        //Assign data to it
   1.203 +        $tag->tagData .= trim($data);
   1.204 +    }
   1.205 +}
   1.206 +
   1.207 +
   1.208 +/**
   1.209 + * XML Tag Object (php5)
   1.210 + * 
   1.211 + * This object stores all of the direct children of itself in the $children array. They are also stored by
   1.212 + * type as arrays. So, if, for example, this tag had 2 <font> tags as children, there would be a class member
   1.213 + * called $font created as an array. $font[0] would be the first font tag, and $font[1] would be the second.
   1.214 + * 
   1.215 + * To loop through all of the direct children of this object, the $children member should be used.
   1.216 + *
   1.217 + * To loop through all of the direct children of a specific tag for this object, it is probably easier 
   1.218 + * to use the arrays of the specific tag names, as explained above.
   1.219 + * 
   1.220 + * @author Adam A. Flynn <adamaflynn@criticaldevelopment.net>
   1.221 + * @copyright Copyright (c) 2005-2007, Adam A. Flynn
   1.222 + *
   1.223 + * @version 1.3.0
   1.224 + */
   1.225 +class XMLTag
   1.226 +{
   1.227 +    /**
   1.228 +     * Array with the attributes of this XML tag
   1.229 +     *
   1.230 +     * @var array
   1.231 +     */
   1.232 +    public $tagAttrs;
   1.233 +    
   1.234 +    /**
   1.235 +     * The name of the tag
   1.236 +     *
   1.237 +     * @var string
   1.238 +     */
   1.239 +    public $tagName;
   1.240 +    
   1.241 +    /**
   1.242 +     * The data the tag contains 
   1.243 +     * 
   1.244 +     * So, if the tag doesn't contain child tags, and just contains a string, it would go here
   1.245 +     *
   1.246 +     * @var stat
   1.247 +     */
   1.248 +    public $tagData;
   1.249 +    
   1.250 +    /**
   1.251 +     * Array of references to the objects of all direct children of this XML object
   1.252 +     *
   1.253 +     * @var array
   1.254 +     */
   1.255 +    public $tagChildren;
   1.256 +    
   1.257 +    /**
   1.258 +     * The number of parents this XML object has (number of levels from this tag to the root tag)
   1.259 +     *
   1.260 +     * Used presently only to set the number of tabs when outputting XML
   1.261 +     *
   1.262 +     * @var int
   1.263 +     */
   1.264 +    public $tagParents;
   1.265 +    
   1.266 +    /**
   1.267 +     * Constructor, sets up all the default values
   1.268 +     *
   1.269 +     * @param string $name
   1.270 +     * @param array $attrs
   1.271 +     * @param int $parents
   1.272 +     * @return XMLTag
   1.273 +     */
   1.274 +    function __construct($name, $attrs = array(), $parents = 0)
   1.275 +    {
   1.276 +        //Make the keys of the attr array lower case, and store the value
   1.277 +        $this->tagAttrs = array_change_key_case($attrs, CASE_LOWER);
   1.278 +        
   1.279 +        //Make the name lower case and store the value
   1.280 +        $this->tagName = strtolower($name);
   1.281 +        
   1.282 +        //Set the number of parents
   1.283 +        $this->tagParents = $parents;
   1.284 +        
   1.285 +        //Set the types for children and data
   1.286 +        $this->tagChildren = array();
   1.287 +        $this->tagData = '';
   1.288 +    }
   1.289 +    
   1.290 +    /**
   1.291 +     * Adds a direct child to this object
   1.292 +     *
   1.293 +     * @param string $name
   1.294 +     * @param array $attrs
   1.295 +     * @param int $parents
   1.296 +     * @param bool $cleanTagName
   1.297 +     */
   1.298 +    public function AddChild($name, $attrs, $parents, $cleanTagName = true)
   1.299 +    {    
   1.300 +        //If the tag is a reserved name, output an error
   1.301 +        if(in_array($name, array('tagChildren', 'tagAttrs', 'tagParents', 'tagData', 'tagName')))
   1.302 +        {
   1.303 +            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);
   1.304 +
   1.305 +            return;
   1.306 +        }
   1.307 +
   1.308 +        //Create the child object itself
   1.309 +        $child = new XMLTag($name, $attrs, $parents);
   1.310 +
   1.311 +        //If the cleanTagName feature is on, replace colons and dashes with underscores
   1.312 +        if($cleanTagName)
   1.313 +            $name = str_replace(array(':', '-'), '_', $name);
   1.314 +        
   1.315 +        //Toss up a notice if someone's trying to to use a colon or dash in a tag name
   1.316 +        elseif(strstr($name, ':') || strstr($name, '-'))
   1.317 +            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, you may have difficulty accessing them. You might want to think about enabling the cleanTagName feature (pass true as the second argument of the XMLParser constructor). For more details, see http://www.criticaldevelopment.net/xml/', E_USER_NOTICE);
   1.318 +        
   1.319 +        //If there is no array already set for the tag name being added, 
   1.320 +        //create an empty array for it
   1.321 +        if(!isset($this->$name))
   1.322 +            $this->$name = array();
   1.323 +        
   1.324 +        //Add the reference of it to the end of an array member named for the tag's name
   1.325 +        $this->{$name}[] = &$child;
   1.326 +        
   1.327 +        //Add the reference to the children array member
   1.328 +        $this->tagChildren[] = &$child;
   1.329 +        
   1.330 +        //Return a reference to this object for the stack
   1.331 +        return $this;
   1.332 +    }
   1.333 +    
   1.334 +    /**
   1.335 +     * Returns the string of the XML document which would be generated from this object
   1.336 +     * 
   1.337 +     * This function works recursively, so it gets the XML of itself and all of its children, which
   1.338 +     * in turn gets the XML of all their children, which in turn gets the XML of all thier children,
   1.339 +     * and so on. So, if you call GetXML from the document root object, it will return a string for 
   1.340 +     * the XML of the entire document.
   1.341 +     * 
   1.342 +     * This function does not, however, return a DTD or an XML version/encoding tag. That should be
   1.343 +     * handled by XMLParser::GetXML()
   1.344 +     *
   1.345 +     * @return string
   1.346 +     */
   1.347 +    public function GetXML()
   1.348 +    {
   1.349 +        //Start a new line, indent by the number indicated in $this->parents, add a <, and add the name of the tag
   1.350 +        $out = "\n".str_repeat("\t", $this->tagParents).'<'.$this->tagName;
   1.351 +
   1.352 +        //For each attribute, add attr="value"
   1.353 +        foreach($this->tagAttrs as $attr => $value)
   1.354 +            $out .= ' '.$attr.'="'.$value.'"';
   1.355 +        
   1.356 +        //If there are no children and it contains no data, end it off with a />
   1.357 +        if(empty($this->tagChildren) && empty($this->tagData))
   1.358 +            $out .= " />";
   1.359 +        
   1.360 +        //Otherwise...
   1.361 +        else
   1.362 +        {    
   1.363 +            //If there are children
   1.364 +            if(!empty($this->tagChildren))
   1.365 +            {
   1.366 +                //Close off the start tag
   1.367 +                $out .= '>';
   1.368 +                
   1.369 +                //For each child, call the GetXML function (this will ensure that all children are added recursively)
   1.370 +                foreach($this->tagChildren as $child)
   1.371 +                    $out .= $child->GetXML();
   1.372 +
   1.373 +                //Add the newline and indentation to go along with the close tag
   1.374 +                $out .= "\n".str_repeat("\t", $this->tagParents);
   1.375 +            }
   1.376 +            
   1.377 +            //If there is data, close off the start tag and add the data
   1.378 +            elseif(!empty($this->tagData))
   1.379 +                $out .= '>'.$this->tagData;
   1.380 +            
   1.381 +            //Add the end tag    
   1.382 +            $out .= '</'.$this->tagName.'>';
   1.383 +        }
   1.384 +        
   1.385 +        //Return the final output
   1.386 +        return $out;
   1.387 +    }
   1.388 +    
   1.389 +    /**
   1.390 +     * Deletes this tag's child with a name of $childName and an index
   1.391 +     * of $childIndex
   1.392 +     *
   1.393 +     * @param string $childName
   1.394 +     * @param int $childIndex
   1.395 +     */
   1.396 +    public function Delete($childName, $childIndex = 0)
   1.397 +    {
   1.398 +        //Delete all of the children of that child
   1.399 +        $this->{$childName}[$childIndex]->DeleteChildren();
   1.400 +        
   1.401 +        //Destroy the child's value
   1.402 +        $this->{$childName}[$childIndex] = null;
   1.403 +        
   1.404 +        //Remove the child's name from the named array
   1.405 +        unset($this->{$childName}[$childIndex]);
   1.406 +        
   1.407 +        //Loop through the tagChildren array and remove any null
   1.408 +        //values left behind from the above operation
   1.409 +        for($x = 0; $x < count($this->tagChildren); $x ++)
   1.410 +        {
   1.411 +            if(is_null($this->tagChildren[$x]))
   1.412 +                unset($this->tagChildren[$x]);
   1.413 +        }
   1.414 +    }
   1.415 +    
   1.416 +    /**
   1.417 +     * Removes all of the children of this tag in both name and value
   1.418 +     */
   1.419 +    private function DeleteChildren()
   1.420 +    {
   1.421 +        //Loop through all child tags
   1.422 +        for($x = 0; $x < count($this->tagChildren); $x ++)
   1.423 +        {
   1.424 +            //Do this recursively
   1.425 +            $this->tagChildren[$x]->DeleteChildren();
   1.426 +            
   1.427 +            //Delete the name and value
   1.428 +            $this->tagChildren[$x] = null;
   1.429 +            unset($this->tagChildren[$x]);
   1.430 +        }
   1.431 +    }
   1.432 +}
   1.433 +?>
   1.434 \ No newline at end of file