Mercurial > defr > templates
view class.template.php @ 16:7a3ce31086b3
Possibilité de créer un fragment de document. Fix du cas DOMDocument.
Il est desormais possible d'inserer un remplacement par un fragment
de document, concept introduit par PHP et qui n'est pas un standard
DOM, correspondant a une suite de noeud non imbriqué dans une
racine.
D'autre part, le remplacement par un document DOM n'était pas
reelement opérationnel, puisque dans le cas général il est
necessaire en plus d'importer le noeud dans l'espace du nouveau
document avec importNode avant de pouvoir l'utiliser.
author | Franck Deroche <webmaster@defr.org> |
---|---|
date | Wed, 24 Oct 2007 20:21:20 +0200 |
parents | 51645aad97a8 |
children | d4ac7cef0cdd |
line wrap: on
line source
<?php class Template { private $xmlDocument; private $xmlXPath; const NS = 'http://defr.net/2007/template'; function __construct($fileName, $shouldValidate = false) { $this->xmlDocument = new DOMDocument(); $this->xmlDocument->validateOnParse = $shouldValidate; $this->xmlDocument->preserveWhiteSpace = false; $this->xmlDocument->loadXML(file_get_contents($fileName)); $this->xmlDocument->preserveWhiteSpace = false; $this->xmlXPath = new DOMXPath($this->xmlDocument); $this->xmlXPath->registerNamespace('_t', Template::NS); } function apply($selector, $obj, DOMElement $root = null) { if(!($root instanceof DOMElement)) $root = $this->xmlDocument->documentElement; $rootSelector = $this->parseSelector($selector, $root); if(is_array($obj)) $this->applyClone($rootSelector, $obj, $root); else { foreach($rootSelector->nodes as $node) { $content = $this->parseReplacement($obj); if(isset($rootSelector->attribute)) $node->setAttribute($rootSelector->attribute, $obj); else $this->setNodeContent($node, $content); } } } function applyClone($rootSelector, $obj, $root) { foreach($obj as $array) { $nodeName = key($array); foreach($rootSelector->nodes as $node) { $tmp = $this->getClonedNode($node, $nodeName); $futureNode = $tmp->clone; $futureNode = $node->insertBefore($futureNode, $tmp->orig); foreach($array as $sel => $test) { $locSelector = $this->parseSelector($sel, $node); if(isset($locSelector->attribute)) $futureNode->setAttribute($locSelector->attribute, $test); else { $content = $this->parseReplacement($test); $node->insertBefore($content, $tmp->orig); $this->setNodeContent($futureNode, $content); } } } } } function getClonedNode($node, $childNodeName) { $candidates = $this->parseSelector($childNodeName, $node)->nodes; foreach($candidates as $candidate) { if($candidate->getAttributeNS(Template::NS, 'toClone') == 'true') { $tmp = array(); $tmp['orig'] = $candidate; $cnode = $candidate->cloneNode(true); $cnode->removeAttributeNS(Template::NS, 'toClone'); $tmp['clone'] = $cnode; return (object)$tmp; } } } function parseSelector($selector, DOMElement $root) { $obj = array(); $pos = strpos($selector, '@'); if($pos !== false) { $obj['attribute'] = substr($selector,$pos +1); $selector = substr($selector, 0, $pos); } if($selector[0] == '#') { $obj['xpath'] = "//*[@_t:id='" . substr($selector, 1) . "']"; $obj['nodes'] = $this->xmlXPath->query($obj['xpath'], $root); } else { $obj['nodeName'] = $selector; $obj['nodes'] = $root->getElementsByTagName($selector); } return (object)$obj; } function parseReplacement($obj) { $retVal = NULL; if(is_string($obj)) $retVal = $this->xmlDocument->createTextNode($obj); else if($obj instanceof DOMDocument) $retVal = $this->xmlDocument->importNode($obj->documentElement); else if($obj instanceof DOMDocumentFragment) $retVal = $obj; else if($obj instanceof DOMNode) $retVal = $obj->clone(true); else if($obj instanceof Template) { $node = $obj->xmlDocument->documentElement; $retVal = $this->xmlDocument->importNode($node, true); } return $retVal; } function setParams($array) { foreach($array as $selector => $obj) { $this->apply($selector, $obj); } } function replaceNode(DOMNode $node, DOMNode $content) { $parent = $node->parentNode; $parent->replaceChild($content, $node); } function setNodeContent(DOMElement $node, DOMNode $content) { // Suppress existing childs foreach($node->childNodes as $child) { $node->removeChild($child); } // Add the new child $node->appendChild($content); } function clean() { // Suppression des noeuds à cloner $nodes = $this->xmlXPath->query("//*[@_t:toClone]|//_t:*"); foreach($nodes as $node) { if($node->parentNode) { $parent = $node->parentNode; if(!$node->hasAttributeNS(Template::NS, 'toClone')) { while($node->hasChildNodes()) $parent->insertBefore($node->firstChild, $node); } $parent->removeChild($node); } } } function __toString() { $this->clean(); $this->xmlDocument->formatOutput = true; $this->xmlDocument->normalizeDocument(); return $this->xmlDocument->saveXML(); } function getDocumentFragment() { return $this->xmlDocument->createDocumentFragment(); } }