<?php
class xmltext {
		public $nodeValue;
		public $nodeType;
		public $entities = array ( "&" => "&amp;", "<" => "&lt;", ">" => "&gt;", "'" => "&apos;", "\"" => "&quot;" );

		public function xmltext() {
				$this -> nodeValue = null;
				$this -> nodeType = XML_TYPE_TEXT;
		} 
} 

class xmlnode extends xmltext {
		public $attributes;
		public $childNodes;
		public $firstChild;
		public $lastChild;
		public $previousSibling;
		public $nextSibling;
		public $nodeName;
		public $parentNode;

		public function xmlnode() {
				$this -> attributes = null;
				$this -> childNodes = null;
				$this -> firstChild = null;
				$this -> lastChild = null;
				$this -> previousSibling = null;
				$this -> nextSibling = null;
				$this -> nodeName = null;
				$this -> parentNode = null;
				$this -> nodeType = XML_TYPE_NODE;
		} 

		public function _xml_get_children( $vals, &$i ) {
				$children = array();
				if ( isset( $vals[$i]['value'] ) ) {
						$tmp = new xmltext();
						$tmp -> nodeValue = $vals[$i]['value'];
						$tmp -> nodeType = XML_TYPE_CDATA;
						$children[] = $tmp;
				} 
				$lastelm = "";
				$nChildren = count( $vals );
				while ( ++$i < $nChildren ) {
						switch ( $vals[$i]['type'] ) {
								case "cdata" :
										if ( $lastelm != "cdata" ) {
												$tmp = new xmltext();
												$tmp -> nodeValue = $vals[$i]['value'];
												$tmp -> nodeType = XML_TYPE_CDATA;
												$children[] = $tmp;
										} else {
												$children[count( $children ) - 1] -> nodeValue .= $vals[$i]['value'];
										} 
										break;
								case "complete" :
										$tmp = new xmlnode();
										$tmp -> nodeName = $vals[$i]['tag'];
										$tmp -> attributes = ( isset( $vals[$i]['attributes'] ) ? $vals[$i]['attributes'] : null );
										if ( isset( $vals[$i]['value'] ) ) {
												$tmp -> appendchild( xmlnode :: createtextnode( $vals[$i]['value'] ) );
										} 
										$tmp -> parentNode = $this;
										$children[] = $tmp;
										break;
								case "open" :
										$tmp = new xmlnode();
										$tmp -> nodeName = $vals[$i]['tag'];
										$tmp -> attributes = ( isset( $vals[$i]['attributes'] ) ? $vals[$i]['attributes'] : null );
										$tmp -> parentNode = $this;
										$tmp -> childNodes = $tmp -> _xml_get_children( $vals, $i );
										$children[] = $tmp;
										break;
								case "close" :
										$nThisChildren = count( $children );
										if ( 1 < $nThisChildren ) {
												for ( $j = $nThisChildren - 2; 0 <= $j; $j-- ) {
														$children[$j] -> nextSibling = &$children[$j + 1];
												} 
												for ( $j = 1; $j < $nThisChildren; $j++ ) {
														$children[$j] -> previousSibling = &$children[$j - 1];
												} 
										} 
										$this -> firstChild = &$children[0];
										$this -> lastChild = &$children[( $nThisChildren - 1 ) % $nThisChildren];
										return $children;
										break;
						} 
						$lastelm = $vals[$i]['type'];
				} 
		} 

		public function appendchild( &$child ) {
				$child -> parentNode = &$this;
				$this -> childNodes[] = $child;
				if ( $child -> nodeType == XML_TYPE_NODE ) {
						$child -> previousSibling = &$this -> lastChild;
				} 
				if ( $this -> nodeType == XML_TYPE_NODE ) {
						if ( !is_null( $this -> lastChild ) ) {
								$this -> lastChild -> nextSibling = $child;
						} 
						$this -> firstChild = &$this -> childNodes[0];
						$this -> lastChild = $child;
				} 
		} 

		public function createelement( $name ) {
				$tmp = new xmlnode();
				$tmp -> nodeName = $name;
				return $tmp;
		} 

		public function createtextnode( $value ) {
				$tmp = new xmltext();
				$tmp -> nodeValue = trim( $value );
				return $tmp;
		} 

		public function haschildnodes() {
				return !is_null( $this -> childNodes );
		} 

		public function insertbefore( &$child, $refChild = null ) {
		} 

		public function removechild() {
		} 

		public function tostring() {
				$tagOpen = "<";
				$tagClose = ">";
				$tagBreak = "\n";
				$retVal = "";
				if ( is_null( $this -> parentNode ) ) {
						if ( !empty( $this -> xmlDecl ) ) {
								$retVal .= $this -> xmlDecl . $tagBreak;
						} 
						if ( !empty( $this -> docTypeDecl ) ) {
								$retVal .= $this -> docTypeDecl . $tagBreak;
						} 
				} 
				$sAttr = "";
				if ( isset( $this -> attributes ) ) {
						foreach ( $this -> attributes as $_key => $_val ) {
								$sAttr .= " " . $_key . "=\"" . strtr( $_val, $this -> entities ) . "\"";
						} 
				} 
				if ( isset( $this -> nodeName ) ) {
						if ( $this -> haschildnodes() ) {
								$retVal .= $tagOpen . $this -> nodeName . $sAttr . $tagClose;
								if ( ( $this -> firstChild -> nodeType != XML_TYPE_TEXT ) && ( $this -> firstChild -> nodeType != XML_TYPE_CDATA ) ) {
										$retVal .= $tagBreak;
								} 
						} else if ( isset( $this -> firstChild -> nodeValue ) ) {
								$retVal .= $tagOpen . $this -> nodeName . $sAttr . $tagClose . strtr( $this -> firstChild -> nodeValue, $this -> entities ) . $tagOpen . "/" . $this -> nodeName . $tagClose . $tagBreak;
						} else {
								$retVal .= $tagOpen . $this -> nodeName . $sAttr . " /" . $tagClose . $tagBreak;
						} 
				} 
				if ( $this -> hasChildNodes() ) {
						foreach ( $this -> childNodes as $nk => $nv ) {
								switch ( $this -> childNodes[$nk] -> nodeType ) {
										case XML_TYPE_TEXT:
												$retVal .= strtr( $this -> childNodes[$nk] -> nodeValue, $this -> entities );
												break;
										case XML_TYPE_CDATA:
												$retVal .= "<![CDATA[" . $this -> childNodes[$nk] -> nodeValue . "]]>";
												break;
										case XML_TYPE_NODE:
										default:
												$retVal .= $this -> childNodes[$nk] -> toString();
												break;
								} 
						} 
				} 
				if ( $this -> haschildnodes() && isset( $this -> nodeName ) ) {
						$retVal .= $tagOpen . "/" . $this -> nodeName . $tagClose . $tagBreak;
				} 
				return $retVal;
		} 
} 

class xml extends xmlnode {
		public $status;
		public $error;
		public $version;
		public $encoding;
		public $contentType;
		public $docTypeDecl;
		public $xmlDecl;

		public function xml( $url = "" ) {
				xmlnode :: xmlnode();
				$this -> status = 0;
				$this -> error = "";
				$this -> version = "1.0";
				$this -> encoding = "UTF-8";
				$this -> contentType = "text/xml";
				$this -> docTypeDecl = "";
				$this -> xmlDecl = "";
				$this -> load( $url );
		} 

		function load( $url ) {
				if ( empty( $url ) ) {
						return false;
				} 
				$this -> parsexml( @file_get_contents( $url ) );
		} 

		function parsexml( $source ) {
				if ( preg_match( "/<\?xml\s+([^<>]*)\?>/i", $source, $matchs ) ) {
						$this -> xmlDecl = "<?xml " . $matchs[1] . "?>";
						if ( preg_match( "/version\s*=\s*('|\")([^<>'\"]*)('|\")/i", $matches[1], $versionInfo ) ) {
							$this -> version = $versionInfo[2];
						} 
						if ( preg_match( "/encoding\s*=\s*('|\")([^<>'\"]*)('|\")/i", $matches[1], $encodingInfo ) ) {
								if ( in_array( strtoupper( $encodingInfo[2] ), array( "ISO-8859-1", "UTF-8", "US-ASCII" ) ) ) {
										$this -> encoding = strtoupper( $encodingInfo[2] );
								} else {
										$this -> encoding = "UTF-8";
										$source = preg_replace( "/<\?xml([^<>]*)(encoding\s*=\s*('|\")([^<>'\"]*)('|\"))([^<>]*)\?>/i", "<?xml\${1}encoding=\"UTF-8\"\${6}?>", $source );
								} 
						} 
				} 
				if ( preg_match( "/<!doctype\ (.*?)>/i", $source, $matchs ) ) {
						$this -> docTypeDecl = "<!DOCTYPE " . $matchs[1] . ">";
				} 
				$parser = xml_parser_create( $this -> encoding );
				xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 );
				$source = preg_replace( "/>\s+</i", "><", $source );
				$ret = @xml_parse_into_struct( $parser, $source, $vals );
				if ( !$ret ) {
					$ret = xml_parse_into_struct( $parser, preg_replace( "/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/", "", $source ), $vals );
				} 
				xml_parser_free( $parser );
				if ( !empty( $vals ) ) {
						$root = xmlnode :: createelement( $vals[0]['tag'] );
						$root -> attributes = ( isset( $vals[0]['attributes'] ) ? $vals[0]['attributes'] : null );
						$root -> childNodes = $root -> _xml_get_children( $vals, $i = 0 );
						$this -> appendchild( $root );
				} 
				return $ret;
		} 
} 

define( "XML_TYPE_NODE", 1 );
define( "XML_TYPE_TEXT", 3 );
define( "XML_TYPE_CDATA", 4 );
