| 
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 } |