<?php

class SPiNXMLObject {
	var $xmlParser;
	var $xmlData;
	var $xmlTag;

	function start( $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->start();
			$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 parse() {
		$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 $tagAttributeList;
	var $tagData;
	var $tagTags;
	var $tagParent;
	var $xmlTag;

	function start() {
		$this->tagAttributeList = null;
		$this->tagTags = array();
	}
	
	function setName( $theName ) {
		$this->tagName = $theName;
	}
	
	function getName() {
		return $this->tagName;
	}
	
	function setAttribute( $tagAttributeName, $tagAttributeValue ) {
		if( is_null( $this->tagAttributeList ) ) {
			$this->tagAttributeList = new SPiNXMLAttributeList();
			$this->tagAttributeList->start();
		}
		
		$this->tagAttributeList->apply( $tagAttributeName, $tagAttributeValue );
	}
	
	function getAttributes() {
		return $this->tagAttributeList;
	}
	
	function addTag ( $theName ) {
		$tag = new SPiNXMLTag();
		$tag->start();
		$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;
	}
}

class SPiNXMLAttributeList {
	var $attributeList;

	function start() {
		$this->attributeList = array();
	}

	function add( $tagAttribute ) {
		array_push( $this->attributeList, $tagAttribute );
	}

	function apply( $tagAttributeName, $tagAttributeValue ) {
		$xmlAttribute = new SPiNXMLAttribute();
		$xmlAttribute->setName( $tagAttributeName );
		$xmlAttribute->setValue( $tagAttributeValue );

		$array_push( $this->attributeList, $xmlAttribute );
	}

	function getByName( $attributeName ) {
		$resultIndex = array_search( $attributeName, $this->attributeList, true );
		
		if( $resultIndex == null || $resultIndex == false )
			return false;

		return $this->attributeList[ $resultIndex ];
	}
}

class SPiNXMLAttribute {
	var $attrName;
	var $attrValue;

	function setName( $attributeName ) {
		$this->attrName = $attributeName;
	}

	function getName() {
		return $this->attrName;
	}

	function setValue( $attributeValue ) {
		$this->attrValue = $attributeValue;
	}

	function getValue() {
		$this->attrValue;
	}
}

?>