<?php
/***************************************************************************
phpdomxml-0.8.5 - an XML Document Object Model implementation for PHP 4.10+.
(c) copyright 2002-2003, Bas van Gaalen. All rights reserved.
This library may be distributed under the terms of the LICENSE, which is
included in this package.
***************************************************************************/
// Define element type constants
define('XML_TYPE_NODE', 1);
define('XML_TYPE_TEXT', 3);
define('XML_TYPE_CDATA', 4);
// XMLNode sub-class: Text =================================================
class XMLText {
// Property (r); returns the node value of the XML object.
var $nodeValue;
// Property (r); retrieves the type of the requested node.
var $nodeType;
function XMLText() {
// Init property
$this->nodeValue = null;
$this->nodeType = XML_TYPE_TEXT;
} // End XMLText-constructor
} // End XMLText class
// XML sub-class: Tags =====================================================
class XMLNode extends XMLText {
// Public properties ----------------------------------------------------
// Collection (r/w); returns an associative array containing all
// attributes of the specified XML object
var $attributes;
// Collection (r); returns an array of the specified XML object's children.
var $childNodes;
// Property (r); references the first child in the parent node's child list.
var $firstChild;
// Property (r); references the last child in the parent node's child list.
var $lastChild;
// Property (r); references the previous sibling in the parent node's child list.
var $previousSibling;
// Property (r); references the next sibling in the parent node's child list.
var $nextSibling;
// Property (r/w); takes or returns the node name of the XML object.
var $nodeName;
// Property (r); references the parent node of the specified XML object.
var $parentNode;
// Property (r); retrieves the type of the requested node.
var $nodeType;
// XMLNode constructor --------------------------------------------------
function XMLNode() {
// Init properties
$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;
} // End XMLNode-constructor
// Private methods ------------------------------------------------------
function _xml_get_children($vals, &$i) {
$children = array();
// CData section before children
if (isset($vals[$i]['value'])) {
$tmp = new XMLText();
$tmp->nodeValue = $vals[$i]['value'];
$tmp->nodeType = XML_TYPE_CDATA;
$children[] = $tmp;
}
// Browse children
$lastelm = '';
$nChildren = count($vals);
while (++$i < $nChildren) {
switch ($vals[$i]['type']) {
case 'cdata':
if ($lastelm != 'cdata') {
// New CData section
$tmp = new XMLText();
$tmp->nodeValue = $vals[$i]['value'];
$tmp->nodeType = XML_TYPE_CDATA;
$children[] = $tmp;
} else {
// Continuing last CData section
$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 ($nThisChildren > 1) {
for ($j = $nThisChildren-2; $j >= 0; $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'];
}
} // End _xml_get_children
// Public methods -------------------------------------------------------
// Appends the specified child node to the XML object's child list.
function appendChild(&$child) {
// Set child's parentNode
$child->parentNode =& $this;
// Add child to list of childNodes
$this->childNodes[] =& $child;
// Is child of type node?
if ($child->nodeType == XML_TYPE_NODE) {
// Set child's previousSibling
$child->previousSibling =& $this->lastChild;
}
// Is this node of type node?
if ($this->nodeType == XML_TYPE_NODE) {
// Set current lastChild's nextSibling to this child
if (!is_null($this->lastChild)) {
$this->lastChild->nextSibling =& $child;
}
// Now (re)set firstChild and lastChild
$this->firstChild =& $this->childNodes[0];
$this->lastChild =& $child;
}
} // End appendChild
// Creates a new XML element with the name specified in the argument.
function createElement($name) {
$tmp = new XMLNode();
$tmp->nodeName = $name;
return $tmp;
} // End createElement
// Creates a new XML text node with the specified text.
function createTextNode($value) {
$tmp = new XMLText();
$tmp->nodeValue = trim($value);
return $tmp;
} // End createTextNode
// Returns true if there are child nodes; otherwise, returns false.
function hasChildNodes() {
return !is_null($this->childNodes);
} // End hasChildNodes
// Inserts a new child node into the XML object's child list, before the
// provided node
function insertBefore(&$child, $refChild = null) {
// Not implemented yet...
} // End insertBefore
// Removes the specified XML object from its parent.
function removeChild() {
// Not implemented yet...
} // End removeNode
// Evalutes the specified XML object, constructs a textual representation
// of the XML structure including the node, children and attributes, and
// returns the result as a string.
function toString() {
$tagOpen = "<";
$tagClose = ">";
$tagBreak = "";
// Set xml-decleration and doc-type if this is the root-element
$retVal = "";
if (is_null($this->parentNode)) {
$retVal .= $this->xmlDecl;
$retVal .= $this->docTypeDecl;
}
// If this element has attributes, gather them
$sAttr = "";
if (isset($this->attributes)) {
foreach ($this->attributes as $key=>$val)
$sAttr .= " $key=\"$val\"";
}
if (isset($this->nodeName)) {
if ($this->hasChildNodes()) {
$retVal .= $tagOpen.$this->nodeName.$sAttr.$tagClose.$tagBreak;
} elseif (isset($this->firstChild->nodeValue)) {
$retVal .= $tagOpen.$this->nodeName.$sAttr.$tagClose.$this->firstChild->nodeValue.$tagOpen."/".$this->nodeName.$tagClose.$tagBreak;
} else {
$retVal .= $tagOpen.$this->nodeName.$sAttr." /".$tagClose.$tagBreak;
}
}
if ($this->hasChildNodes()) {
foreach ($this->childNodes as $child) {
switch ($child->nodeType) {
case XML_TYPE_NODE: // node
default:
$retVal .= $child->toString();
break;
case XML_TYPE_TEXT: // text
$retVal .= $child->nodeValue;
break;
case XML_TYPE_CDATA: // CData
$retVal .= "<![CDATA[".$child->nodeValue."]]>";
break;
}
}
}
if ($this->hasChildNodes() && isset($this->nodeName)) {
$retVal .= $tagOpen."/".$this->nodeName.$tagClose.$tagBreak;
}
return $retVal;
} // End toString
} // End XMLNode class
// Main XML class ==========================================================
class XML extends XMLNode {
// Public properties ----------------------------------------------------
// Some vars for error tracking and messages
var $status;
var $error;
// XML version
var $version;
// XML character encoding
var $encoding;
// Indicates the MIME type transmitted to the server.
var $contentType;
// Property (r/w); information about the XML document DOCTYPE decleration.
var $docTypeDecl;
// Property (r/w); sets and returns information about a document's XML decleration.
var $xmlDecl;
// XML constructor ------------------------------------------------------
function XML($url = '') {
// Init external properties
parent::XMLNode();
$this->status = 0;
$this->error = '';
$this->version = '1.0';
$this->encoding = 'ISO-8859-1';
$this->contentType = 'text/xml';
$this->docTypeDecl = '';
$this->xmlDecl = '';
// Load the referenced XML document
$this->load($url);
} // End XML-constructor
// Public methods -------------------------------------------------------
// Loads an XML document from the specified URL.
function load($url) {
if (empty($url)) return false;
$this->parseXML(implode('', @file($url)));
} // End load
// Parses the XML text specified in the source argument.
function parseXML($source) {
// Clear any content that this object might have
// Call: $this->removeNode()
// Get xml declration from document and set in object
if (preg_match("/<?xml\ (.*?)\?>/i", $source, $matches)) {
$this->xmlDecl = "<?xml ".$matches[1]."?>";
// Get version
if (preg_match("/version=\"(.*?)\"/i", $matches[1], $versionInfo)) {
$this->version = $versionInfo[1];
}
// Get encoding
if (preg_match("/encoding=\"(.*?)\"/i", $matches[1], $encodingInfo)) {
$this->encoding = $encodingInfo[1];
}
}
// Get document type decleration from document and set in object
if (preg_match("/<!doctype\ (.*?)>/i", $source, $matches)) {
$this->docTypeDecl = "<!DOCTYPE ".$matches[1].">";
}
// Strip white space between tags - not _in_ tags
$source = preg_replace("/>\s+</i", "><", $source);
// Parse the xml document to an array structure
$parser = xml_parser_create($this->encoding);
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parse_into_struct($parser, $source, $vals, $index);
xml_parser_free($parser);
// parse the structure and create this object...
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);
}
} // End parseXML
// Encodes the specified XML object into a XML document and sends
// it to the specified URL using the POST method.
// $url is of the form: (http://)www.domain.com:port/path/to/file
function send($url) {
// Get xml document
$strXML = $this->toString();
// Get url parts
if (!preg_match("/http/", $url)) $url = "http://".$url;
$urlParts = parse_url($url);
$host = isset($urlParts['host'])?$urlParts['host']:'localhost';
$port = isset($urlParts['port'])?$urlParts['port']:80;
$path = isset($urlParts['path'])?$urlParts['path']:"/";
// Open a connection with the required host
$fp = fsockopen($host, $port, $errno, $errstr);
if (!$fp) {
$this->status = -11;
$this->error = "Unable to connect to $host at port $port: ($errno) $errstr";
return false;
}
// Send the xml document
fputs($fp, "POST ".$path." HTTP/1.0\r\n".
"Host: ".$host."\r\n".
"Content-length: ".strlen($strXML)."\r\n".
"Content-type: ".$this->contentType."\r\n".
"Connection: close\r\n\r\n".
$strXML."\r\n");
return $fp;
} // End send
// Encodes the specified XML object into a XML document, sends
// it to the specified URL using the POST method, downloads the server's
// response and then loads it into the target.
// $url is of the form: (http://)www.domain.com:port/path/to/file
function sendAndLoad($url, &$target) {
// Check target type, fail on wrong type
if (gettype($target) != 'object') {
$this->status = -10;
$this->error = "Target is of type '".gettype($target)."', but should be 'object'";
return false;
}
// Send the xml document
if (!$fp = $this->send($url)) return false;
// Recieve response
$buf = "";
while (!feof($fp)) $buf .= fread($fp, 128);
fclose($fp);
// Filter xml out response (dump http headers)
if (!preg_match("/(<.*>)/msi", $buf, $matches)) { // Greedy match
$this->status = -12;
$this->error = "Unidentified server response: no xml was sent";
return false;
}
$xmlResponse = $matches[1];
$target->parseXML($xmlResponse);
return true;
} // End sendAndLoad
} // End XML class
?>