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