annotate class.template.php @ 19:fb0e206f1acf tip

Possibilité de supprimer les attributs dans l'espace de nom de transformation Si des attributs sont présents dans un espace de nom autre que celui par défaut dans un document XHTML, ce dernier n'est plus valide au sens strict d'après la documentation du W3C[1], et en conséquence le validator se plaint. Par conséquent, il est désormais possible de définir un paramètre du template amenant la suppression de tous ses attributs. Par défaut, on ne les supprime pas, car il pourrait y avoir des utilisations valides d'une part (CSS étant au courant de l'existence des espaces de noms entre autres), et que cela entraine une pénalité au niveau du temps d'execution d'autre part, puisqu'il faut retrouver ses attributs avant de les supprimer (la pénalité ne devrait pas être trop grande grâce à XPath, mais non nul quand même) Ajout d'un test unitaire qui va bien pour tester cette fonctionnalité. [1] : http://www.w3.org/TR/xhtml1/#well-formed
author Franck Deroche <webmaster@defr.org>
date Wed, 31 Oct 2007 17:56:14 +0100
parents d4ac7cef0cdd
children
rev   line source
webmaster@0 1 <?php
webmaster@0 2 class Template {
webmaster@2 3 private $xmlDocument;
webmaster@2 4 private $xmlXPath;
webmaster@19 5 private $stripAttributesInTemplateNS = false;
webmaster@0 6
webmaster@0 7 const NS = 'http://defr.net/2007/template';
webmaster@0 8
webmaster@6 9 function __construct($fileName, $shouldValidate = false) {
webmaster@2 10 $this->xmlDocument = new DOMDocument();
webmaster@6 11 $this->xmlDocument->validateOnParse = $shouldValidate;
webmaster@9 12 $this->xmlDocument->preserveWhiteSpace = false;
webmaster@17 13 $contents = file_get_contents($fileName, FILE_USE_INCLUDE_PATH);
webmaster@17 14 $this->xmlDocument->loadXML($contents);
webmaster@15 15 $this->xmlDocument->preserveWhiteSpace = false;
webmaster@0 16 $this->xmlXPath = new DOMXPath($this->xmlDocument);
webmaster@8 17 $this->xmlXPath->registerNamespace('_t', Template::NS);
webmaster@0 18 }
webmaster@0 19
webmaster@3 20 function apply($selector, $obj, DOMElement $root = null) {
webmaster@6 21 if(!($root instanceof DOMElement))
webmaster@3 22 $root = $this->xmlDocument->documentElement;
webmaster@3 23 $rootSelector = $this->parseSelector($selector, $root);
webmaster@6 24 if(is_array($obj))
webmaster@6 25 $this->applyClone($rootSelector, $obj, $root);
webmaster@3 26 else {
webmaster@0 27 foreach($rootSelector->nodes as $node) {
webmaster@3 28 $content = $this->parseReplacement($obj);
webmaster@15 29 if(isset($rootSelector->attribute))
webmaster@0 30 $node->setAttribute($rootSelector->attribute, $obj);
webmaster@15 31 else
webmaster@15 32 $this->setNodeContent($node, $content);
webmaster@0 33 }
webmaster@0 34 }
webmaster@0 35 }
webmaster@6 36
webmaster@6 37 function applyClone($rootSelector, $obj, $root) {
webmaster@6 38 foreach($obj as $array) {
webmaster@6 39 $nodeName = key($array);
webmaster@6 40 foreach($rootSelector->nodes as $node) {
webmaster@6 41 $tmp = $this->getClonedNode($node, $nodeName);
webmaster@6 42 $futureNode = $tmp->clone;
webmaster@6 43 $futureNode = $node->insertBefore($futureNode, $tmp->orig);
webmaster@6 44 foreach($array as $sel => $test) {
webmaster@6 45 $locSelector = $this->parseSelector($sel, $node);
webmaster@7 46 if(isset($locSelector->attribute))
webmaster@6 47 $futureNode->setAttribute($locSelector->attribute, $test);
webmaster@6 48 else {
webmaster@6 49 $content = $this->parseReplacement($test);
webmaster@6 50 $node->insertBefore($content, $tmp->orig);
webmaster@15 51 $this->setNodeContent($futureNode, $content);
webmaster@6 52 }
webmaster@6 53 }
webmaster@6 54 }
webmaster@6 55 }
webmaster@6 56 }
webmaster@0 57
webmaster@0 58 function getClonedNode($node, $childNodeName) {
webmaster@3 59 $candidates = $this->parseSelector($childNodeName, $node)->nodes;
webmaster@1 60 foreach($candidates as $candidate) {
webmaster@3 61 if($candidate->getAttributeNS(Template::NS, 'toClone') == 'true') {
webmaster@0 62 $tmp = array();
webmaster@1 63 $tmp['orig'] = $candidate;
webmaster@1 64 $cnode = $candidate->cloneNode(true);
webmaster@6 65 $cnode->removeAttributeNS(Template::NS, 'toClone');
webmaster@0 66 $tmp['clone'] = $cnode;
webmaster@0 67 return (object)$tmp;
webmaster@0 68 }
webmaster@0 69 }
webmaster@0 70 }
webmaster@0 71
webmaster@3 72 function parseSelector($selector, DOMElement $root) {
webmaster@0 73 $obj = array();
webmaster@0 74 $pos = strpos($selector, '@');
webmaster@0 75 if($pos !== false) {
webmaster@0 76 $obj['attribute'] = substr($selector,$pos +1);
webmaster@0 77 $selector = substr($selector, 0, $pos);
webmaster@0 78 }
webmaster@0 79 if($selector[0] == '#') {
webmaster@8 80 $obj['xpath'] = "//*[@_t:id='" . substr($selector, 1) . "']";
webmaster@0 81 $obj['nodes'] = $this->xmlXPath->query($obj['xpath'], $root);
webmaster@0 82 }
webmaster@0 83 else {
webmaster@0 84 $obj['nodeName'] = $selector;
webmaster@0 85 $obj['nodes'] = $root->getElementsByTagName($selector);
webmaster@0 86 }
webmaster@0 87 return (object)$obj;
webmaster@0 88 }
webmaster@0 89
webmaster@0 90 function parseReplacement($obj) {
webmaster@0 91 $retVal = NULL;
webmaster@0 92 if(is_string($obj))
webmaster@0 93 $retVal = $this->xmlDocument->createTextNode($obj);
webmaster@0 94 else if($obj instanceof DOMDocument)
webmaster@16 95 $retVal = $this->xmlDocument->importNode($obj->documentElement);
webmaster@16 96 else if($obj instanceof DOMDocumentFragment)
webmaster@16 97 $retVal = $obj;
webmaster@0 98 else if($obj instanceof DOMNode)
webmaster@3 99 $retVal = $obj->clone(true);
webmaster@11 100 else if($obj instanceof Template) {
webmaster@11 101 $node = $obj->xmlDocument->documentElement;
webmaster@11 102 $retVal = $this->xmlDocument->importNode($node, true);
webmaster@11 103 }
webmaster@0 104 return $retVal;
webmaster@0 105 }
webmaster@0 106
webmaster@0 107 function setParams($array) {
webmaster@0 108 foreach($array as $selector => $obj) {
webmaster@0 109 $this->apply($selector, $obj);
webmaster@0 110 }
webmaster@0 111 }
webmaster@0 112
webmaster@0 113 function replaceNode(DOMNode $node, DOMNode $content) {
webmaster@0 114 $parent = $node->parentNode;
webmaster@0 115 $parent->replaceChild($content, $node);
webmaster@0 116 }
webmaster@0 117
webmaster@0 118 function setNodeContent(DOMElement $node, DOMNode $content) {
webmaster@0 119 // Suppress existing childs
webmaster@0 120 foreach($node->childNodes as $child) {
webmaster@0 121 $node->removeChild($child);
webmaster@0 122 }
webmaster@0 123 // Add the new child
webmaster@0 124 $node->appendChild($content);
webmaster@0 125 }
webmaster@0 126
webmaster@0 127 function clean() {
webmaster@0 128 // Suppression des noeuds à cloner
webmaster@8 129 $nodes = $this->xmlXPath->query("//*[@_t:toClone]|//_t:*");
webmaster@0 130 foreach($nodes as $node) {
webmaster@0 131 if($node->parentNode) {
webmaster@15 132 $parent = $node->parentNode;
webmaster@15 133 if(!$node->hasAttributeNS(Template::NS, 'toClone')) {
webmaster@15 134 while($node->hasChildNodes())
webmaster@15 135 $parent->insertBefore($node->firstChild, $node);
webmaster@15 136 }
webmaster@15 137 $parent->removeChild($node);
webmaster@0 138 }
webmaster@0 139 }
webmaster@19 140
webmaster@19 141 // Suppression éventuelle des attributs de l'espace de nom Template::NS
webmaster@19 142 if($this->stripAttributesInTemplateNS) {
webmaster@19 143 $nodes = $this->xmlXPath->query("//*[@_t:*]");
webmaster@19 144 foreach($nodes as $node) {
webmaster@19 145 foreach($node->attributes as $attr) {
webmaster@19 146 if($attr->namespaceURI == Template::NS)
webmaster@19 147 $node->removeAttributeNode($attr);
webmaster@19 148 }
webmaster@19 149 }
webmaster@19 150 }
webmaster@19 151 }
webmaster@19 152
webmaster@19 153 function shouldStripAttributesInTemplateNS($boolean) {
webmaster@19 154 $this->stripAttributesInTemplateNS = $boolean;
webmaster@0 155 }
webmaster@0 156
webmaster@0 157 function __toString() {
webmaster@0 158 $this->clean();
webmaster@9 159 $this->xmlDocument->formatOutput = true;
webmaster@15 160 $this->xmlDocument->normalizeDocument();
webmaster@0 161 return $this->xmlDocument->saveXML();
webmaster@0 162 }
webmaster@16 163
webmaster@16 164 function getDocumentFragment() {
webmaster@16 165 return $this->xmlDocument->createDocumentFragment();
webmaster@16 166 }
webmaster@6 167 }