<?php

class SPiNXMLObject {
	var $xmlParser;
	var $xmlData;
	var $xmlTag;
	
	function SPiNXMLObject( $xmlData ) {
		$this->xmlParser = null;
		$this->xmlData = $xmlData;
		$this->xmlTag = null;
	}
	
	function elementStart( $theParser, $theName, $theAttributes ) {
		if( !is_object( $this->xmlTag ) ) {
			$this->xmlTag = new SPiNXMLTag();
			$this->xmlTag->setName( $theName );
			$this->xmlTag->setAttributes( $theAttributes );
		}
		else {
			$this->xmlTag->addTag( $theName );
			$this->xmlTag->setAttributes( $theAttributes );
			$this->xmlTag = &$this->xmlTag->getTag();
		}
	}
	
	function elementEnd( $theParser, $theName ) {
		$this->xmlTag = $this->xmlTag->getParent();
	}
	
	function elementData( $theParser, $theData ) {
		$this->xmlTag->addContent( $theData );
	}
	
	function run() {
		$this->xmlParser = xml_parser_create();
		xml_set_object( $this->xmlParser, &$this );
		xml_set_element_handler( $this->xmlParser, "elementStart", "elementEnd" );
		xml_set_character_data_handler( $this->xmlParser, "elementData" );
		
		xml_parse( $this->xmlParser, $this->xmlData );
	}
	
	function destroy() {
		xml_parser_free( $this->xmlParser );
	}
	
	function createXML( $theRootTag, $xmlPre = "" ) {
		$xmlTagList = $theRootTag->tagTags;
		
		$xmlAttributes = array();
		foreach( $theRootTag->getAttributes() as $key => $value ) {
			array_push( $xmlAttributes, strtolower( $key . "=\"" . $value . "\"" ) );
		}
		
		$this->xmlData .= $xmlPre . $theRootTag->getName();
		if( count( $xmlAttributes ) > 0 ) {
			$this->xmlData .= implode( " ", $xmlAttributes );
		}
		
		if( count( array_keys( $xmlTagList ) ) > 0 && trim( $theRootTag->getContent() ) == "" ) {
			$this->xmlData .= ">\n";
			
			createXML( array_pop( $xmlTagList ), $xmlPre . "\t" );
		}
		else if( count( array_keys( $this->xmlTagList ) ) == 0 && trim( $theRootTag->getContent() ) == "" ) {
			$this->xmlData .= " />\n";
		}
		else {
			$this->xmlData .= ">" . trim( $theRootTag->getContent() . "</" . $theRootTag->getName() . ">\n";
		}
	}
	
	function getXML() {
		if( substr( trim( $this->xmlData ), 0, 5 ) == "<?xml" )
			$this->xmlData = writePI() . $this->xmlData;
		
		return $this->xmlData;
	}
	
	function writePI() {
		return "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
	}
	
	function saveXML( $filename ) {
		$filePointer = fopen( $filename, 'w' );
		
		if( !$filePointer )
			return false;
		
		fputs( strlen( $this->getXML() ), $this->getXML() );
		fclose( $filePointer );
	}
}

class SPiNXMLTag {
	var $tagName;
	var $tagAttributes;
	var $tagData;
	var $tagTags;
	var $tagParent;
	var $xmlTag;
	
	function SPiNXMLTag() {
		$tagAttributes = array();
		$tagTags = array();
	}
	
	function setName( $theName ) {
		$this->tagName = $theName;
	}
	
	function getName() {
		return $this->tagName;
	}
	
	function setAttributes( $theAttributes ) {
		is_array( $theAttributes ) ? $theAttributes : array();
	}
	
	function getAttributes() {
		return $this->theAttributes;
	}
	
	function addTag ( $theName ) {
		$tag = $this->newTag();
		$tag->setName( $theName );
		
		$this->tagParent = &$this->xmlTag;
		
		array_push( $this->tagTags, $tag );
		$this->xmlTag = $tag;
	}
	
	function addContent( $theData ) {
		$this->tagData .= $theData;
	}
	
	function getContent() {
		return $this->tagData;
	}
	
	function getTag() {
		return $this->xmlTag;
	}
	
	function getParent() {
		return $this->tagParent;
	}
	
	function getElementsByName( $theName ) {
		$result = array();
		$found = false;
		
		for( $i = 0; $i < count( $this->tagTags ); $i++ ) {
			if( strtolower( $theName ) == strtolower( $this->tagTags[ $i ]->getName() ) ) {
				$found = true;
				array_push( $result, &$this->tagTags[ $i ] );
			}
		}
		
		$found ? return $result : return false;
	}
}

?>