diff options
Diffstat (limited to 'lib/phptal/PHPTAL/Dom/PHPTALDocumentBuilder.php')
| -rw-r--r-- | lib/phptal/PHPTAL/Dom/PHPTALDocumentBuilder.php | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/phptal/PHPTAL/Dom/PHPTALDocumentBuilder.php b/lib/phptal/PHPTAL/Dom/PHPTALDocumentBuilder.php new file mode 100644 index 0000000..a3157be --- /dev/null +++ b/lib/phptal/PHPTAL/Dom/PHPTALDocumentBuilder.php @@ -0,0 +1,167 @@ +<?php +/** + * PHPTAL templating engine + * + * PHP Version 5 + * + * @category HTML + * @package PHPTAL + * @author Laurent Bedubourg <lbedubourg@motion-twin.com> + * @author Kornel LesiĆski <kornel@aardvarkmedia.co.uk> + * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License + * @version SVN: $Id$ + * @link http://phptal.org/ + */ + + +/** + * DOM Builder + * + * @package PHPTAL + * @subpackage Dom + */ +class PHPTAL_Dom_PHPTALDocumentBuilder extends PHPTAL_Dom_DocumentBuilder +{ + private $_xmlns; /* PHPTAL_Dom_XmlnsState */ + private $encoding; + + public function __construct() + { + $this->_xmlns = new PHPTAL_Dom_XmlnsState(array(), ''); + } + + public function getResult() + { + return $this->documentElement; + } + + protected function getXmlnsState() + { + return $this->_xmlns; + } + + // ~~~~~ XmlParser implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public function onDocumentStart() + { + $this->documentElement = new PHPTAL_Dom_Element('documentElement', 'http://xml.zope.org/namespaces/tal', array(), $this->getXmlnsState()); + $this->documentElement->setSource($this->file, $this->line); + $this->_current = $this->documentElement; + } + + public function onDocumentEnd() + { + if (count($this->_stack) > 0) { + $left='</'.$this->_current->getQualifiedName().'>'; + for ($i = count($this->_stack)-1; $i>0; $i--) $left .= '</'.$this->_stack[$i]->getQualifiedName().'>'; + throw new PHPTAL_ParserException("Not all elements were closed before end of the document. Missing: ".$left, + $this->file, $this->line); + } + } + + public function onDocType($doctype) + { + $this->pushNode(new PHPTAL_Dom_DocumentType($doctype, $this->encoding)); + } + + public function onXmlDecl($decl) + { + if (!$this->encoding) { + throw new PHPTAL_Exception("Encoding not set"); + } + $this->pushNode(new PHPTAL_Dom_XmlDeclaration($decl, $this->encoding)); + } + + public function onComment($data) + { + $this->pushNode(new PHPTAL_Dom_Comment($data, $this->encoding)); + } + + public function onCDATASection($data) + { + $this->pushNode(new PHPTAL_Dom_CDATASection($data, $this->encoding)); + } + + public function onProcessingInstruction($data) + { + $this->pushNode(new PHPTAL_Dom_ProcessingInstruction($data, $this->encoding)); + } + + public function onElementStart($element_qname, array $attributes) + { + $this->_xmlns = $this->_xmlns->newElement($attributes); + + if (preg_match('/^([^:]+):/', $element_qname, $m)) { + $prefix = $m[1]; + $namespace_uri = $this->_xmlns->prefixToNamespaceURI($prefix); + if (false === $namespace_uri) { + throw new PHPTAL_ParserException("There is no namespace declared for prefix of element < $element_qname >. You must have xmlns:$prefix declaration in the same document.", + $this->file, $this->line); + } + } else { + $namespace_uri = $this->_xmlns->getCurrentDefaultNamespaceURI(); + } + + $attrnodes = array(); + foreach ($attributes as $qname=>$value) { + + if (preg_match('/^([^:]+):(.+)$/', $qname, $m)) { + list(,$prefix, $local_name) = $m; + $attr_namespace_uri = $this->_xmlns->prefixToNamespaceURI($prefix); + + if (false === $attr_namespace_uri) { + throw new PHPTAL_ParserException("There is no namespace declared for prefix of attribute $qname of element < $element_qname >. You must have xmlns:$prefix declaration in the same document.", + $this->file, $this->line); + } + } else { + $local_name = $qname; + $attr_namespace_uri = ''; // default NS. Attributes don't inherit namespace per XMLNS spec + } + + if ($this->_xmlns->isHandledNamespace($attr_namespace_uri) + && !$this->_xmlns->isValidAttributeNS($attr_namespace_uri, $local_name)) { + throw new PHPTAL_ParserException("Attribute '$qname' is in '$attr_namespace_uri' namespace, but is not a supported PHPTAL attribute", + $this->file, $this->line); + } + + $attrnodes[] = new PHPTAL_Dom_Attr($qname, $attr_namespace_uri, $value, $this->encoding); + } + + $node = new PHPTAL_Dom_Element($element_qname, $namespace_uri, $attrnodes, $this->getXmlnsState()); + $this->pushNode($node); + $this->_stack[] = $this->_current; + $this->_current = $node; + } + + public function onElementData($data) + { + $this->pushNode(new PHPTAL_Dom_Text($data, $this->encoding)); + } + + public function onElementClose($qname) + { + if ($this->_current === $this->documentElement) { + throw new PHPTAL_ParserException("Found closing tag for < $qname > where there are no open tags", + $this->file, $this->line); + } + if ($this->_current->getQualifiedName() != $qname) { + throw new PHPTAL_ParserException("Tag closure mismatch, expected < /".$this->_current->getQualifiedName()." > (opened in line ".$this->_current->getSourceLine().") but found < /".$qname." >", + $this->file, $this->line); + } + $this->_current = array_pop($this->_stack); + if ($this->_current instanceof PHPTAL_Dom_Element) { + $this->_xmlns = $this->_current->getXmlnsState(); // restore namespace prefixes info to previous state + } + } + + private function pushNode(PHPTAL_Dom_Node $node) + { + $node->setSource($this->file, $this->line); + $this->_current->appendChild($node); + } + + public function setEncoding($encoding) + { + $this->encoding = $encoding; + } +} |
