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