| // +----------------------------------------------------------------------+ // // $Id$ require_once('XML/Parser.php'); require_once('XML/Util.php'); /** * Config parser for XML Files * * @author Bertrand Mansion * @package Config */ class Config_Container_XML extends XML_Parser { /** * Deep level used for indentation * * @var int * @access private */ var $_deep = -1; /** * This class options: * version (1.0) : XML version * encoding (ISO-8859-1) : XML content encoding * name : like in phparray, name of your config global entity * indent : char used for indentation * linebreak : char used for linebreak * addDecl : whether to add the xml declaration at beginning or not * useAttr : whether to use the attributes * isFile : whether the given content is a file or an XML string * useCData : whether to surround data with * * @var array */ var $options = array('version' => '1.0', 'encoding' => 'ISO-8859-1', 'name' => '', 'indent' => ' ', 'linebreak' => "\n", 'addDecl' => true, 'useAttr' => true, 'isFile' => true, 'useCData' => false); /** * Container objects * * @var array */ var $containers = array(); /** * Constructor * * @access public * @param string $options Options to be used by renderer * version : (1.0) XML version * encoding : (ISO-8859-1) XML content encoding * name : like in phparray, name of your config global entity * indent : char used for indentation * linebreak : char used for linebreak * addDecl : whether to add the xml declaration at beginning or not * useAttr : whether to use the attributes * isFile : whether the given content is a file or an XML string */ function Config_Container_XML($options = array()) { foreach ($options as $key => $value) { $this->options[$key] = $value; } } // end constructor /** * Parses the data of the given configuration file * * @access public * @param string $datasrc path to the configuration file * @param object $obj reference to a config object * @return mixed returns a PEAR_ERROR, if error occurs or true if ok */ function &parseDatasrc($datasrc, &$obj) { $err = true; $this->folding = false; $this->cdata = null; $this->XML_Parser($this->options['encoding'], 'event'); $this->containers[0] =& $obj->container; if (is_string($datasrc)) { if ($this->options['isFile']) { $err = $this->setInputFile($datasrc); if (PEAR::isError($err)) { return $err; } $err = $this->parse(); } else { $err = $this->parseString($datasrc, true); } } else { $this->setInput($datasrc); $err = $this->parse(); } return $err; } // end func parseDatasrc /** * Handler for the xml-data * * @param mixed $xp ignored * @param string $elem name of the element * @param array $attribs attributes for the generated node * * @access private */ function startHandler($xp, $elem, &$attribs) { $container =& new Config_Container('section', $elem, null, $attribs); $this->containers[] =& $container; return null; } // end func startHandler /** * Handler for the xml-data * * @param mixed $xp ignored * @param string $elem name of the element * * @access private */ function endHandler($xp, $elem) { $count = count($this->containers); $container =& $this->containers[$count-1]; $currentSection =& $this->containers[$count-2]; if (count($container->children) == 0) { $container->setType('directive'); $container->setContent(trim($this->cdata)); } $currentSection->addItem($container); array_pop($this->containers); $this->cdata = null; return null; } // end func endHandler /* * The xml character data handler * * @param mixed $xp ignored * @param string $data PCDATA between tags * * @access private */ function cdataHandler($xp, $cdata) { $this->cdata .= $cdata; } // end func cdataHandler /** * Returns a formatted string of the object * @param object $obj Container object to be output as string * @access public * @return string */ function toString(&$obj) { $indent = ''; if (!$obj->isRoot()) { // no indent for root $this->_deep++; $indent = str_repeat($this->options['indent'], $this->_deep); } else { // Initialize string with xml declaration $string = ''; if ($this->options['addDecl']) { $string .= XML_Util::getXMLDeclaration($this->options['version'], $this->options['encoding']); $string .= $this->options['linebreak']; } if (!empty($this->options['name'])) { $string .= '<'.$this->options['name'].'>'.$this->options['linebreak']; $this->_deep++; $indent = str_repeat($this->options['indent'], $this->_deep); } } if (!isset($string)) { $string = ''; } switch ($obj->type) { case 'directive': $attributes = ($this->options['useAttr']) ? $obj->attributes : array(); $string .= $indent.XML_Util::createTag($obj->name, $attributes, $obj->content, null, ($this->options['useCData'] ? XML_UTIL_CDATA_SECTION : XML_UTIL_REPLACE_ENTITIES)); $string .= $this->options['linebreak']; break; case 'comment': $string .= $indent.''; $string .= $this->options['linebreak']; break; case 'section': if (!$obj->isRoot()) { $string = $indent.'<'.$obj->name; $string .= ($this->options['useAttr']) ? XML_Util::attributesToString($obj->attributes) : ''; } if ($children = count($obj->children)) { if (!$obj->isRoot()) { $string .= '>'.$this->options['linebreak']; } for ($i = 0; $i < $children; $i++) { $string .= $this->toString($obj->getChild($i)); } } if (!$obj->isRoot()) { if ($children) { $string .= $indent.'name.'>'.$this->options['linebreak']; } else { $string .= '/>'.$this->options['linebreak']; } } else { if (!empty($this->options['name'])) { $string .= 'options['name'].'>'.$this->options['linebreak']; } } break; default: $string = ''; } if (!$obj->isRoot()) { $this->_deep--; } return $string; } // end func toString } // end class Config_Container_XML ?>