Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
Tree.php
1 <?php
2 //
3 // +----------------------------------------------------------------------+
4 // | PEAR :: XML_Tree |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2003 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.02 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/2_02.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Authors: Bernd Römer <berndr@bonn.edu> |
17 // | Sebastian Bergmann <sb@sebastian-bergmann.de> |
18 // | Tomas V.V.Cox <cox@idecnet.com> |
19 // | Michele Manzato <michele.manzato@verona.miz.it> |
20 // +----------------------------------------------------------------------+
21 //
22 // $Id: Tree.php,v 1.7 2010/07/15 04:43:37 csmith Exp $
23 //
24 
25 // MM: See line 293 for why we override this file
26 
27 require_once 'XML/Parser.php';
28 require_once 'XML/Tree/Node.php';
29 
51 class XML_Tree extends XML_Parser
52 {
58  var $file = NULL;
59 
65  var $filename = '';
66 
72  var $namespace = array();
73 
79  var $root = NULL;
80 
86  var $version = '1.0';
87 
94  var $use_cdata_sections = false;
95 
102  function XML_Tree($filename = '', $version = '1.0')
103  {
104  $this->filename = $filename;
105  $this->version = $version;
106  }
107 
114  function useCdataSections()
115  {
116  $this->use_cdata_sections = true;
117  }
118 
126  function &getRoot()
127  {
128  if (!is_null($this->root)) {
129  return $this->root;
130  }
131  return $this->raiseError("No root");
132  }
133 
142  function &addRoot($name, $content = '', $attributes = array(), $lineno = null)
143  {
144  $this->root = new XML_Tree_Node($name, $content, $attributes, $lineno);
145  return $this->root;
146  }
147 
167  function &insertChild($path, $pos, $child, $content = '', $attributes = array())
168  {
169  $parent =& $this->getNodeAt($path);
170  if (PEAR::isError($parent)) {
171  return $parent;
172  }
173 
174  $x =& $parent->insertChild(null, $pos, $child, $content, $attributes);
175 
176  if (!PEAR::isError($x)) {
177  // update namespace to maintain namespace integrity
178  $count = count($path);
179  foreach ($this->namespace as $key => $val) {
180  if ((array_slice($val,0,$count)==$path) && ($val[$count]>=$pos)) {
181  $this->namespace[$key][$count]++;
182  }
183  }
184  }
185  return $x;
186  }
187 
201  function &removeChild($path, $pos)
202  {
203  $parent =& $this->getNodeAt($path);
204  if (PEAR::isError($parent)) {
205  return $parent;
206  }
207 
208  $x =& $parent->removeChild($pos);
209 
210  if (!PEAR::isError($x)) {
211  // Update namespace to maintain namespace integrity
212  $count=count($path);
213  foreach($this->namespace as $key => $val) {
214  if (array_slice($val,0,$count)==$path) {
215  if ($val[$count]==$pos) {
216  unset($this->namespace[$key]); break;
217  }
218  if ($val[$count]>$pos) {
219  $this->namespace[$key][$count]--;
220  }
221  }
222  }
223  }
224 
225  return $x;
226  }
227 
234  function &getTreeFromFile ()
235  {
236  $this->folding = false;
237  $this->XML_Parser(null, 'event');
238  $err = $this->setInputFile($this->filename);
239  if (PEAR::isError($err)) {
240  return $err;
241  }
242  $this->cdata = null;
243  $err = $this->parse();
244  if (PEAR::isError($err)) {
245  return $err;
246  }
247  return $this->root;
248  }
249 
256  function &getTreeFromString($str)
257  {
258  $this->i = null;
259  $this->folding = false;
260  $this->XML_Parser(null, 'event');
261  $this->cdata = null;
262  $err = $this->parseString($str);
263  if (PEAR::isError($err)) {
264  return $err;
265  }
266  return $this->root;
267  }
268 
279  function startHandler($xp, $elem, &$attribs)
280  {
281  $lineno = xml_get_current_line_number($xp);
282  // root elem
283  if (!isset($this->i)) {
284  $this->obj1 =& $this->addRoot($elem, null, $attribs, $lineno);
285  $this->i = 2;
286  } else {
287  // mixed contents
288  if (!empty($this->cdata)) {
289  $parent_id = 'obj' . ($this->i - 1);
290  $parent =& $this->$parent_id;
291  // Squiz: (MM/LWr) We have to handle this differently because we
292  // don't want XML_Tree_Node objects created for whitespace
293  // between nodes. But it's still valid when it's not whitespace...
294  if (trim($this->cdata) != '') {
295  $parent->children[] = new XML_Tree_Node(null, $this->cdata, null, $lineno);
296  }
297  }
298  $obj_id = 'obj' . $this->i++;
299  $this->$obj_id = new XML_Tree_Node($elem, null, $attribs, $lineno);
300  }
301  $this->cdata = null;
302  return null;
303  }
304 
314  function endHandler($xp, $elem)
315  {
316  $this->i--;
317  if ($this->i > 1) {
318  $obj_id = 'obj' . $this->i;
319  // recover the node created in StartHandler
320  $node =& $this->$obj_id;
321  // mixed contents
322  if (count($node->children) > 0) {
323  if (trim($this->cdata) != '') {
324  $node->children[] = new XML_Tree_Node(null, $this->cdata);
325  }
326  } else {
327  $node->setContent($this->cdata);
328  }
329  $parent_id = 'obj' . ($this->i - 1);
330  $parent =& $this->$parent_id;
331  // attach the node to its parent node children array
332  $parent->children[] = $node;
333  } else {
334  $node =& $this->obj1;
335  if (count($node->children) > 0) {
336  if (trim($this->cdata)) {
337  $node->children[] = new XML_Tree_Node(null, $this->cdata);
338  }
339  } else {
340  $node->setContent($this->cdata);
341  }
342  }
343  $this->cdata = null;
344  return null;
345  }
346 
356  function cdataHandler($xp, $data)
357  {
358  $this->cdata .= $data;
359  }
360 
367  function cloneTree()
368  {
369  $clone = new XML_Tree($this->filename, $this->version);
370  if (!is_null($this->root)) {
371  $clone->root = $this->root->cloneTree();
372  }
373 
374  // clone all other vars
375  $temp = get_object_vars($this);
376  foreach($temp as $varname => $value) {
377  if (!in_array($varname,array('filename','version','root'))) {
378  $clone->$varname=$value;
379  }
380  }
381  return $clone;
382  }
383 
393  function dump($xmlHeader = false)
394  {
395  if ($xmlHeader) {
396  header('Content-type: text/xml');
397  }
398  echo $this->get($this->use_cdata_sections);
399  }
400 
407  function &get()
408  {
409  $out = '<?xml version="' . $this->version . "\"?>\n";
410 
411  if (!is_null($this->root))
412  {
413  if(!is_object($this->root) || (strtolower(get_class($this->root)) != 'xml_tree_node'))
414  return $this->raiseError("Bad XML root node");
415  $out .= $this->root->get($this->use_cdata_sections);
416  }
417  return $out;
418  }
419 
428  function &getName($name) {
429  return $this->root->getElement($this->namespace[$name]);
430  }
431 
436  function getNodeNamespace(&$node) {
437  $name_parts = explode(':',$node->name);
438  if (sizeof($name_parts) > 1) {
439  $namespace = $name_parts[0];
440  } else {
441  $namespace = '';
442  }
443 
444  if (isset($node->namespace[$namespace])) {
445  return $node->namespace[$namespace];
446  } elseif (isset($this->root->namespace[$namespace])) {
447  return $this->root->namespace[$namespace];
448  } else {
449  return '';
450  }
451  }
452 
465  function &getNodeAt($path)
466  {
467  if (is_null($this->root)){
468  return $this->raiseError("XML_Tree hasn't a root node");
469  }
470  if (is_string($path))
471  $path = explode("/", $path);
472  if (sizeof($path) == 0) {
473  return $this->raiseError("Path to node is empty");
474  }
475  $path1 = $path;
476  $rootName = array_shift($path1);
477  if ($this->root->name != $rootName) {
478  return $this->raiseError("Path does not match the document root");
479  }
480  $x =& $this->root->getNodeAt($path1);
481  if (!PEAR::isError($x)) {
482  return $x;
483  }
484  // No node with that name found
485  return $this->raiseError("Bad path to node: [".implode('/', $path)."]");
486  }
487 
498  function &getElementsByTagName($tagName)
499  {
500  if (empty($tagName)) {
501  return $this->raiseError('Empty tag name');
502  }
503  $result = array();
504  foreach ($this->root->children as $child) {
505  if ($child->name == $tagName) {
506  $result[] = $child;
507  }
508  }
509  return $result;
510  }
511 
524  function &getElementsByTagNameFromNode($tagName, &$node)
525  {
526  if (empty($tagName)) {
527  return $this->raiseError('Empty tag name');
528  }
529  $result = array();
530  foreach ($node->children as $child) {
531  if ($child->name == $tagName) {
532  $result[] = $child;
533  }
534  }
535  return $result;
536  }
537 
538 
547  function isValidName($name, $type) {
548  if (trim($name) == '') {
549  return true;
550  }
551 
552  // check for invalid starting character
553  if (!preg_match("/[[:alpha:]_]/", $name{0})) {
554  return new PEAR_Error( ucfirst($type) . " ('$name') has an invalid name, an XML name may only start with a letter or underscore");
555  }
556 
557  if (!preg_match("/^([a-zA-Z_]([a-zA-Z0-9_\-\.]*)?:)?[a-zA-Z_]([a-zA-Z0-9_\-\.]+)?$/", $name)) {
558  return new PEAR_Error( ucfirst($type) . " ('$name') has an invalid name, an XML name may only contain alphanumeric chars, period, hyphen, colon and underscores");
559  }
560 
561  return true;
562  }
563 }
564 ?>