annotate 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
rev   line source
webmaster@0 1 <?php
webmaster@0 2 class Template {
webmaster@2 3 private $xmlDocument;
webmaster@2 4 private $xmlXPath;
webmaster@0 5
webmaster@0 6 const NS = 'http://defr.net/2007/template';
webmaster@0 7
webmaster@6 8 function __construct($fileName, $shouldValidate = false) {
webmaster@2 9 $this->xmlDocument = new DOMDocument();
webmaster@6 10 $this->xmlDocument->validateOnParse = $shouldValidate;
webmaster@9 11 $this->xmlDocument->preserveWhiteSpace = false;
webmaster@2 12 $this->xmlDocument->loadXML(file_get_contents($fileName));
webmaster@15 13 $this->xmlDocument->preserveWhiteSpace = false;
webmaster@0 14 $this->xmlXPath = new DOMXPath($this->xmlDocument);
webmaster@8 15 $this->xmlXPath->registerNamespace('_t', Template::NS);
webmaster@0 16 }
webmaster@0 17
webmaster@3 18 function apply($selector, $obj, DOMElement $root = null) {
webmaster@6 19 if(!($root instanceof DOMElement))
webmaster@3 20 $root = $this->xmlDocument->documentElement;
webmaster@3 21 $rootSelector = $this->parseSelector($selector, $root);
webmaster@6 22 if(is_array($obj))
webmaster@6 23 $this->applyClone($rootSelector, $obj, $root);
webmaster@3 24 else {
webmaster@0 25 foreach($rootSelector->nodes as $node) {
webmaster@3 26 $content = $this->parseReplacement($obj);
webmaster@15 27 if(isset($rootSelector->attribute))
webmaster@0 28 $node->setAttribute($rootSelector->attribute, $obj);
webmaster@15 29 else
webmaster@15 30 $this->setNodeContent($node, $content);
webmaster@0 31 }
webmaster@0 32 }
webmaster@0 33 }
webmaster@6 34
webmaster@6 35 function applyClone($rootSelector, $obj, $root) {
webmaster@6 36 foreach($obj as $array) {
webmaster@6 37 $nodeName = key($array);
webmaster@6 38 foreach($rootSelector->nodes as $node) {
webmaster@6 39 $tmp = $this->getClonedNode($node, $nodeName);
webmaster@6 40 $futureNode = $tmp->clone;
webmaster@6 41 $futureNode = $node->insertBefore($futureNode, $tmp->orig);
webmaster@6 42 foreach($array as $sel => $test) {
webmaster@6 43 $locSelector = $this->parseSelector($sel, $node);
webmaster@7 44 if(isset($locSelector->attribute))
webmaster@6 45 $futureNode->setAttribute($locSelector->attribute, $test);
webmaster@6 46 else {
webmaster@6 47 $content = $this->parseReplacement($test);
webmaster@6 48 $node->insertBefore($content, $tmp->orig);
webmaster@15 49 $this->setNodeContent($futureNode, $content);
webmaster@6 50 }
webmaster@6 51 }
webmaster@6 52 }
webmaster@6 53 }
webmaster@6 54 }
webmaster@0 55
webmaster@0 56 function getClonedNode($node, $childNodeName) {
webmaster@3 57 $candidates = $this->parseSelector($childNodeName, $node)->nodes;
webmaster@1 58 foreach($candidates as $candidate) {
webmaster@3 59 if($candidate->getAttributeNS(Template::NS, 'toClone') == 'true') {
webmaster@0 60 $tmp = array();
webmaster@1 61 $tmp['orig'] = $candidate;
webmaster@1 62 $cnode = $candidate->cloneNode(true);
webmaster@6 63 $cnode->removeAttributeNS(Template::NS, 'toClone');
webmaster@0 64 $tmp['clone'] = $cnode;
webmaster@0 65 return (object)$tmp;
webmaster@0 66 }
webmaster@0 67 }
webmaster@0 68 }
webmaster@0 69
webmaster@3 70 function parseSelector($selector, DOMElement $root) {
webmaster@0 71 $obj = array();
webmaster@0 72 $pos = strpos($selector, '@');
webmaster@0 73 if($pos !== false) {
webmaster@0 74 $obj['attribute'] = substr($selector,$pos +1);
webmaster@0 75 $selector = substr($selector, 0, $pos);
webmaster@0 76 }
webmaster@0 77 if($selector[0] == '#') {
webmaster@8 78 $obj['xpath'] = "//*[@_t:id='" . substr($selector, 1) . "']";
webmaster@0 79 $obj['nodes'] = $this->xmlXPath->query($obj['xpath'], $root);
webmaster@0 80 }
webmaster@0 81 else {
webmaster@0 82 $obj['nodeName'] = $selector;
webmaster@0 83 $obj['nodes'] = $root->getElementsByTagName($selector);
webmaster@0 84 }
webmaster@0 85 return (object)$obj;
webmaster@0 86 }
webmaster@0 87
webmaster@0 88 function parseReplacement($obj) {
webmaster@0 89 $retVal = NULL;
webmaster@0 90 if(is_string($obj))
webmaster@0 91 $retVal = $this->xmlDocument->createTextNode($obj);
webmaster@0 92 else if($obj instanceof DOMDocument)
webmaster@16 93 $retVal = $this->xmlDocument->importNode($obj->documentElement);
webmaster@16 94 else if($obj instanceof DOMDocumentFragment)
webmaster@16 95 $retVal = $obj;
webmaster@0 96 else if($obj instanceof DOMNode)
webmaster@3 97 $retVal = $obj->clone(true);
webmaster@11 98 else if($obj instanceof Template) {
webmaster@11 99 $node = $obj->xmlDocument->documentElement;
webmaster@11 100 $retVal = $this->xmlDocument->importNode($node, true);
webmaster@11 101 }
webmaster@0 102 return $retVal;
webmaster@0 103 }
webmaster@0 104
webmaster@0 105 function setParams($array) {
webmaster@0 106 foreach($array as $selector => $obj) {
webmaster@0 107 $this->apply($selector, $obj);
webmaster@0 108 }
webmaster@0 109 }
webmaster@0 110
webmaster@0 111 function replaceNode(DOMNode $node, DOMNode $content) {
webmaster@0 112 $parent = $node->parentNode;
webmaster@0 113 $parent->replaceChild($content, $node);
webmaster@0 114 }
webmaster@0 115
webmaster@0 116 function setNodeContent(DOMElement $node, DOMNode $content) {
webmaster@0 117 // Suppress existing childs
webmaster@0 118 foreach($node->childNodes as $child) {
webmaster@0 119 $node->removeChild($child);
webmaster@0 120 }
webmaster@0 121 // Add the new child
webmaster@0 122 $node->appendChild($content);
webmaster@0 123 }
webmaster@0 124
webmaster@0 125 function clean() {
webmaster@0 126 // Suppression des noeuds à cloner
webmaster@8 127 $nodes = $this->xmlXPath->query("//*[@_t:toClone]|//_t:*");
webmaster@0 128 foreach($nodes as $node) {
webmaster@0 129 if($node->parentNode) {
webmaster@15 130 $parent = $node->parentNode;
webmaster@15 131 if(!$node->hasAttributeNS(Template::NS, 'toClone')) {
webmaster@15 132 while($node->hasChildNodes())
webmaster@15 133 $parent->insertBefore($node->firstChild, $node);
webmaster@15 134 }
webmaster@15 135 $parent->removeChild($node);
webmaster@0 136 }
webmaster@0 137 }
webmaster@0 138 }
webmaster@0 139
webmaster@0 140 function __toString() {
webmaster@0 141 $this->clean();
webmaster@9 142 $this->xmlDocument->formatOutput = true;
webmaster@15 143 $this->xmlDocument->normalizeDocument();
webmaster@0 144 return $this->xmlDocument->saveXML();
webmaster@0 145 }
webmaster@16 146
webmaster@16 147 function getDocumentFragment() {
webmaster@16 148 return $this->xmlDocument->createDocumentFragment();
webmaster@16 149 }
webmaster@6 150 }