2erlei/app/helper/classes/element.inc.php

1729 lines
40 KiB
PHP
Raw Permalink Normal View History

2019-09-22 14:53:30 +00:00
<?php
/**
* MiniXML - PHP class library for generating and parsing XML.
*
* @package miniXML
* @author Patrick Deegan, Psychogenic.com
* @license GPL
*/
require_once(MINIXML_CLASSDIR . "/treecomp.inc.php");
require_once(MINIXML_CLASSDIR . "/node.inc.php");
/***************************************************************************************************
****************************************************************************************************
*****
***** MiniXMLElement
*****
****************************************************************************************************
***************************************************************************************************/
/* class MiniXMLElement (MiniXMLTreeComponent)
**
** Although the main handle to the xml document is the MiniXMLDoc object,
** much of the functionality and manipulation involves interaction with
** MiniXMLElement objects.
**
** A MiniXMLElement
** has:
** - a name
** - a list of 0 or more attributes (which have a name and a value)
** - a list of 0 or more children (MiniXMLElement or MiniXMLNode objects)
** - a parent (optional, only if MINIXML_AUTOSETPARENT > 0)
**/
class MiniXMLElement extends MiniXMLTreeComponent {
var $xname;
var $xattributes;
var $xchildren;
var $xnumChildren;
var $xnumElementChildren;
var $xavoidLoops = MINIXML_AVOIDLOOPS;
/* MiniXMLElement NAME
** Creates and inits a new MiniXMLElement
*/
function MiniXMLElement ($name=NULL)
{
$this->MiniXMLTreeComponent();
$this->xname = NULL;
$this->xattributes = array();
$this->xchildren = array();
$this->xnumChildren = 0;
$this->xnumElementChildren = 0;
if ($name)
{
$this->name($name);
} else {
return _MiniXMLError("MiniXMLElement Constructor: must pass a name to constructor");
}
} /* end method MiniXMLElement */
/**************** Get/set methods for MiniXMLElement data *****************/
/* name [NEWNAME]
**
** If a NEWNAME string is passed, the MiniXMLElement's name is set
** to NEWNAME.
**
** Returns the element's name.
*/
function name ($setTo=NULL)
{
if (! is_null($setTo))
{
if (! is_string($setTo))
{
return _MiniXMLError("MiniXMLElement::name() Must pass a STRING to method to set name");
}
$this->xname = $setTo;
}
return $this->xname;
} /* end method name */
/* attribute NAME [SETTO [SETTOALT]]
**
** The attribute() method is used to get and set the
** MiniXMLElement's attributes (ie the name/value pairs contained
** within the tag, <tagname attrib1="value1" attrib2="value2">)
**
** If SETTO is passed, the attribute's value is set to SETTO.
**
** If the optional SETTOALT is passed and SETTO is false, the
** attribute's value is set to SETTOALT. This is usefull in cases
** when you wish to set the attribute to a default value if no SETTO is
** present, eg $myelement->attribute('href', $theHref, 'http://psychogenic.com')
** will default to 'http://psychogenic.com'.
**
** Note: if the MINIXML_LOWERCASEATTRIBUTES define is > 0, all attribute names
** will be lowercased (while setting and during retrieval)
**
** Returns the value associated with attribute NAME.
**
*/
function attribute ($name, $primValue=NULL, $altValue=NULL)
{
$value = (is_null($primValue) ? $altValue : $primValue );
if (MINIXML_UPPERCASEATTRIBUTES > 0)
{
$name = strtoupper($name);
} elseif (MINIXML_LOWERCASEATTRIBUTES > 0)
{
$name = strtolower($name);
}
if (! is_null($value))
{
$this->xattributes[$name] = $value;
}
if (! is_null($this->xattributes[$name]))
{
return $this->xattributes[$name];
} else {
return NULL;
}
} /* end method attribute */
/* text [SETTO [SETTOALT]]
**
** The text() method is used to get or append text data to this
** element (it is appended to the child list as a new MiniXMLNode object).
**
** If SETTO is passed, a new node is created, filled with SETTO
** and appended to the list of this element's children.
**
** If the optional SETTOALT is passed and SETTO is false, the
** new node's value is set to SETTOALT. See the attribute() method
** for an example use.
**
** Returns a string composed of all child MiniXMLNodes' contents.
**
** Note: all the children MiniXMLNodes' contents - including numeric
** nodes are included in the return string.
*/
function text ($setToPrimary = NULL, $setToAlternate=NULL)
{
$setTo = ($setToPrimary ? $setToPrimary : $setToAlternate);
if (! is_null($setTo))
{
$this->createNode($setTo);
}
$retString = '';
/* Extract text from all child nodes */
for($i=0; $i< $this->xnumChildren; $i++)
{
if ($this->isNode($this->xchildren[$i]))
{
$nodeTxt = $this->xchildren[$i]->getValue();
if (! is_null($nodeTxt))
{
$retString .= "$nodeTxt ";
} /* end if text returned */
} /* end if this is a MiniXMLNode */
} /* end loop over all children */
return $retString;
} /* end method text */
/* numeric [SETTO [SETTOALT]]
**
** The numeric() method is used to get or append numeric data to
** this element (it is appended to the child list as a MiniXMLNode object).
**
** If SETTO is passed, a new node is created, filled with SETTO
** and appended to the list of this element's children.
**
** If the optional SETTOALT is passed and SETTO is false, the
** new node's value is set to SETTOALT. See the attribute() method
** for an example use.
**
** Returns a space seperated string composed all child MiniXMLNodes'
** numeric contents.
**
** Note: ONLY numerical contents are included from the list of child MiniXMLNodes.
**
*/
function numeric ($setToPrimary = NULL, $setToAlternate=NULL)
{
$setTo = (is_null($setToPrimary) ? $setToAlternate : $setToPrimary);
if (! is_null($setTo))
{
$this->createNode($setTo);
}
} /* end method numeric */
/* comment CONTENTS
**
** The comment() method allows you to add a new MiniXMLElementComment to this
** element's list of children.
**
** Comments will return a <!-- CONTENTS --> string when the element's toString()
** method is called.
**
** Returns a reference to the newly appended MiniXMLElementComment
**
*/
function & comment ($contents)
{
$newEl = new MiniXMLElementComment();
$appendedComment =& $this->appendChild($newEl);
$appendedComment->text($contents);
return $appendedComment;
} /* end method comment */
/*
** docType DEFINITION
**
** Append a new <!DOCTYPE DEFINITION [ ...]> element as a child of this
** element.
**
** Returns the appended DOCTYPE element. You will normally use the returned
** element to add ENTITY elements, like
** $newDocType =& $xmlRoot->docType('spec SYSTEM "spec.dtd"');
** $newDocType->entity('doc.audience', 'public review and discussion');
*/
function & docType ($definition)
{
$newElement = new MiniXMLElementDocType($definition);
$appendedElement =& $this->appendChild($newElement);
return $appendedElement;
}
/*
** entity NAME VALUE
**
** Append a new <!ENTITY NAME "VALUE"> element as a child of this
** element.
** Returns the appended ENTITY element.
*/
function & entity ($name,$value)
{
$newElement = new MiniXMLElementEntity($name, $value);
$appendedEl =& $this->appendChild($newElement);
return $appendedEl;
}
/*
** cdata CONTENTS
**
** Append a new <![CDATA[ CONTENTS ]]> element as a child of this element.
** Returns the appended CDATA element.
**
*/
function & cdata ($contents)
{
$newElement = new MiniXMLElementCData($contents);
$appendedChild =& $this->appendChild($newElement);
return $appendedChild;
}
/* getValue
**
** Returns a string containing the value of all the element's
** child MiniXMLNodes (and all the MiniXMLNodes contained within
** it's child MiniXMLElements, recursively).
**
** Note: the seperator parameter remains officially undocumented
** since I'm not sure it will remain part of the API
*/
function getValue ($seperator=' ')
{
$retStr = '';
$valArray = array();
for($i=0; $i < $this->xnumChildren; $i++)
{
$value = $this->xchildren[$i]->getValue();
if (! is_null($value))
{
array_push($valArray, $value);
}
}
if (count($valArray))
{
$retStr = implode($seperator, $valArray);
}
return $retStr;
} /* end method getValue */
/* getElement NAME
** Searches the element and it's children for an element with name NAME.
**
** Returns a reference to the first MiniXMLElement with name NAME,
** if found, NULL otherwise.
**
** NOTE: The search is performed like this, returning the first
** element that matches:
**
** - Check this element for a match
** - Check this element's immediate children (in order) for a match.
** - Ask each immediate child (in order) to MiniXMLElement::getElement()
** (each child will then proceed similarly, checking all it's immediate
** children in order and then asking them to getElement())
*/
function &getElement ($name)
{
if (MINIXML_DEBUG > 0)
{
$elname = $this->name();
_MiniXMLLog("MiniXMLElement::getElement() called for $name on $elname.");
}
if (is_null($name))
{
return _MiniXMLError("MiniXMLElement::getElement() Must Pass Element name.");
}
/** Must only check children as checking $this results in an inability to
*** fetch nested objects with the same name
*** <tag>
*** <nested>
*** <nested>
*** Can't get here from tag or from the first 'nested'
*** </nested>
*** </nested>
*** </tag>
if (MINIXML_CASESENSITIVE > 0)
{
if (strcmp($this->xname, $name) == 0)
{
/* This element is it * /
return $this;
}
} else {
if (strcasecmp($this->xname,$name) == 0)
{
return $this;
}
}
***** end commented out section ****
*/
if (! $this->xnumChildren )
{
/* Not match here and and no kids - not found... */
return NULL;
}
/* Try each child (immediate children take priority) */
for ($i = 0; $i < $this->xnumChildren; $i++)
{
$childname = $this->xchildren[$i]->name();
if ($childname)
{
if (MINIXML_CASESENSITIVE > 0)
{
/* case sensitive matches only */
if (strcmp($name, $childname) == 0)
{
return $this->xchildren[$i];
}
} else {
/* case INsensitive matching */
if (strcasecmp($name, $childname) == 0)
{
return $this->xchildren[$i];
}
} /* end if case sensitive */
} /* end if child has a name */
} /* end loop over all my children */
/* Use beautiful recursion, daniel san */
for ($i = 0; $i < $this->xnumChildren; $i++)
{
$theelement =& $this->xchildren[$i]->getElement($name);
if ($theelement)
{
if (MINIXML_DEBUG > 0)
{
_MiniXMLLog("MiniXMLElement::getElement() returning element $theelement");
}
return $theelement;
}
}
/* Not found */
return NULL;
} /* end method getElement */
/* getElementByPath PATH
** Attempts to return a reference to the (first) element at PATH
** where PATH is the path in the structure (relative to this element) to
** the requested element.
**
** For example, in the document represented by:
**
** <partRateRequest>
** <vendor>
** <accessid user="myusername" password="mypassword" />
** </vendor>
** <partList>
** <partNum>
** DA42
** </partNum>
** <partNum>
** D99983FFF
** </partNum>
** <partNum>
** ss-839uent
** </partNum>
** </partList>
** </partRateRequest>
**
** $partRate =& $xmlDocument->getElement('partRateRequest');
**
** $accessid =& $partRate->getElementByPath('vendor/accessid');
**
** Will return what you expect (the accessid element with attributes user = "myusername"
** and password = "mypassword").
**
** BUT be careful:
** $accessid =& $partRate->getElementByPath('partList/partNum');
**
** will return the partNum element with the value "DA42". Other partNums are
** inaccessible by getElementByPath() - Use MiniXMLElement::getAllChildren() instead.
**
** Returns the MiniXMLElement reference if found, NULL otherwise.
*/
function &getElementByPath($path)
{
$names = split ("/", $path);
$element = $this;
foreach ($names as $elementName)
{
if ($element && $elementName) /* Make sure we didn't hit a dead end and that we have a name*/
{
/* Ask this element to get the next child in path */
$element =& $element->getElement($elementName);
}
}
return $element;
} /* end method getElementByPath */
/* numChildren [NAMED]
**
** Returns the number of immediate children for this element
**
** If the optional NAMED parameter is passed, returns only the
** number of immediate children named NAMED.
*/
function numChildren ($named=NULL)
{
if (is_null($named))
{
return $this->xnumElementChildren;
}
/* We require only children named '$named' */
$allkids =& $this->getAllChildren($named);
return count($allkids);
}
/* getAllChildren [NAME]
**
** Returns a reference to an array of all this element's MiniXMLElement children
**
** Note: although the MiniXMLElement may contain MiniXMLNodes as children, these are
** not part of the returned list.
**/
function &getAllChildren ($name=NULL)
{
$retArray = array();
$count = 0;
if (is_null($name))
{
/* Return all element children */
for($i=0; $i < $this->xnumChildren; $i++)
{
if (method_exists($this->xchildren[$i], 'MiniXMLElement'))
{
$retArray[$count++] =& $this->xchildren[$i];
}
}
} else {
/* Return only element children with name $name */
for($i=0; $i < $this->xnumChildren; $i++)
{
if (method_exists($this->xchildren[$i], 'MiniXMLElement'))
{
if (MINIXML_CASESENSITIVE > 0)
{
if ($this->xchildren[$i]->name() == $name)
{
$retArray[$count++] =& $this->xchildren[$i];
}
} else {
if (strcasecmp($this->xchildren[$i]->name(), $name) == 0)
{
$retArray[$count++] =& $this->xchildren[$i];
}
} /* end if case sensitive */
} /* end if child is a MiniXMLElement object */
} /* end loop over all children */
} /* end if specific name was requested */
return $retArray;
} /* end method getAllChildren */
function &insertChild (&$child, $idx=0)
{
if (! $this->_validateChild($child))
{
return;
}
/* Set the parent for the child element to this element if
** avoidLoops or MINIXML_AUTOSETPARENT is set
*/
if ($this->xavoidLoops || (MINIXML_AUTOSETPARENT > 0) )
{
if ($this->xparent == $child)
{
$cname = $child->name();
return _MiniXMLError("MiniXMLElement::insertChild() Tryng to append parent $cname as child of "
. $this->xname );
}
$child->parent($this);
}
$nextIdx = $this->xnumChildren;
$lastIdx = $nextIdx - 1;
if ($idx > $lastIdx)
{
if ($idx > $nextIdx)
{
$idx = $lastIdx + 1;
}
$this->xchildren[$idx] = $child;
$this->xnumChildren++;
if ($this->isElement($child))
{
$this->xnumElementChildren++;
}
} elseif ($idx >= 0)
{
$removed = array_splice($this->xchildren, $idx);
array_push($this->xchildren, $child);
$numRemoved = count($removed);
for($i=0; $i<$numRemoved; $i++)
{
array_push($this->xchildren, $removed[$i]);
}
$this->xnumChildren++;
if ($this->isElement($child))
{
$this->xnumElementChildren++;
}
} else {
$revIdx = (-1 * $idx) % $this->xnumChildren;
$newIdx = $this->xnumChildren - $revIdx;
if ($newIdx < 0)
{
return _MiniXMLError("Element::insertChild() Ended up with a negative index? ($newIdx)");
}
return $this->insertChild($child, $newIdx);
}
return $child;
}
/* appendChild CHILDELEMENT
**
** appendChild is used to append an existing MiniXMLElement object to
** this element's list.
**
** Returns a reference to the appended child element.
**
** NOTE: Be careful not to create loops in the hierarchy, eg
** $parent->appendChild($child);
** $child->appendChild($subChild);
** $subChild->appendChild($parent);
**
** If you want to be sure to avoid loops, set the MINIXML_AVOIDLOOPS define
** to 1 or use the avoidLoops() method (will apply to all children added with createChild())
*/
function &appendChild (&$child)
{
if (! $this->_validateChild($child))
{
_MiniXMLLog("MiniXMLElement::appendChild() Could not validate child, aborting append");
return NULL;
}
/* Set the parent for the child element to this element if
** avoidLoops or MINIXML_AUTOSETPARENT is set
*/
if ($this->xavoidLoops || (MINIXML_AUTOSETPARENT > 0) )
{
if ($this->xparent == $child)
{
$cname = $child->name();
return _MiniXMLError("MiniXMLElement::appendChild() Tryng to append parent $cname as child of "
. $this->xname );
}
$child->parent($this);
}
$this->xnumElementChildren++; /* Note that we're addind a MiniXMLElement child */
/* Add the child to the list */
$idx = $this->xnumChildren++;
$this->xchildren[$idx] =& $child;
return $this->xchildren[$idx];
} /* end method appendChild */
/* prependChild CHILDELEMENT
**
** prependChild is used to prepend an existing MiniXMLElement object to
** this element's list. The child will be positioned at the begining of
** the elements child list, thus it will be output first in the resulting XML.
**
** Returns a reference to the prepended child element.
*/
function &prependChild ($child)
{
if (! $this->_validateChild($child))
{
_MiniXMLLog("MiniXMLElement::prependChild - Could not validate child, aborting.");
return NULL;
}
/* Set the parent for the child element to this element if
** avoidLoops or MINIXML_AUTOSETPARENT is set
*/
if ($this->xavoidLoops || (MINIXML_AUTOSETPARENT > 0) )
{
if ($this->xparent == $child)
{
$cname = $child->name();
return _MiniXMLError("MiniXMLElement::prependChild() Tryng to append parent $cname as child of "
. $this->xname );
}
$child->parent($this);
}
$this->xnumElementChildren++; /* Note that we're adding a MiniXMLElement child */
/* Add the child to the list */
$idx = $this->xnumChildren++;
array_unshift($this->xchildren, $child);
return $this->xchildren[0];
} /* end method prependChild */
function _validateChild (&$child)
{
if (is_null($child))
{
return _MiniXMLError("MiniXMLElement::_validateChild() need to pass a non-NULL MiniXMLElement child.");
}
if (! method_exists($child, 'MiniXMLElement'))
{
return _MiniXMLError("MiniXMLElement::_validateChild() must pass a MiniXMLElement object to _validateChild.");
}
/* Make sure element is named */
$cname = $child->name();
if (is_null($cname))
{
_MiniXMLLog("MiniXMLElement::_validateChild() children must be named");
return 0;
}
/* Check for loops */
if ($child == $this)
{
_MiniXMLLog("MiniXMLElement::_validateChild() Trying to append self as own child!");
return 0;
} elseif ( $this->xavoidLoops && $child->parent())
{
_MiniXMLLog("MiniXMLElement::_validateChild() Trying to append a child ($cname) that already has a parent set "
. "while avoidLoops is on - aborting");
return 0;
}
return 1;
}
/* createChild ELEMENTNAME [VALUE]
**
** Creates a new MiniXMLElement instance and appends it to the list
** of this element's children.
** The new child element's name is set to ELEMENTNAME.
**
** If the optional VALUE (string or numeric) parameter is passed,
** the new element's text/numeric content will be set using VALUE.
**
** Returns a reference to the new child element
**
** Note: don't forget to use the =& (reference assignment) operator
** when calling createChild:
**
** $newChild =& $myElement->createChild('newChildName');
**
*/
function & createChild ($name, $value=NULL)
{
if (! $name)
{
return _MiniXMLError("MiniXMLElement::createChild() Must pass a NAME to createChild.");
}
if (! is_string($name))
{
return _MiniXMLError("MiniXMLElement::createChild() Name of child must be a STRING");
}
$child = new MiniXMLElement($name);
$appendedChild =& $this->appendChild($child);
if (! $appendedChild )
{
_MiniXMLLog("MiniXMLElement::createChild() '$name' child NOT appended.");
return NULL;
}
if (! is_null($value))
{
if (is_numeric($value))
{
$appendedChild->numeric($value);
} elseif (is_string($value))
{
$appendedChild->text($value);
}
}
$appendedChild->avoidLoops($this->xavoidLoops);
return $appendedChild;
} /* end method createChild */
/* removeChild CHILD
** Removes CHILD from this element's list of children.
**
** Returns the removed child, if found, NULL otherwise.
*/
function &removeChild (&$child)
{
if (! $this->xnumChildren)
{
if (MINIXML_DEBUG > 0)
{
_MiniXMLLog("Element::removeChild() called for element without any children.") ;
}
return NULL;
}
$foundChild = NULL;
$idx = 0;
while ($idx < $this->xnumChildren && ! $foundChild)
{
if ($this->xchildren[$idx] == $child)
{
$foundChild =& $this->xchildren[$idx];
} else {
$idx++;
}
}
if (! $foundChild)
{
if (MINIXML_DEBUG > 0)
{
_MiniXMLLog("Element::removeChild() No matching child found.") ;
}
return NULL;
}
array_splice($this->xchildren, $idx, 1);
$this->xnumChildren--;
if ($this->isElement($foundChild))
{
$this->xnumElementChildren--;
}
unset ($foundChild->xparent) ;
return $foundChild;
}
/* removeAllChildren
** Removes all children of this element.
**
** Returns an array of the removed children (which may be empty)
*/
function &removeAllChildren ()
{
$emptyArray = array();
if (! $this->xnumChildren)
{
return $emptyArray;
}
$retList =& $this->xchildren;
$idx = 0;
while ($idx < $this->xnumChildren)
{
unset ($retList[$idx++]->xparent);
}
$this->xchildren = array();
$this->xnumElementChildren = 0;
$this->xnumChildren = 0;
return $retList;
}
function & remove ()
{
$parent =& $this->parent();
if (!$parent)
{
_MiniXMLLog("XML::Mini::Element::remove() called for element with no parent set. Aborting.");
return NULL;
}
$removed =& $parent->removeChild($this);
return $removed;
}
/* parent NEWPARENT
**
** The parent() method is used to get/set the element's parent.
**
** If the NEWPARENT parameter is passed, sets the parent to NEWPARENT
** (NEWPARENT must be an instance of MiniXMLElement)
**
** Returns a reference to the parent MiniXMLElement if set, NULL otherwise.
**
** Note: This method is mainly used internally and you wouldn't normally need
** to use it.
** It get's called on element appends when MINIXML_AUTOSETPARENT or
** MINIXML_AVOIDLOOPS or avoidLoops() > 1
**
*/
function &parent (&$setParent)
{
if (! is_null($setParent))
{
/* Parents can only be MiniXMLElement objects */
if (! $this->isElement($setParent))
{
return _MiniXMLError("MiniXMLElement::parent(): Must pass an instance of MiniXMLElement to set.");
}
$this->xparent = $setParent;
}
return $this->xparent;
} /* end method parent */
/* avoidLoops SETTO
**
** The avoidLoops() method is used to get or set the avoidLoops flag for this element.
**
** When avoidLoops is true, children with parents already set can NOT be appended to any
** other elements. This is overkill but it is a quick and easy way to avoid infinite loops
** in the heirarchy.
**
** The avoidLoops default behavior is configured with the MINIXML_AVOIDLOOPS define but can be
** set on individual elements (and automagically all the element's children) with the
** avoidLoops() method.
**
** Returns the current value of the avoidLoops flag for the element.
**
*/
function avoidLoops ($setTo = NULL)
{
if (! is_null($setTo))
{
$this->xavoidLoops = $setTo;
}
return $this->xavoidLoops;
}
/* toString [SPACEOFFSET]
**
** toString returns an XML string based on the element's attributes,
** and content (recursively doing the same for all children)
**
** The optional SPACEOFFSET parameter sets the number of spaces to use
** after newlines for elements at this level (adding 1 space per level in
** depth). SPACEOFFSET defaults to 0.
**
** If SPACEOFFSET is passed as MINIXML_NOWHITESPACES.
** no \n or whitespaces will be inserted in the xml string
** (ie it will all be on a single line with no spaces between the tags.
**
** Returns the XML string.
**
**
** Note: Since the toString() method recurses into child elements and because
** of the MINIXML_NOWHITESPACES and our desire to avoid testing for this value
** on every element (as it does not change), here we split up the toString method
** into 2 subs: toStringWithWhiteSpaces(DEPTH) and toStringNoWhiteSpaces().
**
** Each of these methods, which are to be considered private (?), in turn recurses
** calling the appropriate With/No WhiteSpaces toString on it's children - thereby
** avoiding the test on SPACEOFFSET
*/
function toString ($depth=0)
{
if ($depth == MINIXML_NOWHITESPACES)
{
return $this->toStringNoWhiteSpaces();
} else {
return $this->toStringWithWhiteSpaces($depth);
}
}
function toStringWithWhiteSpaces ($depth=0)
{
$attribString = '';
$elementName = $this->xname;
$spaces = $this->_spaceStr($depth) ;
$retString = "$spaces<$elementName";
foreach ($this->xattributes as $attrname => $attrvalue)
{
$attribString .= "$attrname=\"$attrvalue\" ";
}
if ($attribString)
{
$attribString = rtrim($attribString);
$retString .= " $attribString";
}
if (! $this->xnumChildren)
{
/* No kids -> no sub-elements, no text, nothing - consider a <unary/> element */
$retString .= " />\n";
return $retString;
}
/* If we've gotten this far, the element has
** kids or text - consider a <binary>otherstuff</binary> element
*/
$onlyTxtChild = 0;
if ($this->xnumChildren == 1 && ! $this->xnumElementChildren)
{
$onlyTxtChild = 1;
}
if ($onlyTxtChild)
{
$nextDepth = 0;
$retString .= "> ";
} else {
$nextDepth = $depth+1;
$retString .= ">\n";
}
for ($i=0; $i < $this->xnumChildren ; $i++)
{
if (method_exists($this->xchildren[$i], 'toStringWithWhiteSpaces') )
{
$newStr = $this->xchildren[$i]->toStringWithWhiteSpaces($nextDepth);
if (! is_null($newStr))
{
if (! ( preg_match("/\n\$/", $newStr) || $onlyTxtChild) )
{
$newStr .= "\n";
}
$retString .= $newStr;
}
} else {
_MiniXMLLog("Invalid child found in $elementName ". $this->xchildren[$i]->name() );
} /* end if has a toString method */
} /* end loop over all children */
/* add the indented closing tag */
if ($onlyTxtChild)
{
$retString .= " </$elementName>\n";
} else {
$retString .= "$spaces</$elementName>\n";
}
return $retString;
} /* end method toString */
function toStringNoWhiteSpaces ()
{
$retString = '';
$attribString = '';
$elementName = $this->xname;
foreach ($this->xattributes as $attrname => $attrvalue)
{
$attribString .= "$attrname=\"$attrvalue\" ";
}
$retString = "<$elementName";
if ($attribString)
{
$attribString = rtrim($attribString);
$retString .= " $attribString";
}
if (! $this->xnumChildren)
{
/* No kids -> no sub-elements, no text, nothing - consider a <unary/> element */
$retString .= " />";
return $retString;
}
/* If we've gotten this far, the element has
** kids or text - consider a <binary>otherstuff</binary> element
*/
$retString .= ">";
/* Loop over all kids, getting associated strings */
for ($i=0; $i < $this->xnumChildren ; $i++)
{
if (method_exists($this->xchildren[$i], 'toStringNoWhiteSpaces') )
{
$newStr = $this->xchildren[$i]->toStringNoWhiteSpaces();
if (! is_null($newStr))
{
$retString .= $newStr;
}
} else {
_MiniXMLLog("Invalid child found in $elementName");
} /* end if has a toString method */
} /* end loop over all children */
/* add the indented closing tag */
$retString .= "</$elementName>";
return $retString;
} /* end method toStringNoWhiteSpaces */
/* toStructure
**
** Converts an element to a structure - either an array or a simple string.
**
** This method is used by MiniXML documents to perform their toArray() magic.
*/
function & toStructure ()
{
$retHash = array();
$contents = "";
$numAdded = 0;
for($i=0; $i< $this->xnumChildren; $i++)
{
if ($this->isElement($this->xchildren[$i]))
{
$name = $this->xchildren[$i]->name();
if (array_key_exists($name, $retHash))
{
if (! (is_array($retHash[$name]) && array_key_exists('_num', $retHash[$name])) )
{
$retHash[$name] = array($retHash[$name],
$this->xchildren[$i]->toStructure());
$retHash[$name]['_num'] = 2;
} else {
array_push($retHash[$name], $this->xchildren[$i]->toStructure() );
$retHash[$name]['_num']++;
}
} else {
$retHash[$name] = $this->xchildren[$i]->toStructure();
}
$numAdded++;
} else {
$contents .= $this->xchildren[$i]->getValue();
}
}
foreach ($this->xattributes as $attrname => $attrvalue)
{
#array_push($retHash, array($attrname => $attrvalue));
$retHash["_attributes"][$attrname] = $attrvalue;
$numAdded++;
}
if ($numAdded)
{
if (! empty($contents))
{
$retHash['_content'] = $contents;
}
return $retHash;
} else {
return $contents;
}
} // end toStructure() method
/* isElement ELEMENT
** Returns a true value if ELEMENT is an instance of MiniXMLElement,
** false otherwise.
**
** Note: Used internally.
*/
function isElement (&$testme)
{
if (is_null($testme))
{
return 0;
}
return method_exists($testme, 'MiniXMLElement');
}
/* isNode NODE
** Returns a true value if NODE is an instance of MiniXMLNode,
** false otherwise.
**
** Note: used internally.
*/
function isNode (&$testme)
{
if (is_null($testme))
{
return 0;
}
return method_exists($testme, 'MiniXMLNode');
}
/* createNode NODEVALUE [ESCAPEENTITIES]
**
** Private (?)
**
** Creates a new MiniXMLNode instance and appends it to the list
** of this element's children.
** The new child node's value is set to NODEVALUE.
**
** Returns a reference to the new child node.
**
** Note: You don't need to use this method normally - it is used
** internally when appending text() and such data.
**
*/
function & createNode (&$value, $escapeEntities=NULL)
{
$newNode = new MiniXMLNode($value, $escapeEntities);
$appendedNode =& $this->appendNode($newNode);
return $appendedNode;
}
/* appendNode CHILDNODE
**
** appendNode is used to append an existing MiniXMLNode object to
** this element's list.
**
** Returns a reference to the appended child node.
**
**
** Note: You don't need to use this method normally - it is used
** internally when appending text() and such data.
*/
function &appendNode (&$node)
{
if (is_null($node))
{
return _MiniXMLError("MiniXMLElement::appendNode() need to pass a non-NULL MiniXMLNode.");
}
if (! method_exists($node, 'MiniXMLNode'))
{
return _MiniXMLError("MiniXMLElement::appendNode() must pass a MiniXMLNode object to appendNode.");
}
if (MINIXML_AUTOSETPARENT)
{
if ($this->xparent == $node)
{
return _MiniXMLError("MiniXMLElement::appendnode() Tryng to append parent $cname as node of "
. $this->xname );
}
$node->parent($this);
}
$idx = $this->xnumChildren++;
$this->xchildren[$idx] = $node;
return $this->xchildren[$idx];
}
/* Destructor to keep things clean -- patch by Ilya */
function __destruct()
{
for ($i = 0; $i < count($this->xchildren); ++$i)
$this->xchildren[$i]->xparent = null;
}
} /* end MiniXMLElement class definition */
/***************************************************************************************************
****************************************************************************************************
*****
***** MiniXMLElementComment
*****
****************************************************************************************************
***************************************************************************************************/
/* The MiniXMLElementComment class is a specific extension of the MiniXMLElement class.
**
** It is used to create the special <!-- comment --> tags and an instance in created when calling
** $elementObject->comment('this is a comment');
**
** It's methods are the same as for MiniXMLElement - see those for documentation.
**/
class MiniXMLElementComment extends MiniXMLElement {
function MiniXMLElementComment ($name=NULL)
{
$this->MiniXMLElement('!--');
}
function toString ($depth=0)
{
if ($depth == MINIXML_NOWHITESPACES)
{
return $this->toStringNoWhiteSpaces();
} else {
return $this->toStringWithWhiteSpaces($depth);
}
}
function toStringWithWhiteSpaces ($depth=0)
{
$spaces = $this->_spaceStr($depth) ;
$retString = "$spaces<!-- \n";
if (! $this->xnumChildren)
{
/* No kids, no text - consider a <unary/> element */
$retString .= " -->\n";
return $retString;
}
/* If we get here, the element does have children... get their contents */
$nextDepth = $depth+1;
for ($i=0; $i < $this->xnumChildren ; $i++)
{
$retString .= $this->xchildren[$i]->toStringWithWhiteSpaces($nextDepth);
}
$retString .= "\n$spaces -->\n";
return $retString;
}
function toStringNoWhiteSpaces ()
{
$retString = '';
$retString = "<!-- ";
if (! $this->xnumChildren)
{
/* No kids, no text - consider a <unary/> element */
$retString .= " -->";
return $retString;
}
/* If we get here, the element does have children... get their contents */
for ($i=0; $i < $this->xnumChildren ; $i++)
{
$retString .= $this->xchildren[$i]->toStringNoWhiteSpaces();
}
$retString .= " -->";
return $retString;
}
}
/***************************************************************************************************
****************************************************************************************************
*****
***** MiniXMLElementCData
*****
****************************************************************************************************
***************************************************************************************************/
/* The MiniXMLElementCData class is a specific extension of the MiniXMLElement class.
**
** It is used to create the special <![CDATA [ data ]]> tags and an instance in created when calling
** $elementObject->cdata('data');
**
** It's methods are the same as for MiniXMLElement - see those for documentation.
**/
class MiniXMLElementCData extends MiniXMLElement {
function MiniXMLElementCData ($contents)
{
$this->MiniXMLElement('CDATA');
if (! is_null($contents))
{
$this->createNode($contents, 0) ;
}
}
function toStringNoWhiteSpaces ()
{
return $this->toString(MINIXML_NOWHITESPACES);
}
function toStringWithWhiteSpaces ($depth=0)
{
return $this->toString($depth);
}
function toString ($depth=0)
{
$spaces = '';
if ($depth != MINIXML_NOWHITESPACES)
{
$spaces = $this->_spaceStr($depth);
}
$retString = "$spaces<![CDATA[ ";
if (! $this->xnumChildren)
{
$retString .= "]]>\n";
return $retString;
}
for ( $i=0; $i < $this->xnumChildren; $i++)
{
$retString .= $this->xchildren[$i]->getValue();
}
$retString .= " ]]>\n";
return $retString;
}
}
/***************************************************************************************************
****************************************************************************************************
*****
***** MiniXMLElementDocType
*****
****************************************************************************************************
***************************************************************************************************/
/* The MiniXMLElementDocType class is a specific extension of the MiniXMLElement class.
**
** It is used to create the special <!DOCTYPE def [...]> tags and an instance in created when calling
** $elementObject->comment('');
**
** It's methods are the same as for MiniXMLElement - see those for documentation.
**/
class MiniXMLElementDocType extends MiniXMLElement {
var $dtattr;
function MiniXMLElementDocType ($attr)
{
$this->MiniXMLElement('DOCTYPE');
$this->dtattr = $attr;
}
function toString ($depth)
{
if ($depth == MINIXML_NOWHITESPACES)
{
return $this->toStringNoWhiteSpaces();
} else {
return $this->toStringWithWhiteSpaces($depth);
}
}
function toStringWithWhiteSpaces ($depth=0)
{
$spaces = $this->_spaceStr($depth);
$retString = "$spaces<!DOCTYPE " . $this->dtattr . " [\n";
if (! $this->xnumChildren)
{
$retString .= "]>\n";
return $retString;
}
$nextDepth = $depth + 1;
for ( $i=0; $i < $this->xnumChildren; $i++)
{
$retString .= $this->xchildren[$i]->toStringWithWhiteSpaces($nextDepth);
}
$retString .= "\n$spaces]>\n";
return $retString;
}
function toStringNoWhiteSpaces ()
{
$retString = "<!DOCTYPE " . $this->dtattr . " [ ";
if (! $this->xnumChildren)
{
$retString .= "]>\n";
return $retString;
}
for ( $i=0; $i < $this->xnumChildren; $i++)
{
$retString .= $this->xchildren[$i]->toStringNoWhiteSpaces();
}
$retString .= " ]>\n";
return $retString;
}
}
/***************************************************************************************************
****************************************************************************************************
*****
***** MiniXMLElementEntity
*****
****************************************************************************************************
***************************************************************************************************/
/* The MiniXMLElementEntity class is a specific extension of the MiniXMLElement class.
**
** It is used to create the special <!ENTITY name "val"> tags and an instance in created when calling
** $elementObject->comment('');
**
** It's methods are the same as for MiniXMLElement - see those for documentation.
**/
class MiniXMLElementEntity extends MiniXMLElement {
function MiniXMLElementEntity ($name, $value=NULL)
{
$this->MiniXMLElement($name);
if (! is_null ($value))
{
$this->createNode($value, 0);
}
}
function toString ($depth = 0)
{
$spaces = '';
if ($depth != MINIXML_NOWHITESPACES)
{
$spaces = $this->_spaceStr($depth);
}
$retString = "$spaces<!ENTITY " . $this->name();
if (! $this->xnumChildren)
{
$retString .= ">\n";
return $retString;
}
$nextDepth = ($depth == MINIXML_NOWHITESPACES) ? MINIXML_NOWHITESPACES
: $depth + 1;
$retString .= '"';
for ( $i=0; $i < $this->xnumChildren; $i++)
{
$retString .= $this->xchildren[$i]->toString(MINIXML_NOWHITESPACES);
}
$retString .= '"';
$retString .= " >\n";
return $retString;
}
function toStringNoWhiteSpaces ()
{
return $this->toString(MINIXML_NOWHITESPACES);
}
function toStringWithWhiteSpaces ($depth=0)
{
return $this->toString($depth);
}
}
?>