PHP Classes
Icontem

File: class.xml.phtml


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Ricardo Costa  >  MySQL to XML - XML to MySQL  >  class.xml.phtml  
File: class.xml.phtml
Role: Class source
Content type: text/plain
Description: Class by Chris Monson required by my class
Class: MySQL to XML - XML to MySQL
Insert XML in MySQL and export MySQL to XML
 

Contents

Class file image Download
<?php
# XMLFile -- Initial version June 1, 2000 
# May 29, 2002
#  Fixed to work with later versions of PHP that have deprecated the call-time
#  pass by reference syntax.  This may break versions of PHP older than 3, so
#  if you are using this on those versions, go with an earlier version.
#  Also added some more comments on how to use it to create XML files.  Some
#  people (a surprising number of them, in fact) were having difficulty
#  understanding the recursive nature of XML files, and that each tag has
#  subtags, each of which can have subtags, each of which....
# July 12, 2001
#  Fixed an oops in the find_subtags_by_name function.
# July 11, 2001
#  Incorporated Kevin Howe's read_xml_string function.
#  Incorporated Mike Konkov's find_subtags_by_name function (with some changes).
#  Fixed an errant documentation comment (open instead of fopen -- oops).
#
# September 29, 2000
# by Chris Monson -- e408345b17be3ce90059d01d96be0599@orangatango.com This PHP module is licensed under the GNU LGPL (www.gnu.org)
# Please become familiar with this license before sending this thing all over
# the place!  I would like to have any changes submitted back to me, and this
# comment must be included with any distribution of this component.
#
# The purpose of this module was to provide a simple interface for dealing with
# small to medium sized XML files.  It is probably not suitable for very large
# files since it reads the entire file into a structure in memory.  For very
# large files, the XML parsing functions should be used more or less directly
# so that pieces of the file can be dealt with as they are read in.
#
# The basic idea is this: Read the XML file into an internal tree structure
# that is easy to traverse.  This module also allows you to create such a
# structure in memory and then write it out to disk.  The output is formatted
# in a nice, readable way, using whitespace to delimit tag containment, etc.
# It makes it very easy to write nice-looking XML files.
#
# I have included some usage comments.  They are almost certainly incomplete.
# If you get stumped, first use the source, then email me.
#
#------------------------------------------------------------------------------
### USAGE ###
#------------------------------------------------------------------------------
# Reading an XML file:
#------------------------------------------------------------------------------
#
# $xml = new XMLFile();
# $fh = fopen( 'myxmlfile.xml', 'r' );
# $xml->read_file_handle( $fh );
# close( $fh );
#
# Now the tags can be accessed via the root node of $xml:
#
# $root = &$xml->roottag;
# $tagname = $root->name;
# $tagdata = $root->cdata;
#
# Note that a tag is of the following form:
# <NAME attribute=value>CDATA</NAME>
# Each tag contains an attributes array, which is associative by nature.  In
# other words, you would access the value of "attribute" as follows:
#
# $value = $root->attributes['attribute'];
#
# Also, each tag has a 'tags' proprerty, which is an ordered array (integer
# indices, not associative!) which has the tags that were contained within
# this tag in their order of appearance.  The reason that this is not
# associative is that there can be multiple tags of the same name.  There is
# nothing in the XML spec (barring a DTD) that declares the uniqueness of tag
# names.  For example:
#
# <OUTER>
#     <INNER>CDATA</INNER>
#     <INNER name="hello"/>
# </OUTER>
#
# In the above example, the outer tag would have a tags array that has two
# entries, each of which has a tag name of "INNER".  The one with CDATA wrapped
# inside would be at index 0, and the other would be at index 1.
#
# Once you have finished with the XMLFile object, you need to call the cleanup
# method.  If you don't, you will get a memory leak, since PHP is reference
# counted and each element in the tree refers to its parent.  'cleanup' simply
# traverses the tree and disconnects the parent pointers.  The PHP cleans up
# everything else.
#
# $xml->cleanup();
# 
# Note that you can change the elements, delete tags, and do other things
# to the tree once it has been read from the file.  After it has been changed,
# you can write it back out and the file will reflect your changes.
#------------------------------------------------------------------------------
# Writing a new file:
# 
# $xml = new XMLFile();
# $xml->create_root(); # necessary -- no root is created until requested
# $xml->roottag->name = 'ROOT';
# $xml->roottag->add_subtag( 'INNER', array() );
# $innertag = &$xml->roottag->curtag;
# $innertag->add_subtag( 'REALLYINNER', array() );
# # Or, you can do this:
# $xml->roottag->curtag->add_subtag( 'INNER2', array() );
# # The point is that each tag can have subtags.  The most recently added
# # subtag is always the curtag of its parent.
# $xml->roottag->add_subtag( 'INNER', array( 'name' => 'value' ) );
# $xml->roottag->curtag->cdata = "Hello!"; # curtag is the most recent addition
# $fh = fopen( 'myxmlfile.xml', 'w' );
# $xml->write_file_handle( $fh );
# close( $fh );
#
# The file will look like this: (no space between ? and >)
#
# <?xml version="1.0" encoding="UTF-8" ? >
# <ROOT>
#     <INNER>
#           <REALLYINNER/>
#           <INNER2/>
#     </INNER>
#     <INNER name="value">Hello!</INNER>
# </ROOT>
#
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
#
if (!isset($XMLFile_Included) || !$XMLFile_Included) {
$XMLFile_Included = 1;

###############################################################################
class XMLTag
{
    var $cdata;
    var $attributes;
    var $name;
    var $tags;
    var $parent;

    var $curtag;

    function XMLTag(&$parent)
    {
        if (is_object( $parent ))
        {
            $this->parent = &$parent;
        }
        $this->_init();
    }

    function _init()
    {
        $this->attributes = array();
        $this->cdata = '';
        $this->name = '';
        $this->tags = array();
    }

    function add_subtag($name, $attributes=0)
    {
        $tag = new XMLTag( $this );
        $tag->set_name( $name );
        if (is_array($attributes)) {
            $tag->set_attributes( $attributes );
        }
        $this->tags[] = &$tag;
        $this->curtag = &$tag;
    }

    function find_subtags_by_name( $name )
    {
        $result = array();
        $found=false;
        for($i=0;$i<$this->num_subtags();$i++) {
            if(strtoupper($this->tags[$i]->name)==strtoupper($name)) {
                $found=true;
                $array2return[]=&$this->tags[$i];
            }
        }
        if($found) {
            return $array2return;
        }
        else {
            return false;
        }
    }

    function clear_subtags()
    {
        # Traverse the structure, removing the parent pointers
        $numtags = sizeof($this->tags);
        $keys = array_keys( $this->tags );
        foreach( $keys as $k ) {
            $this->tags[$k]->clear_subtags();
            unset($this->tags[$k]->parent);
        }

        # Clear the tags array
        $this->tags = array();
        unset( $this->curtag );
    }

    function remove_subtag($index)
    {
        if (is_object($this->tags[$index])) {
            unset($this->tags[$index]->parent);
            unset($this->tags[$index]);
        }
    }

    function num_subtags()
    {
        return sizeof( $this->tags );
    }

    function add_attribute( $name, $val )
    {
        $this->attributes[strtoupper($name)] = $val;
    }

    function clear_attributes()
    {
        $this->attributes = array();
    }

    function set_name( $name )
    {
        $this->name = strtoupper($name);
    }

    function set_attributes( $attributes )
    {
        $this->attributes = (is_array($attributes)) ? $attributes : array();
    }

    function add_cdata( $data )
    {
        $this->cdata .= $data;
    }

    function clear_cdata()
    {
        $this->cdata = "";
    }

    function write_file_handle( $fh, $prepend_str='' )
    {
        # Get the attribute string
        $attrs = array();
        $attr_str = '';
        foreach( $this->attributes as $key => $val )
        {
            $attrs[] = strtoupper($key) . "=\"$val\"";
        }
        if ($attrs) {
            $attr_str = join( " ", $attrs );
        }
        # Write out the start element
        $tagstr = "$prepend_str<{$this->name}";
        if ($attr_str) {
            $tagstr .= " $attr_str";
        }

        $keys = array_keys( $this->tags );
        $numtags = sizeof( $keys );
        # If there are subtags and no data (only whitespace), 
        # then go ahead and add a carriage
        # return.  Otherwise the tag should be of this form:
        # <tag>val</tag>
        # If there are no subtags and no data, then the tag should be
        # closed: <tag attrib="val"/>
        $trimmeddata = trim( $this->cdata );
        if ($numtags && ($trimmeddata == "")) {
            $tagstr .= ">\n";
        }
        elseif (!$numtags && ($trimmeddata == "")) {
            $tagstr .= "/>\n";
        }
        else {
            $tagstr .= ">";
        }

        fwrite( $fh, $tagstr );

        # Write out the data if it is not purely whitespace
        if ($trimmeddata != "") {
            fwrite( $fh, $trimmeddata );
        }

        # Write out each subtag
        foreach( $keys as $k ) {
            $this->tags[$k]->write_file_handle( $fh, "$prepend_str\t" );
        }

        # Write out the end element if necessary
        if ($numtags || ($trimmeddata != "")) {
            $tagstr = "</{$this->name}>\n";
            if ($numtags) {
                $tagstr = "$prepend_str$tagstr";
            }
            fwrite( $fh, $tagstr );
        }
    }

}
###############################################################################
class XMLFile
{
    var $parser;
    var $roottag;
    var $curtag;

    function XMLFile()
    {
        $this->init();
    }

    # Until there is a suitable destructor mechanism, this needs to be
    # called when the file is no longer needed.  This calls the clear_subtags
    # method of the root node, which eliminates all circular references
    # in the xml tree.
    function cleanup()
    {
        if (is_object( $this->roottag )) {
            $this->roottag->clear_subtags();
        }
    }

    function init()
    {
        $this->roottag = "";
        $this->curtag = &$this->roottag;
    }

    function create_root()
    {
        $null = 0;
        $this->roottag = new XMLTag($null);
        $this->curtag = &$this->roottag;
    }

    # read_xml_string
    # Same as read_file_handle, but you pass it a string.  Note that
    # depending on the size of the XML, this could be rather memory intensive.
    # Contributed July 06, 2001 by Kevin Howe
    function read_xml_string( $str )
    {
        $this->init();
        $this->parser = xml_parser_create("UTF-8");
        xml_set_object( $this->parser, $this );
        xml_set_element_handler( $this->parser, "_tag_open", "_tag_close" );
        xml_set_character_data_handler( $this->parser, "_cdata" );
        xml_parse( $this->parser, $str );
        xml_parser_free( $this->parser );
    }

    function read_file_handle( $fh )
    {
        $this->init();
        $this->parser = xml_parser_create("UTF-8");
        xml_set_object( $this->parser, $this );
        xml_set_element_handler( $this->parser, "_tag_open", "_tag_close" );
        xml_set_character_data_handler( $this->parser, "_cdata" );

        while( $data = fread( $fh, 4096 )) {
            if (!xml_parse( $this->parser, $data, feof( $fh ) )) {
                die(sprintf("XML error: %s at line %d",
                    xml_error_string(xml_get_error_code($this->parser)),
                    xml_get_current_line_number($this->parser)));
            }
        }

        xml_parser_free( $this->parser );
    }

    function write_file_handle( $fh, $write_header=1 )
    {
        if ($write_header) {
            fwrite( $fh, "<?xml version='1.0' encoding='UTF-8'?>\n" );
        }

        # Start at the root and write out all of the tags
        $this->roottag->write_file_handle( $fh );
    }

    ###### UTIL #######

    function _tag_open( $parser, $tag, $attributes )
    {
        #print "tag_open: $parser, $tag, $attributes\n";
        # If the current tag is not set, then we are at the root
        if (!is_object($this->curtag)) {
            $null = 0;
            $this->curtag = new XMLTag($null);
            $this->curtag->set_name( $tag );
            $this->curtag->set_attributes( $attributes );
        }
        else { # otherwise, add it to the tag list and move curtag
            $this->curtag->add_subtag( $tag, $attributes );
            $this->curtag = &$this->curtag->curtag;
        }
    }

    function _tag_close( $parser, $tag )
    {
        # Move the current pointer up a level
        $this->curtag = &$this->curtag->parent;
    }

    function _cdata( $parser, $data )
    {
        $this->curtag->add_cdata( $data );
    }
}
###############################################################################
} // included
###############################################################################

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products