Skip to content
Browse files

* Fixes for bugs #89, #766, #905, #1125, #1253, #1414, #492, #555, #1238

* registerName() is now in XML_Tree_Node - a namespace can be registered for ANY node of the tree now
* Added XML Name checking for element and attribute names on addChild() (see XML_Tree::isValidName()) - XML_Tree_Node::error is set to the PEAR_Error for checking on the root element, a PEAR_Error is returned when using addChild();
* Added XML_Tree::getNodeNamespace() to get namespace for specified Node
* Added XML_Tree::getElementsByTagNameFromNode() - same as getElementsByTagName except it uses a specified node as the top of the tree in which to search


git-svn-id: http://svn.php.net/repository/pear/packages/XML_Tree/trunk@159129 c90b9560-bf6c-de11-be94-00142212c4b1
  • Loading branch information...
1 parent d712381 commit a5cd12edb4f121bdb668bad0b395981b27f151fe @dshafik dshafik committed May 20, 2004
Showing with 207 additions and 59 deletions.
  1. +83 −21 Tree.php
  2. +124 −38 Tree/Node.php
View
104 Tree.php
@@ -234,6 +234,7 @@ function &getTreeFromFile ()
*/
function &getTreeFromString($str)
{
+ $this->i = null;
$this->folding = false;
$this->XML_Parser(null, 'event');
$this->cdata = null;
@@ -293,7 +294,7 @@ function endHandler($xp, $elem)
$node =& $this->$obj_id;
// mixed contents
if (count($node->children) > 0) {
- if (trim($this->cdata)) {
+ if (trim($this->cdata) != '') {
$node->children[] = &new XML_Tree_Node(null, $this->cdata);
}
} else {
@@ -303,6 +304,15 @@ function endHandler($xp, $elem)
$parent =& $this->$parent_id;
// attach the node to its parent node children array
$parent->children[] = $node;
+ } else {
+ $node =& $this->obj1;
+ if (count($node->children) > 0) {
+ if (trim($this->cdata)) {
+ $node->children[] = &new XML_Tree_Node(null, $this->cdata);
+ }
+ } else {
+ $node->setContent($this->cdata);
+ }
}
$this->cdata = null;
return null;
@@ -319,9 +329,7 @@ function endHandler($xp, $elem)
*/
function cdataHandler($xp, $data)
{
- if (trim($data) != '') {
- $this->cdata .= $data;
- }
+ $this->cdata .= $data;
}
/**
@@ -330,11 +338,11 @@ function cdataHandler($xp, $data)
* @return object XML_Tree copy of this node.
* @access public
*/
- function clone()
+ function cloneTree()
{
$clone = new XML_Tree($this->filename, $this->version);
if (!is_null($this->root)) {
- $clone->root = $this->root->clone();
+ $clone->root = $this->root->cloneTree();
}
// clone all other vars
@@ -374,9 +382,9 @@ function &get()
{
$out = '<?xml version="' . $this->version . "\"?>\n";
if (!is_null($this->root))
- {
- if(!is_object($this->root) || (get_class($this->root) != 'xml_tree_node'))
- return $this->raiseError("Bad XML root node");
+ {
+ if(!is_object($this->root) || (strtolower(get_class($this->root)) != 'xml_tree_node'))
+ return $this->raiseError("Bad XML root node");
$out .= $this->root->get();
}
return $out;
@@ -395,15 +403,24 @@ function &getName($name) {
}
/**
- * Register a namespace.
- *
- * @param string $name namespace
- * @param string $path path
- *
- * @access public
- */
- function registerName($name, $path) {
- $this->namespace[$name] = $path;
+ * Get A Nodes Namespace
+ */
+
+ function getNodeNamespace(&$node) {
+ $name_parts = explode(':',$node->name);
+ if (sizeof($name_parts) > 1) {
+ $namespace = $name_parts[0];
+ } else {
+ $namespace = '';
+ }
+
+ if (isset($node->namespace[$namespace])) {
+ return $node->namespace[$namespace];
+ } elseif (isset($this->root->namespace[$namespace])) {
+ return $this->root->namespace[$namespace];
+ } else {
+ return '';
+ }
}
/**
@@ -456,16 +473,61 @@ function &getElementsByTagName($tagName)
if (empty($tagName)) {
return $this->raiseError('Empty tag name');
}
- if (sizeof($this->children)==0) {
- return null;
+ $result = array();
+ foreach ($this->root->children as $child) {
+ if ($child->name == $tagName) {
+ $result[] = $child;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Gets all children that match a given tag name from node
+ *
+ * @param string $tagName Tag Name
+ * @param object &$node Node in which to search
+ * @see XML_Tree::getElementsByTagName()
+ * @return array An array of found Node objects, empty is none found.
+ * @access public
+ * @author Pierre-Alain Joye <paj@pearfr.org>
+ * @author Davey Shafik <davey@php.net>
+ */
+
+ function &getElementsByTagNameFromNode($tagName, &$node)
+ {
+ if (empty($tagName)) {
+ return $this->raiseError('Empty tag name');
}
$result = array();
- foreach ($this->children as $child) {
+ foreach ($node->children as $child) {
if ($child->name == $tagName) {
$result[] = $child;
}
}
return $result;
}
+
+
+ /**
+ * Checks if $name is a valid XML name
+ *
+ * @static
+ * @param string $name String to check for validity as an XML Name
+ * @return mixed
+ */
+
+ function isValidName($name, $type) {
+ // check for invalid starting character
+ if (!preg_match("/[[:alpha:]_]/", $name{0})) {
+ return new PEAR_Error( ucfirst($type) . " ('$name') has an invalid name, an XML name may only start with a letter or underscore");
+ }
+
+ if (!preg_match("/^([a-zA-Z_]([a-zA-Z0-9_\-\.]*)?:)?[a-zA-Z_]([a-zA-Z0-9_\-\.]+)?$/", $name)) {
+ return new PEAR_Error( ucfirst($type) . " ('$name') has an invalid name, an XML name may only contain alphanumeric chars, period, hyphen, colon and underscores");
+ }
+
+ return true;
+ }
}
?>
View
162 Tree/Node.php
@@ -28,44 +28,80 @@
* @package XML_Tree
* @version 1.0 16-Aug-2001
*/
+
class XML_Tree_Node {
/**
* Attributes of this node
*
* @var array
*/
+
var $attributes;
/**
* Children of this node
*
* @var array
*/
+
var $children;
/**
* Content (text) of this node
*
* @var string
*/
+
var $content;
/**
* Name of the node
*
* @var string
*/
+
var $name;
/**
+ * Namespaces for the node
+ *
+ * @var array
+ */
+
+
+ var $namespaces = array();
+
+ /**
+ * Stores PEAR_Error upon error
+ *
+ * @var object PEAR_Error
+ */
+
+ var $error = null;
+
+
+ /**
* Constructor
*
* @param string name Node name
* @param string content Node content (text)
* @param array attributes Attribute-hash for the node
*/
+
function XML_Tree_Node($name, $content = '', $attributes = array(), $lineno = null)
{
+ $check_name = XML_Tree::isValidName($name, 'element');
+ if (PEAR::isError($check_name)) {
+ $this->error =& $check_name;
+ return;
+ }
+ foreach ($attributes as $attribute_name => $value) {
+ $error = XML_Tree::isValidName($attribute_name, 'Attribute');
+ if (PEAR::isError($error)) {
+ $this->error =& $error;
+ return;
+ }
+ }
$this->name = $name;
$this->setContent($content);
$this->attributes = $attributes;
@@ -85,6 +121,7 @@ function XML_Tree_Node($name, $content = '', $attributes = array(), $lineno = nu
* @return object reference to new child node
* @access public
*/
+
function &addChild($child, $content = '', $attributes = array(), $lineno = null)
{
$index = sizeof($this->children);
@@ -98,7 +135,12 @@ function &addChild($child, $content = '', $attributes = array(), $lineno = null)
$this->children[$index] = $child->root->getElement();
}
} else {
- $this->children[$index] = new XML_Tree_Node($child, $content, $attributes, $lineno);
+ $node = new XML_Tree_Node($child, $content, $attributes, $lineno);
+ if (PEAR::isError($node->error)) {
+ return $node->error;
+ }
+
+ $this->children[$index] = $node;
}
return $this->children[$index];
@@ -111,23 +153,25 @@ function &addChild($child, $content = '', $attributes = array(), $lineno = null)
* @return object Reference to the cloned copy.
* @access public
*/
- function &clone()
+
+ function &cloneNode()
{
$clone = new XML_Tree_Node($this->name,$this->content,$this->attributes);
$max_child=count($this->children);
for($i=0;$i<$max_child;$i++) {
- $clone->children[]=$this->children[$i]->clone();
+ $clone->children[]=$this->children[$i]->cloneNode();
}
/* for future use....
- // clone all other vars
- $temp=get_object_vars($this);
- foreach($temp as $varname => $value)
- if (!in_array($varname,array('name','content','attributes','children')))
- $clone->$varname=$value;
- */
-
+ // clone all other vars
+ $temp=get_object_vars($this);
+ foreach($temp as $varname => $value)
+ if (!in_array($varname,array('name','content','attributes','children')))
+ $clone->$varname=$value;
+ */
+
+
return $clone;
}
@@ -149,6 +193,7 @@ function &clone()
* @return Reference to the newly inserted node, or PEAR_Error upon insertion error.
* @access public
*/
+
function &insertChild($path,$pos,&$child, $content = '', $attributes = array())
{
$parent =& $this->getNodeAt($path);
@@ -165,29 +210,29 @@ function &insertChild($path,$pos,&$child, $content = '', $attributes = array())
}
if (is_object($child)) { // child is an object
- // insert a single node
- if (strtolower(get_class($child)) == 'xml_tree_node') {
- array_splice($this->children, $pos, 0, 'dummy');
- if ($pos < 0) {
- $pos = count($this->children) + $pos - 1;
- }
- $this->children[$pos] = &$child;
- // insert a tree i.e insert root-element of tree
- } elseif (strtolower(get_class($child)) == 'xml_tree' && isset($child->root)) {
- array_splice($this->children, $pos, 0, 'dummy');
- if ($pos < 0) {
- $pos = count($this->children) + $pos - 1;
- }
- $this->children[$pos] = $child->root;
- } else {
- return new PEAR_Error("Bad node (must be a XML_Tree or an XML_Tree_Node)");
+ // insert a single node
+ if (strtolower(get_class($child)) == 'xml_tree_node') {
+ array_splice($this->children, $pos, 0, 'dummy');
+ if ($pos < 0) {
+ $pos = count($this->children) + $pos - 1;
}
- } else { // child offered is a string
+ $this->children[$pos] = &$child;
+ // insert a tree i.e insert root-element of tree
+ } elseif (strtolower(get_class($child)) == 'xml_tree' && isset($child->root)) {
array_splice($this->children, $pos, 0, 'dummy');
if ($pos < 0) {
$pos = count($this->children) + $pos - 1;
}
- $this->children[$pos] = new XML_Tree_Node($child, $content, $attributes);
+ $this->children[$pos] = $child->root;
+ } else {
+ return new PEAR_Error("Bad node (must be a XML_Tree or an XML_Tree_Node)");
+ }
+ } else { // child offered is a string
+ array_splice($this->children, $pos, 0, 'dummy');
+ if ($pos < 0) {
+ $pos = count($this->children) + $pos - 1;
+ }
+ $this->children[$pos] = new XML_Tree_Node($child, $content, $attributes);
}
return $this;
}
@@ -202,6 +247,7 @@ function &insertChild($path,$pos,&$child, $content = '', $attributes = array())
* @return mixed The removed node, or PEAR_Error upon removal error.
* @access public
*/
+
function &removeChild($pos)
{
if (($pos < -count($this->children)) || ($pos >= count($this->children))) {
@@ -213,17 +259,32 @@ function &removeChild($pos)
}
/**
+ * Register a namespace.
+ *
+ * @param string $name namespace
+ * @param string $path path
+ *
+ * @access public
+ */
+
+ function registerName($name, $path) {
+ $this->namespace[$name] = $path;
+ }
+
+ /**
* Returns text representation of this node.
*
* @return string text (xml) representation of this node. Each tag is
* indented according to its level.
* @access public
*/
+
function &get()
{
static $deep = -1;
static $do_ident = true;
$deep++;
+ $empty = false;
if ($this->name !== null) {
$ident = str_repeat(' ', $deep);
if ($do_ident) {
@@ -234,9 +295,24 @@ function &get()
foreach ($this->attributes as $name => $value) {
$out .= ' ' . $name . '="' . $value . '"';
}
-
- $out .= '>' . $this->content;
-
+
+ if (isset($this->namespace) && (is_array($this->namespace))) {
+ foreach ($this->namespace as $qualifier => $uri) {
+ if ($qualifier == '') {
+ $out .= " xmlns='$uri'";
+ } else {
+ $out .= " xmlns:$qualifier='$uri'";
+ }
+ }
+ }
+
+ if ($this->content == '' && sizeof($this->children) === 0 && $deep != 0) {
+ $out .= ' />';
+ $empty = true;
+ } else {
+ $out .= '>' . $this->content;
+ }
+
if (sizeof($this->children) > 0) {
$out .= "\n";
foreach ($this->children as $child) {
@@ -245,9 +321,10 @@ function &get()
} else {
$ident = '';
}
- if ($do_ident) {
+
+ if ($do_ident && $empty != true) {
$out .= $ident . '</' . $this->name . ">\n";
- } else {
+ } elseif ($empty != true) {
$out .= '</' . $this->name . '>';
}
$do_ident = true;
@@ -267,10 +344,11 @@ function &get()
* @return string attribute, or null if attribute is unset.
* @access public
*/
+
function getAttribute($name)
{
- if (isset($this->attributes[strtolower($name)])) {
- return $this->attributes[strtolower($name)];
+ if (isset($this->attributes[$name])) {
+ return $this->attributes[$name];
}
return null;
}
@@ -283,9 +361,10 @@ function getAttribute($name)
*
* @access public
*/
+
function setAttribute($name, $value = '')
{
- $this->attributes[strtolower($name)] = $value;
+ $this->attributes[$name] = $value;
}
/**
@@ -295,10 +374,11 @@ function setAttribute($name, $value = '')
*
* @access public
*/
+
function unsetAttribute($name)
{
- if (isset($this->attributes[strtolower($name)])) {
- unset($this->attributes[strtolower($name)]);
+ if (isset($this->attributes[$name])) {
+ unset($this->attributes[$name]);
}
}
@@ -309,6 +389,7 @@ function unsetAttribute($name)
*
* @access public
*/
+
function setContent(&$content)
{
$this->content = $this->encodeXmlEntities($content);
@@ -325,6 +406,7 @@ function setContent(&$content)
* be found.
* @access public
*/
+
function &getElement($path)
{
if (!is_array($path)) {
@@ -360,6 +442,7 @@ function &getElement($path)
* returned.
* @access public
*/
+
function &getNodeAt($path)
{
if (is_string($path))
@@ -399,6 +482,7 @@ function &getNodeAt($path)
* @return string xml
* @access public
*/
+
function encodeXmlEntities($xml)
{
$xml = str_replace(array('ü', 'Ü', 'ö',
@@ -438,6 +522,7 @@ function encodeXmlEntities($xml)
* @return string Decoded text
* @access public
*/
+
function decodeXmlEntities($xml)
{
static $trans_tbl = null;
@@ -460,6 +545,7 @@ function decodeXmlEntities($xml)
*
* @access public
*/
+
function dump() {
echo $this->get();
}

0 comments on commit a5cd12e

Please sign in to comment.
Something went wrong with that request. Please try again.