1   <?php
  2  
  3   class xml_doc {
  4           var $parser;                    // Object Reference to parser
  5           var $xml;                               // Raw XML code
  6           var $version;                   // XML Version
  7           var $encoding;                  // Encoding type
  8           var $dtd;                               // DTD Information
  9           var $entities;                  // Array (key/value set) of entities
  10           var $xml_index;                 // Array of object references to XML tags in a DOC
  11           var $xml_reference;             // Next available Reference ID for index
  12           var $document;                  // Document tag (type: xml_tag)
  13           var $stack;                     // Current object depth (array of index numbers)
  14  
  15           function xml_doc($xml='') {
  16                   // XML Document constructor
  17  
  18  
  19                   $this->xml = $xml;
  20  
  21                   // Set default values
  22                   $this->version = '1.0';
  23                   $this->encoding = "ISO-8859-1";
  24                   $this->dtd = '';
  25                   $this->entities = array();
  26                   $this->xml_index = array();
  27                   $this->xml_reference = 0;
  28                   $this->stack = array();
  29           }
  30  
  31           function parse() {
  32                   // Creates the object tree from XML code
  33  
  34  
  35                   $this->parser = xml_parser_create($this->encoding);
  36                   xml_set_object($this->parser, $this);
  37                   xml_set_element_handler($this->parser, "startElement", "endElement");
  38                   xml_set_character_data_handler($this->parser, "characterData");
  39                   xml_set_default_handler($this->parser, "defaultHandler");
  40  
  41                   if (!xml_parse($this->parser, $this->xml)) {
  42                           // Error while parsing document
  43  
  44                           $err_code = xml_get_error_code();
  45                           $err_string = xml_get_error_string();
  46                           $err_line = xml_get_current_line_number();
  47                           $err_col = xml_get_current_column_number();
  48                           $err_byte = xml_get_current_byte_index();
  49  
  50                           print "<p><b>Error Code:</b> $err_code<br>$err_string<br><b>Line:</b> $err_line<br><b>Column: $err_col</p>";
  51                   }
  52  
  53                   xml_parser_free($this->parser);
  54           }
  55  
  56           function generate() {
  57                   // Generates XML string from the xml_doc::document object
  58  
  59  
  60                   // Create document header
  61                   if ($this->version == '' and $this->encoding == '') {
  62                           $out_header = '<' . '?xml ?' . ">\n";
  63                   } elseif ($this->version != '' and $this->encoding == '') {
  64                           $out_header = '<' . "?xml version=\"{$this->version}\"?" . ">\n";
  65                   } else {
  66                           $out_header = '<' . "?xml version=\"{$this->version}\" encoding=\"{$this->encoding}\"?" . ">\n";
  67                   }
  68  
  69                   if ($this->dtd != '') {
  70                           $out_header .= "<!DOCTYPE " . $this->dtd . ">\n";
  71                   }
  72  
  73                   // Get reference for root tag
  74                   $_root =& $this->xml_index[0];
  75  
  76                   // Create XML for root tag
  77                   $this->xml = $this->createXML(0);
  78  
  79                   return $out_header . $this->xml;
  80           }
  81  
  82           function stack_location() {
  83                   // Returns index for current working tag
  84  
  85  
  86                   return $this->stack[(count($this->stack) - 1)];
  87           }
  88  
  89           function startElement($parser, $name, $attrs=array()) {
  90                   // Process a new tag
  91  
  92  
  93                   // Check to see if tag is root-level
  94                   if (count($this->stack) == 0) {
  95                           // Tag is root-level (document)
  96  
  97                           $this->document = new xml_tag($this,$name,$attrs);
  98                           $this->document->refID = 0;
  99  
  100                           $this->xml_index[0] =& $this->document;
  101                           $this->xml_reference = 1;
  102  
  103                           $this->stack[0] = 0;
  104  
  105                   } else {
  106                           // Get current location in stack array
  107                           $parent_index = $this->stack_location();
  108  
  109                           // Get object reference to parent tag
  110                           $parent =& $this->xml_index[$parent_index];
  111  
  112                           // Add child to parent
  113                           $parent->addChild($this,$name,$attrs);
  114  
  115                           // Update stack
  116                           array_push($this->stack,($this->xml_reference - 1));
  117                   }
  118  
  119           }
  120  
  121           function endElement($parser, $name) {
  122                   // Update stack
  123  
  124  
  125                   array_pop($this->stack);
  126           }
  127  
  128           function characterData($parser, $data) {
  129                   // Add textual data to the current tag
  130  
  131  
  132                   // Get current location in stack array
  133                   $cur_index = $this->stack_location();
  134  
  135                   // Get object reference for tag
  136                   $tag =& $this->xml_index[$cur_index];
  137  
  138                   // Assign data to tag
  139                   $tag->contents = $data;
  140           }
  141  
  142           function defaultHandler($parser, $data) {
  143  
  144           }
  145  
  146           function createTag($name, $attrs=array(), $contents='', $parentID = '') {
  147                   // Creates an XML tag, returns Tag Index #
  148  
  149  
  150                   if ($parentID === '') {
  151                           // Tag is root-level
  152  
  153                           $this->document = new xml_tag($this,$name,$attrs,$contents);
  154                           $this->document->refID = 0;
  155  
  156                           $this->xml_index[0] =& $this->document;
  157                           $this->xml_reference = 1;
  158  
  159                           return 0;
  160                   } else {
  161                           // Tag is a child
  162  
  163                           // Get object reference to parent tag
  164                           $parent =& $this->xml_index[$parentID];
  165  
  166                           // Add child to parent
  167                           return $parent->addChild($this,$name,$attrs,$contents);
  168                   }
  169           }
  170  
  171  
  172           function createXML($tagID,$parentXML='') {
  173                   // Creates XML string for a tag object
  174                   // Specify parent XML to insert new string into parent XML
  175  
  176  
  177                   $final = '';
  178  
  179                   // Get Reference to tag object
  180                   $tag =& $this->xml_index[$tagID];
  181  
  182                   $name = $tag->name;
  183                   $contents = $tag->contents;
  184                   $attr_count = count($tag->attributes);
  185                   $child_count = count($tag->tags);
  186                   $empty_tag = ($tag->contents == '') ? true : false;
  187  
  188                   // Create intial tag
  189                   if ($attr_count == 0) {
  190                           // No attributes
  191  
  192                           if ($empty_tag === true) {
  193                                           $final = "<$name />";
  194                           } else {
  195                                           $final = "<$name>$contents</$name>";
  196                           }
  197                   } else {
  198                           // Attributes present
  199  
  200                           $attribs = '';
  201                           foreach ($tag->attributes as $key => $value) {
  202                                   $attribs .= ' ' . $key . "=\"$value\"";
  203                           }
  204  
  205                           if ($empty_tag === true) {
  206                                   $final = "<$name$attribs />\n";
  207                           } else {
  208                                   $final = "<$name$attribs>$contents</$name>\n";
  209                           }
  210                   }
  211  
  212                   // Search for children
  213                   if ($child_count > 0) {
  214                           foreach ($tag->tags as $childID) {
  215                                   $final = $this->createXML($childID,$final);
  216                           }
  217                   }
  218  
  219                   if ($parentXML != '') {
  220                           // Add tag XML to parent XML
  221  
  222                           $stop1 = strrpos($parentXML,'</');
  223                           $stop2 = strrpos($parentXML,' />');
  224  
  225                           if ($stop1 > $stop2) {
  226                                   // Parent already has children
  227  
  228                                   $begin_chunk = substr($parentXML,0,$stop1);
  229                                   $end_chunk = substr($parentXML,$stop1,(strlen($parentXML) - $stop1 + 1));
  230  
  231                                   $final = $begin_chunk . $final . $end_chunk;
  232                           } elseif ($stop2 > $stop1) {
  233                                   // No previous children
  234  
  235                                   $spc = strpos($parentXML,' ',0);
  236  
  237                                   $parent_name = substr($parentXML,1,$spc - 1);
  238  
  239                                   if ($spc != $stop2) {
  240                                           // Attributes present
  241                                           $parent_attribs = substr($parentXML,$spc,($stop2 - $spc));
  242                                   } else {
  243                                           // No attributes
  244                                           $parent_attribs = '';
  245                                   }
  246  
  247                                   $final = "<$parent_name$parent_attribs>$final</$parent_name>";
  248                           }
  249                   }
  250  
  251                   return $final;
  252           }
  253  
  254  
  255           function getTag($tagID,&$name,&$attributes,&$contents,&$tags) {
  256                   // Returns tag information via variable references from a tag index#
  257  
  258  
  259                   // Get object reference for tag
  260                   $tag =& $this->xml_index[$tagID];
  261  
  262                   $name = $tag->name;
  263                   $attributes = $tag->attributes;
  264                   $contents = $tag->contents;
  265                   $tags = $tag->tags;
  266           }
  267           
  268           function &getTagByID($tagID) {
  269                   // Returns tag information via variable references from a tag index#
  270  
  271  
  272                   // Get object reference for tag
  273                   $tag =& $this->xml_index[$tagID];
  274                   return $tag;
  275           }       
  276  
  277           function getChildByName($parentID,$childName,$startIndex=0) {
  278                   // Returns child index# searching by name
  279  
  280  
  281                   // Get reference for parent
  282                   $parent =& $this->xml_index[$parentID];
  283  
  284                   if ($startIndex > count($parent->tags)) return false;
  285  
  286  
  287                   for ($i = $startIndex; $i < count($parent->tags); $i++) {
  288                           $childID = $parent->tags[$i];           
  289  
  290                           // Get reference for child
  291                           $child =& $this->xml_index[$childID];
  292  
  293                           if ($child->name == $childName) {
  294                                   // Found child, return index#
  295  
  296                                   return $childID;
  297                           }
  298                   }
  299           }
  300  
  301   }
  302  
  303  
  304   class xml_tag {
  305  
  306           var $refID;                     // Unique ID number of the tag
  307           var $name;                      // Name of the tag
  308           var $attributes = array();      // Array (assoc) of attributes for this tag
  309           var $tags = array();            // An array of refID's for children tags
  310           var $contents;                  // textual (CDATA) contents of a tag
  311           var $children = array();        // Collection (type: xml_tag) of child tag's
  312  
  313  
  314           function xml_tag(&$document,$tag_name,$tag_attrs=array(),$tag_contents='') {
  315                   // Constructor function for xml_tag class
  316  
  317  
  318                   // Set object variables
  319                   $this->name = $tag_name;
  320                   $this->attributes = $tag_attrs;
  321                   $this->contents = $tag_contents;
  322  
  323                   $this->tags = array();                  // Initialize children array/collection
  324                   $this->children = array();
  325           }
  326  
  327           function addChild (&$document,$tag_name,$tag_attrs=array(),$tag_contents='') {
  328                   // Adds a child tag object to the current tag object
  329  
  330  
  331                   // Create child instance
  332                   $this->children[(count($this->children))] = new xml_tag($document,$tag_name,$tag_attrs,$tag_contents);
  333  
  334                   // Add object reference to document index
  335                   $document->xml_index[$document->xml_reference] =& $this->children[(count($this->children) - 1)];
  336  
  337                   // Assign document index# to child
  338                   $document->xml_index[$document->xml_reference]->refID = $document->xml_reference;
  339  
  340                   // Add child index# to parent collection of child indices
  341                   array_push($this->tags,$document->xml_reference);
  342  
  343                   // Update document index counter
  344                   $document->xml_reference++;
  345  
  346                   // Return child index#
  347                   return ($document->xml_reference - 1);
  348           }
  349   }
  350  
  351   ?>