cb.xml.domit.php
上传用户:stephen_wu
上传日期:2008-07-05
资源大小:1757k
文件大小:23k
源码类别:

网络

开发平台:

Unix_Linux

  1. <?php
  2. /**
  3. * Precise emulation of PHP SimpleXMLElement in PHP < 5.1.3
  4. * @version $Id:$
  5. * @author Beat
  6. * @copyright (C) 2007 Beat and Lightning MultiCom SA, 1009 Pully, Switzerland
  7. * @license Lightning Proprietary. See licence. Allowed for free use within CB and for CB plugins.
  8. */
  9. // Check to ensure this file is within the rest of the framework
  10. if ( ! ( defined( '_VALID_CB' ) || defined( '_JEXEC' ) || defined( '_VALID_MOS' ) ) ) { die( 'Direct Access to this location is not allowed.' ); }
  11. if( defined('JXML_TEST_DOMIT') || ! function_exists( 'xml_parser_create' ) ) {
  12. global $_CB_framework;
  13. $domitPath = $_CB_framework->getCfg('absolute_path') . '/includes/domit/xml_domit_lite_include.php';
  14. if ( file_exists( $domitPath ) ) {
  15. require_once( $domitPath );
  16. } else {
  17. die("<font color='red'>". $_CB_framework->getCfg( 'absolute_path' ) . "/includes/domit/ does not exist! This is normal with mambo 4.5.0 and 4.6.1 and php 4 without xml parser library binded. Community Builder needs this library for handling plugins.<br />  You Must Manually do the following:<br /> 1.) create " . $_CB_framework->getCfg( 'absolute_path' ) . "/includes/domit/ directory <br /> 2.) chmod it to 777 <br /> 3.) copy corresponding content of a mambo 4.5.2 directory.</font><br /><br />n");
  18. }
  19. }
  20. /**
  21.  * Class to emulate precisely PHP SimpleXMLElement in PHP < 5.1.3
  22.  *
  23.  * @author Beat
  24.  * @copyright Beat 2007
  25.  * @licence allowed for free use within CB and for CB plugins
  26.  */
  27. class FixedSimpleXML {
  28. /** Attributes of this element
  29. * @var array of string */
  30. var $_attributes = array();
  31. /** The name of the element
  32. * @var string */
  33. var $_name = '';
  34. /** The data the element contains
  35. * @var string */
  36. var $_data = '';
  37. /** The parent of the element
  38. * @var FixedSimpleXML */
  39. var $_parent = null;
  40. /** Array of references to the objects of all direct children of this XML object
  41. * @var array of FixedSimpleXML */
  42. var $_children = array();
  43. /**
  44.  * Constructor, creates tree and parses XML
  45.  * All parameters are equivalent to PHP 5 SimpleXML, except last 2
  46.  *
  47.  * @param  string          $data
  48.  * @param  int             $options
  49.  * @param  boolean         $data_is_url
  50.  * @param  string          $ns
  51.  * @param  boolean         $is_prefix
  52.  * @param  string          $name         used internally to creat tree:  name
  53.  * @param  array           $attrs        used internally to create tree: attributes
  54.  * @return FixedSimpleXML
  55.  */
  56. function FixedSimpleXML( $data, $options = null, $data_is_url = false, $ns = null, $is_prefix = false, $name = null, $attrs = array() )
  57. {
  58. if ( $data ) {
  59. $this->_xmlHelper =& new SimpleXML_Helper( $this,  $data, $options, $data_is_url, $ns, $is_prefix );
  60. } else {
  61. //Make the keys of the attr array lower case, and store the value
  62. $this->_attributes = $attrs; // array_change_key_case($attrs, CASE_LOWER);
  63. $this->_name = $name;
  64. }
  65. }
  66. /**
  67.  * Get an element in the document by / separated path
  68.  * or FALSE
  69.  *
  70.  * @param string $path The / separated path to the element
  71.  * @return CBSimpleXMLElement or FALSE
  72.  */
  73. function & getElementByPath( $path ) {
  74. $parts = explode( '/', trim($path, '/') );
  75. $tmp =& $this;
  76. foreach ($parts as $node) {
  77. $found = false;
  78. foreach ( $tmp->_children as $k => $child ) {
  79. if ($child->_name == $node) {
  80. $tmp =& $tmp->_children[$k];
  81. $found = true;
  82. break;
  83. }
  84. }
  85. if ( ! $found ) break;
  86. }
  87. if ( $found ) {
  88. return $tmp;
  89. } else {
  90. $false = false;
  91. return $false;
  92. }
  93. }
  94. /**
  95.  * Get the name of the element
  96.  *
  97.  * @return string
  98.  */
  99. function name() {
  100. return $this->_name;
  101. }
  102. /**
  103.  * Get the an attribute of the element
  104.  *
  105.  * @param  string  $attribute  The name of the attribute
  106.  * @return mixed   string      If an attribute is given will return the attribute if it exist.
  107.  *                 boolean     Null if attribute is given but doesn't exist
  108.  *     array       If no attribute is given will return the complete attributes array
  109.  */
  110. function attributes( $attribute = null ) {
  111. if( ! isset( $attribute ) ) {
  112. return $this->_attributes;
  113. }
  114. return ( isset( $this->_attributes[$attribute] ) ? $this->_attributes[$attribute] : null );
  115. }
  116. /**
  117.  * Get the data of the element
  118.  *
  119.  * @return string
  120.  */
  121. function data( ) {
  122. return $this->_data;
  123. }
  124. /**
  125.  * Set the data of the element
  126.  * WARNING: Not PHP SimpleXML compatible
  127.  *
  128.  * @param string $data
  129.  * @return string
  130.  */
  131. function setData( $data ) {
  132. $this->_data = $data;
  133. }
  134. /**
  135.  * Get the children of the element
  136.  *
  137.  * @return array FixedSimpleXML
  138.  * 
  139.  */
  140. function & children( ) {
  141. return $this->_children;
  142. }
  143.  /**
  144.  * Adds an attribute to the element, override if it already exists
  145.  *
  146.  * @param string $name
  147.  * @param array  $attrs
  148.  */
  149. function addAttribute( $name, $value ) {
  150. $this->_attributes[$name] = $value;
  151. }
  152. /**
  153.  * Searches this SimpleXML node for children matching the XPath path.
  154.  * Implements a usefull subset of the syntax of http://www.w3.org/TR/xpath:
  155.  *
  156.  * Abreviated syntax: works:
  157.    * para  selects the para element children of the context node
  158.    * *     selects all element children of the context node
  159.    * para[1] selects the first para child of the context node
  160.    * * / para selects all para grandchildren of the context node ( space added around / to not break comment
  161.    * /doc/chapter[5]/section[2] selects the second section of the fifth chapter of the doc
  162.    * chapter//para selects the para element descendants of the chapter element children of the context node
  163.    * //olist/item selects all the item elements in the same document as the context node that have an olist parent
  164.    * . selects the context node
  165.    * .//para selects the para element descendants of the context node
  166.    * .. selects the parent of the context node
  167.    * para[@type="warning"] selects all para children of the context node that have a type attribute with value warning
  168.    * para[@type="warning"][5] selects the fifth para child of the context node that has a type attribute with value warning
  169.    * para[5][@type="warning"] selects the fifth para child of the context node if that child has a type attribute with value warning
  170.    * chapter[title="Introduction"] selects the chapter children of the context node that have one or more title children with string-value equal to Introduction
  171.  * DOES NOT WORK yet:
  172.    * //para selects all the para descendants of the document root and thus selects all para elements in the same document as the context node
  173.    * //para selects all descendant para elements that are the first para children of their parents
  174.    * div//para select all para descendants of div children
  175.    * para[last()] selects the last para child of the context node
  176.    * chapter[title] selects the chapter children of the context node that have one or more title children
  177.    * employee[@secretary and @assistant] selects all the employee children of the context node that have both a secretary attribute and an assistant attribute
  178.  *
  179.  * @param  string  $basePath
  180.  * @return array|boolean     array of SimpleXMLElement objects or FALSE in case of an error.
  181.  */
  182. function xpath ( $basePath ) {
  183. $path = $basePath;
  184.     if ( empty( $path ) ) {
  185.      return array();
  186.     } elseif ( substr( $path , -1) === '/' ) {
  187. return false;  // If ends with '/' then wrong
  188. }
  189. $nodesList = array( &$this );
  190. $recurse = false;
  191. $absoluteMode = ( $path[0] == '/' );
  192. if ( $absoluteMode ) {
  193. $node = $this;
  194. while ( $node->_parent ) {
  195. $node = $node->_parent;
  196. }
  197. $path = substr( $path, 1 );
  198. if ( ( $path != '' ) && ( $path[0] == '/' ) ) {
  199. $recurse = true; //TBD
  200. $path = substr( $path, 1 );
  201. }
  202. $nodesList = array( &$node );
  203. }
  204. $xpa = explode( '/', $path );
  205. if ( $absoluteMode && ! $recurse ) {
  206. $xpb = array_shift( $xpa );
  207. if ( ! in_array( $xpb, array( '*', $node->name() ) ) ) {
  208. return array();
  209. }
  210. }
  211. foreach ( $xpa as $xpb ) {
  212. $xpc = explode( '::', $xpb, 2 );
  213. if ( count( $xpc ) == 1 ) {
  214. if ( $xpb == '.' ) {
  215. // ./
  216. $nodesList = array( &$this );
  217. } elseif ( $xpb == '..' ) {
  218. // ../
  219. $new = array();
  220. foreach ( $nodesList as $n ) {
  221. if ( $n->_parent && ! in_array( $n->_parent, $new ) ) {
  222. $new[] = $n->_parent;
  223. }
  224. }
  225. $nodesList = $new;
  226. } elseif ( ( $xpb == '*' ) || ( $xpb == '' ) ) { //TBD to check: maybe this case is included below already...
  227. // */ or /
  228. $new = array();
  229. foreach ( $nodesList as $n ) {
  230. foreach ( $n->children() as $nn ) {
  231. $new[] = $nn;
  232. }
  233. }
  234. $nodesList = $new;
  235. } else {
  236. // tag or tag[a] or tag[a][b]
  237. $matches = null;
  238. $result = preg_match_all( "/^([^\[\]]*)*?(?:\[([^\[\]]*)\])?(?:\[([^\[\]]*)\])?$/", $xpb, $matches );
  239. if ( $result ) {
  240. // tag or tag[a] or tag[a][b]
  241. // $matches = array( 0 => "tag[b][c]", 1 => "tag", 2 => "b", 3 => "c" );
  242. if ( $matches[2][0] ) {
  243. $matchesB = null;
  244. $resultB = preg_match_all( "/^@([^=]+)=(["'])(.+)\2$/", $matches[2][0], $matchesB );
  245. // $matchesB = array( 0 => '@attr="val"', 1 => 'attr', 2 => '"', 3 => 'val' );
  246. }
  247. if ( $matches[3][0] ) {
  248. $matchesC = null;
  249. $resultC = preg_match_all( "/^@([^=]+)=(["'])(.+)\2$/", $matches[3][0], $matchesC );
  250. // $matchesC = array( 0 => '@attr="val"', 1 => 'attr', 2 => '"', 3 => 'val' );
  251. }
  252. $new = array();
  253. foreach ( $nodesList as $n ) {
  254. // tag , tag[1], tag[1][@attr="val"], tag[@attr="val"], tag[@attr="val"][1]  ( where tag can be '*' or '' or tag )
  255. $counterA = 0;
  256. $counterB = 0;
  257. foreach ( $n->children() as $nn ) {
  258. if ( in_array( $matches[1][0], array( '*', '', $nn->name() ) ) ) {
  259. if ( is_numeric( $matches[2][0] ) ) {
  260. if ( ++$counterA < $matches[2][0] ) {
  261. continue;
  262. } elseif ( $counterA > $matches[2][0] ) {
  263. break;
  264. }
  265. } elseif ( $matches[2][0] ) {
  266. if ( ! ( ( ! $resultB ) || ( $resultB && ( $nn->attributes( $matchesB[1][0] ) == $matchesB[3][0] ) ) ) ) {
  267. continue;
  268. }
  269. }
  270. // second [ ]:
  271. if ( is_numeric( $matches[3][0] ) ) {
  272. if ( ++$counterB < $matches[3][0] ) {
  273. continue;
  274. } elseif ( $counterB > $matches[3][0] ) {
  275. break;
  276. }
  277. } elseif ( $matches[3][0] ) {
  278. if ( ! ( ( ! $resultC ) || ( $resultC && ( $nn->attributes( $matchesC[1][0] ) == $matchesC[3][0] ) ) ) ) {
  279. continue;
  280. }
  281. }
  282. $new[] = $nn;
  283. }
  284. }
  285. }
  286. $nodesList = $new;
  287. } else {
  288. trigger_error( sprintf( 'Error in xpath( %s ): illegal subexpression: %s ', $basePath , $xpb), E_USER_WARNING );
  289. }
  290. }
  291. } else { // ( count( $xpc ) == 2 ) {
  292. //TBD: for now just trigger an error:
  293. trigger_error( sprintf( 'Unsuported in CB xpath( %s ): unabreviated syntax subexpression: %s ', $basePath , $xpb), E_USER_WARNING );
  294. }
  295. }
  296. return $nodesList;
  297. }
  298. /**
  299.  * Adds a direct child to the element
  300.  *
  301.  * @param string $name
  302.  * @param string $value
  303.  * @param string $nameSpace
  304.  * @param array  $attrs
  305.  * @return FixedSimpleXML the child
  306.  */
  307. function &addChildWithAttr( $name, $value, $nameSpace = null, $attrs = array() ) {
  308. // If there is no array already set for the tag name being added, create an empty array for it:
  309. if( ! isset( $this->$name ) ) {
  310. $this->$name = array();
  311. }
  312. // Create the child object itself:
  313. $classname = get_class( $this );
  314. $child =& new $classname( null, null, false, null, false, $name, $attrs );
  315. $child->_data = $value;
  316. // Add the parent:
  317. $child->_parent =& $this;
  318. // Add the reference of it to the end of an array member named for the elements name:
  319. $this->{$name}[] =& $child;
  320. // Add the reference to the children array member:
  321. $this->_children[] =& $child;
  322. return $child;
  323. }
  324. /**
  325.  * Remove a specific child from the tree
  326.  *
  327.  * @param FixedSimpleXML $child  the child
  328.  */
  329. function removeChild( &$child ) {
  330. $name = $child->name();
  331. for ( $i = 0, $n = count( $this->_children ); $i < $n; $i++ ) {
  332. if ( $this->_children[$i] == $child ) {
  333. unset( $this->_children[$i] );
  334. }
  335. }
  336. for ( $i = 0, $n = count( $this->{$name} ); $i < $n; $i++ ) {
  337. if ( $this->{$name}[$i] == $child ) {
  338. unset( $this->{$name}[$i] );
  339. }
  340. }
  341. $this->_children = array_values( $this->_children );
  342. $this->{$name} = array_values($this->{$name});
  343. unset( $child );
  344. }
  345. /**
  346.  * Adds a direct child to the element prepended as first child
  347.  * WARNING: Not PHP SimpleXML compatible
  348.  *
  349.  * @param string $name
  350.  * @param array  $attrs
  351.  * @return FixedSimpleXML  the child
  352.  */
  353. function & prependChild( $name, $attrs ) {
  354. // If there is no array already set for the tag name being added, create an empty array for it:
  355. if(!isset($this->$name))
  356. $this->$name = array();
  357. // Create the child object itself
  358. $classname = get_class( $this );
  359. $child = new $classname( null, null, false, null, false, $name, $attrs );
  360. // Add the reference of it to the end of an array member named for the elements name:
  361. array_unshift( $this->$name, $child );
  362. // Add the reference to the children array member:
  363. array_unshift( $this->_children, $child );
  364. return $child;
  365. }
  366. /**
  367.  * Return a well-formed XML string based on SimpleXML element
  368.  *
  369.  * @param  string  $filename  filename to write to if not returning xml
  370.  * @param  int     $_level    no public access: level for indentation
  371.  * @return string             if no $filename, otherwise null
  372.  */
  373. function asXML( $filename = null, $_level = 0 ) {
  374. $out = "n".str_repeat("t", $_level).'<'.$this->_name;
  375. //For each attribute, add attr="value"
  376. foreach($this->_attributes as $attr => $value)
  377. $out .= ' '.$attr.'="'.htmlspecialchars($value).'"';
  378. //If there are no children and it contains no data, end it off with a />
  379. if(empty($this->_children) && empty($this->_data))
  380. $out .= " />";
  381. else
  382. {
  383. //If there are children
  384. if(!empty($this->_children))
  385. {
  386. //Close off the start tag
  387. $out .= '>';
  388. //For each child, call the asXML function (this will ensure that all children are added recursively)
  389. foreach($this->_children as $child)
  390. $out .= $child->asXML( null, $_level + 1 );
  391. //Add the newline and indentation to go along with the close tag
  392. $out .= "n".str_repeat("t", $_level);
  393. }
  394. //If there is data, close off the start tag and add the data
  395. elseif(!empty($this->_data))
  396. $out .= '>'. htmlspecialchars($this->_data);
  397. //Add the end tag
  398. $out .= '</'.$this->_name.'>';
  399. }
  400. if ( ( $_level != 0 ) || ( $filename === null ) ) {
  401. return $out;
  402. } else {
  403. file_put_contents( $filename, $out );
  404. return null;
  405. }
  406. }
  407. }
  408. /**
  409.  * Helper Class to load SimpleXMLElement in PHP < 5.1.3
  410.  *
  411.  * @author Beat
  412.  * @copyright Beat 2007
  413.  * @licence allowed for free use within CB and for CB plugins
  414.  */
  415. class SimpleXML_Helper
  416. {
  417. /** Document element
  418. * @var FixedSimpleXML $document */
  419. var $document = null;
  420. /** The XML parser
  421.  * @var resource */
  422. var $_parser = null;
  423. /** parsing helper
  424. * @var array of array */
  425. var $_stack = array();
  426. /**
  427.  * Constructor.
  428.  */
  429. function SimpleXML_Helper( &$firstElement, $data, $options = null, $data_is_url = false, $ns = null, $is_prefix = false ) {
  430. if ( strlen( $data ) > 64000 ) {
  431. // DOMIT XML parser can be very very very memory-hungry on PHP < 5.1.3 on large files:
  432. if ( ( ! is_callable( 'ini_get_all' ) ) || in_array( 'memory_limit', array_keys( ini_get_all() ) ) ) {
  433. $memMax = trim( @ini_get( 'memory_limit' ) );
  434. if ( $memMax ) {
  435. $last = strtolower( $memMax{strlen( $memMax ) - 1} );
  436. switch( $last ) {
  437. case 'g':
  438. $memMax *= 1024;
  439. case 'm':
  440. $memMax *= 1024;
  441. case 'k':
  442. $memMax *= 1024;
  443. }
  444. if ( $memMax < 64000000 ) {
  445. @ini_set( 'memory_limit', '64M' );
  446. }
  447. if ( $memMax < 96000000 ) {
  448. @ini_set( 'memory_limit', '96M' );
  449. }
  450. if ( $memMax < 128000000 ) {
  451. @ini_set( 'memory_limit', '128M' );
  452. }
  453. if ( $memMax < 196000000 ) {
  454. @ini_set( 'memory_limit', '196M' );
  455. }
  456. }
  457. }
  458. }
  459. if( defined('JXML_TEST_DOMIT') || ! function_exists( 'xml_parser_create' ) ) {
  460. global $_CB_framework;
  461. $domitPath = $_CB_framework->getCfg('absolute_path') . '/includes/domit/xml_domit_lite_include.php';
  462. if ( file_exists( $domitPath ) ) {
  463. require_once( $domitPath );
  464. } else {
  465. die("<font color='red'>". $_CB_framework->getCfg( 'absolute_path' ) . "/includes/domit/ does not exist! This is normal with mambo 4.5.0 and 4.6.1. Community Builder needs this library for handling plugins.<br />  You Must Manually do the following:<br /> 1.) create " . $_CB_framework->getCfg( 'absolute_path' ) . "/includes/domit/ directory <br /> 2.) chmod it to 777 <br /> 3.) copy corresponding content of a mambo 4.5.2 directory.</font><br /><br />n");
  466. }
  467. $this->_parser = null;
  468. } else {
  469. //Create the parser resource and make sure both versions of PHP autodetect the format
  470. $this->_parser = xml_parser_create('');
  471. // check parser resource
  472. xml_set_object($this->_parser, $this);
  473. xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, 0);
  474. //Set the handlers
  475. xml_set_element_handler($this->_parser, '_startElement', '_endElement');
  476. xml_set_character_data_handler($this->_parser, '_characterData');
  477. }
  478. // set the first element
  479. $this->document[0] =& $firstElement;
  480. /*
  481. $mem0 = memory_get_usage();
  482. echo "Memory: " . $mem0 ."n";
  483. $time = microtime(true);
  484. */
  485. // load the XML data and generate tree
  486. if ( $data_is_url ) {
  487. if ( ! $this->loadFile( $data ) ) {
  488. echo "XML file " . $data . " load error.";
  489. exit();
  490. }
  491. } else {
  492. if ( ! $this->loadString( $data ) ) {
  493. echo "XML string load error.";
  494. exit();
  495. }
  496. }
  497. /*
  498. $time2 = microtime(true) - $time;
  499. echo "Time function calls: " . $time2 ."n";
  500. $mem1 = memory_get_usage();
  501. echo "Memory used additional: " . ($mem1 - $mem0) ."n";
  502. $mem0 = $mem1;
  503. */
  504. }
  505.  /**
  506.  * Interprets a string of XML into an object
  507.  *
  508.  * This function will take the well-formed xml string data and return an object of class
  509.  * FixedSimpleXML with properties containing the data held within the xml document.
  510.  * If any errors occur, it returns FALSE.
  511.  *
  512.  * @param string  Well-formed xml string data
  513.  * @return boolean
  514.  */
  515. function loadString( $string ) {
  516. $this->_parse( $string );
  517. return true;
  518. }
  519.  /**
  520.  * Interprets an XML file into an object
  521.  *
  522.  * @param string  Path to xml file containing a well-formed XML document
  523.  * @return boolean True if successful, false if file empty
  524.  */
  525. function loadFile( $path ) {
  526. if ( file_exists( $path ) ) {
  527. //Get the XML document loaded into a variable
  528. $xml = trim( file_get_contents($path) );
  529. if ( $xml == '' ) {
  530. return false;
  531. } else {
  532. $this->_parse( $xml );
  533. unset( $xml );
  534. return true;
  535. }
  536. } else {
  537. return false;
  538. }
  539. }
  540. /**
  541.  * Returns all attributes of the DOMIT element in an array
  542.  *
  543.  * @param DOMIT_Lite_Element $element
  544.  * @return array of string
  545.  */
  546. function _domitGetAttributes( &$element ) {
  547. $attributesArray = array();
  548. //get a reference to the attributes list / named node map (don't forget the ampersand!)
  549. $attrList =& $element->attributes;
  550. if ( $attrList !== null && is_array( $attrList ) && ( count( $attrList ) > 0 ) ) {
  551. //iterate through the list
  552. foreach ($attrList as $k => $currAttr ) {
  553. $attributesArray[$k] = $currAttr;
  554. }
  555. }
  556. return $attributesArray;
  557. }
  558. /**
  559.  * Recursively parses XML using DOMIT
  560.  *
  561.  * @param unknown_type $element
  562.  */
  563. function _domitParse( &$element ) {
  564. if ( $element->nodeName != '#text' ) {
  565. $this->_startElement( null, $element->nodeName, $this->_domitGetAttributes( $element ) );
  566. if ( $element->hasChildNodes() ) {
  567. $myChildNodes = $element->childNodes;
  568. //get the total number of childNodes for the document element
  569. $numChildren = $element->childCount;
  570. //iterate through the collection
  571. for ($i = 0; $i < $numChildren; $i++) {
  572. //get a reference to the i childNode
  573. $currentNode = $myChildNodes[$i];
  574. // recurse
  575. $this->_domitParse( $currentNode );
  576. }
  577. }
  578. $this->_endElement( null, $element->nodeName );
  579. } else {
  580. $this->_characterData( null, $element->nodeValue );
  581. }
  582. }
  583. /**
  584.  * Start parsing an XML document
  585.  *
  586.  * Parses an XML document. The handlers for the configured events are called as many times as necessary.
  587.  *
  588.  * @param  string $data to parse
  589.  */
  590. function _parse($data = '') {
  591. if ( $this->_parser === null ) {
  592. $xml =& new DOMIT_Lite_Document();
  593. $success = $xml->parseXML( $data );
  594. if ($success) {
  595. //gets a reference to the root element of the cd collection
  596. $myDocumentElement =& $xml->documentElement;
  597. $this->_domitParse( $myDocumentElement );
  598. $this->document = $this->document[0];
  599. }
  600. } else {
  601. if ( xml_parse( $this->_parser, $data ) ) {
  602. $this->document = $this->document[0];
  603. } else {
  604. //Error handling
  605. $this->_handleError( xml_get_error_code( $this->_parser ),
  606.  xml_get_current_line_number( $this->_parser ),
  607.  xml_get_current_column_number( $this->_parser ) );
  608. }
  609. xml_parser_free($this->_parser);
  610. }
  611. }
  612. /**
  613.  * Handles an XML parsing error
  614.  *
  615.  * @param int $code XML Error Code
  616.  * @param int $line Line on which the error happened
  617.  * @param int $col Column on which the error happened
  618.  */
  619. function _handleError($code, $line, $col) {
  620. echo 'XML Parsing Error at '.$line.':'.$col.'. Error '.$code.': '.xml_error_string($code);
  621. }
  622. /**
  623.  * Gets the current direct parent
  624.  *
  625.  * @return FixedSimpleXML  object
  626.  */
  627. function & _getStackElement() {
  628. $return =& $this;
  629. foreach($this->_stack as $stack) {
  630. $return =& $return->{$stack[0]}[$stack[1]];
  631. // equivalent to:
  632. //list( $n, $k ) = $stack;
  633. //$return = $return->{$n}[$k];
  634. }
  635. return $return;
  636. }
  637. /**
  638.  * Handler function for the start of a tag
  639.  *
  640.  * @param resource $parser
  641.  * @param string $name
  642.  * @param array $attrs
  643.  */
  644. function _startElement( $parser, $name, $attrs = array() ) {
  645. //Check to see if tag is root-level
  646. if (count($this->_stack) == 0) {
  647. // start out the stack with the document tag
  648. $this->_stack = array( array ( 'document', 0 ) );
  649. $this->document[0]->_name = $name;
  650. $this->document[0]->_attributes = $attrs;
  651. } else {
  652. //If it isn't root level, use the stack to find the parent
  653.  //Get the name which points to the current direct parent, relative to $this
  654. $parent =& $this->_getStackElement();
  655. //Add the child
  656. $parent->addChildWithAttr( $name, null, null, $attrs );
  657. //Update the stack
  658. $this->_stack[] = array( $name, ( count( $parent->$name ) - 1 ) );
  659. }
  660. }
  661. /**
  662.  * Handler function for the end of a tag
  663.  *
  664.  * @param resource $parser
  665.  * @param string $name
  666.  */
  667. function _endElement( $parser, $name ) {
  668. //Update stack by removing the end value from it as the parent
  669. array_pop($this->_stack);
  670. }
  671. /**
  672.  * Handler function for the character data within a tag
  673.  *
  674.  * @param resource $parser
  675.  * @param string $data
  676.  */
  677. function _characterData( $parser, $data ) {
  678. //Get the reference to the current parent object
  679. $tag =& $this->_getStackElement();
  680. //Assign data to it
  681. $tag->_data .= $data;
  682. }
  683. }
  684. ?>