1 | <?php |
||
17 | class Parser extends IRProcessor |
||
18 | { |
||
19 | /** |
||
20 | * @var Normalizer |
||
21 | */ |
||
22 | protected $normalizer; |
||
23 | |||
24 | /** |
||
25 | * @param Normalizer $normalizer |
||
26 | * @return void |
||
27 | */ |
||
28 | public function __construct(Normalizer $normalizer) |
||
29 | { |
||
30 | $this->normalizer = $normalizer; |
||
31 | } |
||
32 | |||
33 | /** |
||
34 | * Parse a template into an internal representation |
||
35 | * |
||
36 | * @param string $template Source template |
||
37 | * @return DOMDocument Internal representation |
||
38 | */ |
||
39 | public function parse($template) |
||
40 | { |
||
41 | $dom = TemplateHelper::loadTemplate($template); |
||
42 | |||
43 | $ir = new DOMDocument; |
||
44 | $ir->loadXML('<template/>'); |
||
45 | |||
46 | $this->createXPath($dom); |
||
47 | $this->parseChildren($ir->documentElement, $dom->documentElement); |
||
48 | $this->normalizer->normalize($ir); |
||
49 | |||
50 | return $ir; |
||
51 | } |
||
52 | |||
53 | /** |
||
54 | * Append <output/> elements corresponding to given AVT |
||
55 | * |
||
56 | * @param DOMElement $parentNode Parent node |
||
57 | * @param string $avt Attribute value template |
||
58 | * @return void |
||
59 | */ |
||
60 | protected function appendAVT(DOMElement $parentNode, $avt) |
||
74 | |||
75 | /** |
||
76 | * Append an <output/> element with literal content to given node |
||
77 | * |
||
78 | * @param DOMElement $parentNode Parent node |
||
79 | * @param string $content Content to output |
||
80 | * @return void |
||
81 | */ |
||
82 | protected function appendLiteralOutput(DOMElement $parentNode, $content) |
||
83 | { |
||
84 | if ($content === '') |
||
85 | { |
||
86 | return; |
||
87 | } |
||
88 | |||
89 | $this->appendElement($parentNode, 'output', htmlspecialchars($content)) |
||
90 | ->setAttribute('type', 'literal'); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Append an <output/> element for given XPath expression to given node |
||
95 | * |
||
96 | * @param DOMElement $parentNode Parent node |
||
97 | * @param string $expr XPath expression |
||
98 | * @return void |
||
99 | */ |
||
100 | protected function appendXPathOutput(DOMElement $parentNode, $expr) |
||
101 | { |
||
102 | $this->appendElement($parentNode, 'output', htmlspecialchars(trim($expr))) |
||
103 | ->setAttribute('type', 'xpath'); |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Parse all the children of a given element |
||
108 | * |
||
109 | * @param DOMElement $ir Node in the internal representation that represents the parent node |
||
110 | * @param DOMElement $parent Parent node |
||
111 | * @return void |
||
112 | */ |
||
113 | protected function parseChildren(DOMElement $ir, DOMElement $parent) |
||
139 | |||
140 | /** |
||
141 | * Parse a given node into the internal representation |
||
142 | * |
||
143 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
144 | * @param DOMElement $node Node to parse |
||
145 | * @return void |
||
146 | */ |
||
147 | protected function parseNode(DOMElement $ir, DOMElement $node) |
||
190 | |||
191 | /** |
||
192 | * Parse an <xsl:apply-templates/> node into the internal representation |
||
193 | * |
||
194 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
195 | * @param DOMElement $node <xsl:apply-templates/> node |
||
196 | * @return void |
||
197 | */ |
||
198 | protected function parseXslApplyTemplates(DOMElement $ir, DOMElement $node) |
||
199 | { |
||
200 | $applyTemplates = $this->appendElement($ir, 'applyTemplates'); |
||
201 | if ($node->hasAttribute('select')) |
||
202 | { |
||
203 | $applyTemplates->setAttribute('select', $node->getAttribute('select')); |
||
204 | } |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Parse an <xsl:attribute/> node into the internal representation |
||
209 | * |
||
210 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
211 | * @param DOMElement $node <xsl:attribute/> node |
||
212 | * @return void |
||
213 | */ |
||
214 | protected function parseXslAttribute(DOMElement $ir, DOMElement $node) |
||
215 | { |
||
216 | $attribute = $this->appendElement($ir, 'attribute'); |
||
217 | $attribute->setAttribute('name', $node->getAttribute('name')); |
||
218 | $this->parseChildren($attribute, $node); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Parse an <xsl:choose/> node and its <xsl:when/> and <xsl:otherwise/> children into the |
||
223 | * internal representation |
||
224 | * |
||
225 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
226 | * @param DOMElement $node <xsl:choose/> node |
||
227 | * @return void |
||
228 | */ |
||
229 | protected function parseXslChoose(DOMElement $ir, DOMElement $node) |
||
230 | { |
||
231 | $switch = $this->appendElement($ir, 'switch'); |
||
232 | foreach ($this->query('./xsl:when', $node) as $when) |
||
233 | { |
||
234 | // Create a <case/> element with the original test condition in @test |
||
235 | $case = $this->appendElement($switch, 'case'); |
||
236 | $case->setAttribute('test', $when->getAttribute('test')); |
||
237 | $this->parseChildren($case, $when); |
||
238 | } |
||
239 | |||
240 | // Add the default branch, which is presumed to be last |
||
241 | foreach ($this->query('./xsl:otherwise', $node) as $otherwise) |
||
242 | { |
||
243 | $case = $this->appendElement($switch, 'case'); |
||
244 | $this->parseChildren($case, $otherwise); |
||
245 | |||
246 | // There should be only one <xsl:otherwise/> but we'll break anyway |
||
247 | break; |
||
248 | } |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Parse an <xsl:comment/> node into the internal representation |
||
253 | * |
||
254 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
255 | * @param DOMElement $node <xsl:comment/> node |
||
256 | * @return void |
||
257 | */ |
||
258 | protected function parseXslComment(DOMElement $ir, DOMElement $node) |
||
259 | { |
||
260 | $comment = $this->appendElement($ir, 'comment'); |
||
261 | $this->parseChildren($comment, $node); |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Parse an <xsl:copy-of/> node into the internal representation |
||
266 | * |
||
267 | * NOTE: only attributes are supported |
||
268 | * |
||
269 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
270 | * @param DOMElement $node <xsl:copy-of/> node |
||
271 | * @return void |
||
272 | */ |
||
273 | protected function parseXslCopyOf(DOMElement $ir, DOMElement $node) |
||
305 | |||
306 | /** |
||
307 | * Parse an <xsl:element/> node into the internal representation |
||
308 | * |
||
309 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
310 | * @param DOMElement $node <xsl:element/> node |
||
311 | * @return void |
||
312 | */ |
||
313 | protected function parseXslElement(DOMElement $ir, DOMElement $node) |
||
314 | { |
||
315 | $element = $this->appendElement($ir, 'element'); |
||
316 | $element->setAttribute('name', $node->getAttribute('name')); |
||
317 | $this->parseChildren($element, $node); |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * Parse an <xsl:if/> node into the internal representation |
||
322 | * |
||
323 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
324 | * @param DOMElement $node <xsl:if/> node |
||
325 | * @return void |
||
326 | */ |
||
327 | protected function parseXslIf(DOMElement $ir, DOMElement $node) |
||
337 | |||
338 | /** |
||
339 | * Parse an <xsl:text/> node into the internal representation |
||
340 | * |
||
341 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
342 | * @param DOMElement $node <xsl:text/> node |
||
343 | * @return void |
||
344 | */ |
||
345 | protected function parseXslText(DOMElement $ir, DOMElement $node) |
||
353 | |||
354 | /** |
||
355 | * Parse an <xsl:value-of/> node into the internal representation |
||
356 | * |
||
357 | * @param DOMElement $ir Node in the internal representation that represents the node's parent |
||
358 | * @param DOMElement $node <xsl:value-of/> node |
||
359 | * @return void |
||
360 | */ |
||
361 | protected function parseXslValueOf(DOMElement $ir, DOMElement $node) |
||
369 | } |