1 package org.apache.velocity.tools.generic;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.StringWriter;
23 import java.net.URL;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import org.dom4j.Attribute;
31 import org.dom4j.Node;
32 import org.dom4j.Element;
33 import org.dom4j.Document;
34 import org.dom4j.DocumentHelper;
35 import org.dom4j.io.XMLWriter;
36 import org.dom4j.io.SAXReader;
37 import org.apache.velocity.runtime.log.Log;
38 import org.apache.velocity.tools.ConversionUtils;
39 import org.apache.velocity.tools.ToolContext;
40 import org.apache.velocity.tools.config.DefaultKey;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 @DefaultKey("xml")
77 public class XmlTool extends SafeConfig
78 {
79 public static final String FILE_KEY = "file";
80
81 protected Log LOG;
82
83 private List<Node> nodes;
84
85 public XmlTool() {}
86
87 public XmlTool(Node node)
88 {
89 this(Collections.singletonList(node));
90 }
91
92 public XmlTool(List<Node> nodes)
93 {
94 this.nodes = nodes;
95 }
96
97
98
99
100
101
102
103
104 protected void configure(ValueParser parser)
105 {
106 this.LOG = (Log)parser.getValue(ToolContext.LOG_KEY);
107
108 String file = parser.getString(FILE_KEY);
109 if (file != null)
110 {
111 try
112 {
113 read(file);
114 }
115 catch (IllegalArgumentException iae)
116 {
117 throw iae;
118 }
119 catch (Exception e)
120 {
121 throw new RuntimeException("Could not read XML file at: "+file, e);
122 }
123 }
124 }
125
126
127
128
129 protected void setRoot(Node node)
130 {
131 if (node instanceof Document)
132 {
133 node = ((Document)node).getRootElement();
134 }
135 this.nodes = new ArrayList<Node>(1);
136 this.nodes.add(node);
137 }
138
139 private void log(Object o, Throwable t)
140 {
141 if (LOG != null)
142 {
143 LOG.debug("XmlTool - "+o, t);
144 }
145 }
146
147
148
149
150 protected void read(String file) throws Exception
151 {
152 URL url = ConversionUtils.toURL(file, this);
153 if (url == null)
154 {
155 throw new IllegalArgumentException("Could not find file, classpath resource or standard URL for '"+file+"'.");
156 }
157 read(url);
158 }
159
160
161
162
163
164 protected void read(URL url) throws Exception
165 {
166 SAXReader reader = new SAXReader();
167 setRoot(reader.read(url));
168 }
169
170
171
172
173
174 protected void parse(String xml) throws Exception
175 {
176 setRoot(DocumentHelper.parseText(xml));
177 }
178
179
180
181
182
183
184
185
186
187
188 public XmlTool read(Object o)
189 {
190 if (isSafeMode() || o == null)
191 {
192 return null;
193 }
194 try
195 {
196 XmlTool xml = new XmlTool();
197 if (o instanceof URL)
198 {
199 xml.read((URL)o);
200 }
201 else
202 {
203 String file = String.valueOf(o);
204 xml.read(file);
205 }
206 return xml;
207 }
208 catch (Exception e)
209 {
210 log("Failed to read XML from : "+o, e);
211 return null;
212 }
213 }
214
215
216
217
218
219
220
221 public XmlTool parse(Object o)
222 {
223 if (o == null)
224 {
225 return null;
226 }
227 String s = String.valueOf(o);
228 try
229 {
230 XmlTool xml = new XmlTool();
231 xml.parse(s);
232 return xml;
233 }
234 catch (Exception e)
235 {
236 log("Failed to parse XML from : "+o, e);
237 return null;
238 }
239 }
240
241
242
243
244
245
246
247
248
249
250
251
252
253 public Object get(Object o)
254 {
255 if (isEmpty() || o == null)
256 {
257 return null;
258 }
259 String attr = attr(o);
260 if (attr != null)
261 {
262 return attr;
263 }
264 Number i = ConversionUtils.toNumber(o);
265 if (i != null)
266 {
267 return get(i);
268 }
269 String s = String.valueOf(o);
270 if (s.length() == 0)
271 {
272 return null;
273 }
274 if (s.indexOf('/') < 0)
275 {
276 s = getPath()+'/'+s;
277 }
278 return find(s);
279 }
280
281
282
283
284
285
286 public Object getName()
287 {
288
289 Object name = get("name");
290 if (name != null)
291 {
292 return name;
293 }
294 return getNodeName();
295 }
296
297
298
299
300
301
302 public String getNodeName()
303 {
304 if (isEmpty())
305 {
306 return null;
307 }
308 return node().getName();
309 }
310
311
312
313
314
315 public String getPath()
316 {
317 if (isEmpty())
318 {
319 return null;
320 }
321 return node().getPath();
322 }
323
324
325
326
327
328
329
330
331 public String attr(Object o)
332 {
333 if (o == null)
334 {
335 return null;
336 }
337 String key = String.valueOf(o);
338 Node node = node();
339 if (node instanceof Element)
340 {
341 return ((Element)node).attributeValue(key);
342 }
343 return null;
344 }
345
346
347
348
349
350
351 public Map<String,String> attributes()
352 {
353 Node node = node();
354 if (node instanceof Element)
355 {
356 Map<String,String> attrs = new HashMap<String,String>();
357 for (Iterator i = ((Element)node).attributeIterator(); i.hasNext();)
358 {
359 Attribute a = (Attribute)i.next();
360 attrs.put(a.getName(), a.getValue());
361 }
362 return attrs;
363 }
364 return null;
365 }
366
367
368
369
370
371
372 public boolean isEmpty()
373 {
374 return (nodes == null || nodes.isEmpty());
375 }
376
377
378
379
380 public int size()
381 {
382 if (isEmpty())
383 {
384 return 0;
385 }
386 return nodes.size();
387 }
388
389
390
391
392
393 public Iterator<XmlTool> iterator()
394 {
395 if (isEmpty())
396 {
397 return null;
398 }
399 return new NodeIterator(nodes.iterator());
400 }
401
402
403
404
405
406 public XmlTool getFirst()
407 {
408 if (size() == 1)
409 {
410 return this;
411 }
412 return new XmlTool(node());
413 }
414
415
416
417
418
419 public XmlTool getLast()
420 {
421 if (size() == 1)
422 {
423 return this;
424 }
425 return new XmlTool(nodes.get(size() - 1));
426 }
427
428
429
430
431
432 public XmlTool get(Number n)
433 {
434 if (n == null)
435 {
436 return null;
437 }
438 int i = n.intValue();
439 if (i < 0 || i > size() - 1)
440 {
441 return null;
442 }
443 return new XmlTool(nodes.get(i));
444 }
445
446
447
448
449
450 public Node node()
451 {
452 if (isEmpty())
453 {
454 return null;
455 }
456 return nodes.get(0);
457 }
458
459
460
461
462
463
464 public XmlTool find(Object o)
465 {
466 if (o == null || isEmpty())
467 {
468 return null;
469 }
470 return find(String.valueOf(o));
471 }
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486 public XmlTool find(String xpath)
487 {
488 if (xpath == null || xpath.length() == 0)
489 {
490 return null;
491 }
492 if (xpath.indexOf('/') < 0)
493 {
494 xpath = "//"+xpath;
495 }
496 List<Node> found = new ArrayList<Node>();
497 for (Node n : nodes)
498 {
499 found.addAll((List<Node>)n.selectNodes(xpath));
500 }
501 if (found.isEmpty())
502 {
503 return null;
504 }
505 return new XmlTool(found);
506 }
507
508
509
510
511
512
513 public XmlTool getParent()
514 {
515 if (isEmpty())
516 {
517 return null;
518 }
519 Element parent = node().getParent();
520 if (parent == null)
521 {
522 return null;
523 }
524 return new XmlTool(parent);
525 }
526
527
528
529
530
531
532
533 public XmlTool parents()
534 {
535 if (isEmpty())
536 {
537 return null;
538 }
539 if (size() == 1)
540 {
541 return getParent();
542 }
543 List<Node> parents = new ArrayList<Node>(size());
544 for (Node n : nodes)
545 {
546 Element parent = n.getParent();
547 if (parent != null && !parents.contains(parent))
548 {
549 parents.add(parent);
550 }
551 }
552 if (parents.isEmpty())
553 {
554 return null;
555 }
556 return new XmlTool(parents);
557 }
558
559
560
561
562
563
564 public XmlTool children()
565 {
566 if (isEmpty())
567 {
568 return null;
569 }
570 List<Node> kids = new ArrayList<Node>();
571 for (Node n : nodes)
572 {
573 if (n instanceof Element)
574 {
575 kids.addAll((List<Node>)((Element)n).elements());
576 }
577 }
578 return new XmlTool(kids);
579 }
580
581
582
583
584
585 public String getText()
586 {
587 if (isEmpty())
588 {
589 return null;
590 }
591 StringBuilder out = new StringBuilder();
592 for (Node n : nodes)
593 {
594 String text = n.getText();
595 if (text != null)
596 {
597 out.append(text);
598 }
599 }
600 String result = out.toString().trim();
601 if (result.length() > 0)
602 {
603 return result;
604 }
605 return null;
606 }
607
608
609
610
611
612
613
614
615
616 public String toString()
617 {
618 if (isEmpty())
619 {
620 return super.toString();
621 }
622 StringBuilder out = new StringBuilder();
623 for (Node n : nodes)
624 {
625 if (n instanceof Attribute)
626 {
627 out.append(n.getText().trim());
628 }
629 else
630 {
631 out.append(n.asXML());
632 }
633 }
634 return out.toString();
635 }
636
637
638
639
640
641
642
643 public static class NodeIterator implements Iterator<XmlTool>
644 {
645 private Iterator<Node> i;
646
647 public NodeIterator(Iterator<Node> i)
648 {
649 this.i = i;
650 }
651
652 public boolean hasNext()
653 {
654 return i.hasNext();
655 }
656
657 public XmlTool next()
658 {
659 return new XmlTool(i.next());
660 }
661
662 public void remove()
663 {
664 i.remove();
665 }
666 }
667 }