1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.common.xml;
21
22 import org.dom4j.Document;
23 import org.dom4j.DocumentException;
24 import org.dom4j.DocumentHelper;
25 import org.dom4j.Element;
26 import org.dom4j.Node;
27 import org.dom4j.io.OutputFormat;
28 import org.dom4j.io.SAXReader;
29 import org.dom4j.io.XMLWriter;
30 import org.waarp.common.exception.InvalidArgumentException;
31 import org.waarp.common.utility.WaarpStringUtils;
32 import org.xml.sax.SAXException;
33
34 import java.io.File;
35 import java.io.FileWriter;
36 import java.io.IOException;
37 import java.io.InvalidObjectException;
38 import java.io.Writer;
39 import java.util.List;
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public final class XmlUtil {
54
55 private static final String NODE_NOT_FOUND = "Node not found: ";
56
57 private XmlUtil() {
58 }
59
60
61
62
63 public static SAXReader getNewSaxReader() {
64 final SAXReader saxReader = new SAXReader();
65 try {
66 saxReader.setFeature(
67 "http://apache.org/xml/features/disallow-doctype-decl", true);
68 saxReader.setFeature(
69 "http://apache.org/xml/features/nonvalidating/load-dtd-grammar",
70 false);
71 saxReader.setFeature(
72 "http://apache.org/xml/features/nonvalidating/load-external-dtd",
73 false);
74 saxReader.setFeature("http://xml.org/sax/features/resolve-dtd-uris",
75 false);
76 saxReader.setFeature(
77 "http://xml.org/sax/features/external-general-entities", false);
78 saxReader.setFeature(
79 "http://xml.org/sax/features/external-parameter-entities", false);
80 saxReader.setFeature(
81 "http://apache.org/xml/features/validation/id-idref-checking", false);
82 } catch (final SAXException e) {
83
84 }
85 return saxReader;
86 }
87
88
89
90
91
92
93
94
95
96 public static Document getDocument(final String filename)
97 throws IOException, DocumentException {
98 final File file = new File(filename);
99 if (!file.canRead()) {
100 throw new IOException("File is not readable: " + filename);
101 }
102 return getDocument(file);
103 }
104
105
106
107
108
109
110
111
112
113 public static Document getDocument(final File file)
114 throws IOException, DocumentException {
115 if (!file.canRead()) {
116 throw new IOException("File is not readable: " + file.getPath());
117 }
118 final SAXReader reader = getNewSaxReader();
119 return reader.read(file);
120 }
121
122
123
124
125
126
127
128
129
130
131 public static Document readDocument(final String document)
132 throws DocumentException {
133 return DocumentHelper.parseText(document);
134 }
135
136
137
138
139
140
141 public static String writeToString(final Document document) {
142 return document.asXML();
143 }
144
145
146
147
148
149
150 public static String writeToString(final Element element) {
151 return element.asXML();
152 }
153
154
155
156
157 public static Document createEmptyDocument() {
158 return DocumentHelper.createDocument();
159 }
160
161
162
163
164
165
166
167
168
169 public static void saveDocument(final String filename,
170 final Document document) throws IOException {
171 final File file = new File(filename);
172 saveDocument(file, document);
173 }
174
175
176
177
178
179
180
181
182
183 public static void saveDocument(final File file, final Document document)
184 throws IOException {
185 if (file.exists() && !file.canWrite()) {
186 throw new IOException("File is not writable: " + file.getPath());
187 }
188
189 saveDocument(new FileWriter(file), document);
190 }
191
192
193
194
195
196
197
198
199
200 public static void saveDocument(final Writer outWriter,
201 final Document document) throws IOException {
202 final OutputFormat format = OutputFormat.createPrettyPrint();
203 format.setEncoding(WaarpStringUtils.UTF8.name());
204 final XMLWriter writer = new XMLWriter(outWriter, format);
205 writer.write(document);
206 writer.flush();
207 writer.close();
208 }
209
210
211
212
213
214
215
216
217
218 public static void saveElement(final String filename, final Element element)
219 throws IOException {
220 final File file = new File(filename);
221 saveElement(file, element);
222 }
223
224
225
226
227
228
229
230
231
232 public static void saveElement(final File file, final Element element)
233 throws IOException {
234 if (file.exists() && !file.canWrite()) {
235 throw new IOException("File is not writable: " + file.getPath());
236 }
237 final OutputFormat format = OutputFormat.createPrettyPrint();
238 format.setEncoding(WaarpStringUtils.UTF8.name());
239 final XMLWriter writer = new XMLWriter(new FileWriter(file), format);
240 writer.write(element);
241 writer.flush();
242 writer.close();
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256 public static Element addOrSetElement(final Element ref, final String path,
257 final String value) {
258 final Element current = addOrGetElement(ref, path);
259 current.setText(value);
260 return current;
261 }
262
263
264
265
266
267
268
269
270
271
272 public static Element addOrGetElement(final Element ref, final String path) {
273 final String[] pathes = path.split("/");
274 Element current = ref;
275 for (final String nodename : pathes) {
276 if (!nodename.isEmpty()) {
277 final Element exist = current.element(nodename);
278 if (exist == null) {
279 current = current.addElement(nodename);
280 } else {
281 current = exist;
282 }
283 }
284 }
285 return current;
286 }
287
288
289
290
291
292
293
294
295
296
297
298 public static Element addAndSetElementMultiple(final Element ref,
299 final String path,
300 final String value) {
301 final Element current = addAndGetElementMultiple(ref, path);
302 current.setText(value);
303 return current;
304 }
305
306
307
308
309
310
311
312
313
314 public static Element addAndGetElementMultiple(final Element ref,
315 final String path) {
316 final String[] pathes = path.split("/");
317 Element current = ref;
318 for (int i = 0; i < pathes.length - 1; i++) {
319 final String nodename = pathes[i];
320 if (!nodename.isEmpty()) {
321 final Element exist = current.element(nodename);
322 if (exist == null) {
323 current = current.addElement(nodename);
324 } else {
325 current = exist;
326 }
327 }
328 }
329 final String nodename = pathes[pathes.length - 1];
330 if (!nodename.isEmpty()) {
331 current = current.addElement(nodename);
332 }
333 return current;
334 }
335
336
337
338
339
340
341
342
343
344
345 public static Element getParentElement(final Element ref, final String path)
346 throws DocumentException {
347 String npath = path;
348 while (npath.charAt(0) == '/') {
349 npath = npath.substring(1);
350 }
351 final Element current = (Element) ref.selectSingleNode(npath);
352 if (current == null) {
353 throw new DocumentException(NODE_NOT_FOUND + path);
354 }
355 return current.getParent();
356 }
357
358
359
360
361
362
363
364
365
366
367 public static Element getElement(final Element ref, final String path)
368 throws DocumentException {
369 String npath = path;
370 while (npath.charAt(0) == '/') {
371 npath = npath.substring(1);
372 }
373 final Element current = (Element) ref.selectSingleNode(npath);
374 if (current == null) {
375 throw new DocumentException(NODE_NOT_FOUND + path);
376 }
377 return current;
378 }
379
380
381
382
383
384
385
386
387
388
389 public static List<Node> getElementMultiple(final Element ref,
390 final String path)
391 throws DocumentException {
392 String npath = path;
393 while (npath.charAt(0) == '/') {
394 npath = npath.substring(1);
395 }
396 final List<Node> list = ref.selectNodes(npath);
397 if (list == null || list.isEmpty()) {
398 throw new DocumentException("Nodes not found: " + path);
399 }
400 return list;
401 }
402
403
404
405
406
407
408
409
410
411
412
413 public static Element addOrSetElement(final Document doc, final String path,
414 final String value) {
415 final Element current = addOrGetElement(doc, path);
416 if (current != null) {
417 current.setText(value);
418 }
419 return current;
420 }
421
422
423
424
425
426
427
428
429
430
431 public static Element addOrGetElement(final Document doc, final String path) {
432 final String[] pathes = path.split("/");
433 int rank;
434 for (rank = 0; rank < pathes.length; rank++) {
435 if (!pathes[rank].isEmpty()) {
436 break;
437 }
438 }
439 if (rank >= pathes.length) {
440 return null;
441 }
442 Element current = (Element) doc.selectSingleNode(pathes[rank]);
443 if (current == null) {
444 current = doc.addElement(pathes[rank]);
445 }
446 for (int i = rank + 1; i < pathes.length; i++) {
447 final String nodename = pathes[i];
448 if (!nodename.isEmpty()) {
449 final Element exist = current.element(nodename);
450 if (exist == null) {
451 current = current.addElement(nodename);
452 } else {
453 current = exist;
454 }
455 }
456 }
457 return current;
458 }
459
460
461
462
463
464
465
466
467
468
469
470 public static Element addAndSetElementMultiple(final Document doc,
471 final String path,
472 final String value) {
473 final Element current = addAndGetElementMultiple(doc, path);
474 if (current != null) {
475 current.setText(value);
476 }
477 return current;
478 }
479
480
481
482
483
484
485
486
487
488 public static Element addAndGetElementMultiple(final Document doc,
489 final String path) {
490 final String[] pathes = path.split("/");
491 int rank;
492 for (rank = 0; rank < pathes.length; rank++) {
493 if (!pathes[rank].isEmpty()) {
494 break;
495 }
496 }
497 if (rank >= pathes.length) {
498 return null;
499 }
500 Element current = (Element) doc.selectSingleNode(pathes[rank]);
501 if (current == null) {
502 current = doc.addElement(pathes[rank]);
503 }
504 if (rank == pathes.length - 1) {
505
506
507 return current;
508 }
509 for (int i = rank + 1; i < pathes.length - 1; i++) {
510 final String nodename = pathes[i];
511 if (!nodename.isEmpty()) {
512 final Element exist = current.element(nodename);
513 if (exist == null) {
514 current = current.addElement(nodename);
515 } else {
516 current = exist;
517 }
518 }
519 }
520 final String nodename = pathes[pathes.length - 1];
521 if (!nodename.isEmpty()) {
522 current = current.addElement(nodename);
523 }
524 return current;
525 }
526
527
528
529
530
531
532
533
534
535
536 public static Element getParentElement(final Document doc, final String path)
537 throws DocumentException {
538 final Element current = (Element) doc.selectSingleNode(path);
539 if (current == null) {
540 throw new DocumentException(NODE_NOT_FOUND + path);
541 }
542 return current.getParent();
543 }
544
545
546
547
548
549
550
551
552
553 public static Element getElement(final Document doc, final String path)
554 throws DocumentException {
555 final Element current = (Element) doc.selectSingleNode(path);
556 if (current == null) {
557 throw new DocumentException(NODE_NOT_FOUND + path);
558 }
559 return current;
560 }
561
562
563
564
565
566
567
568
569
570 public static List<Node> getElementMultiple(final Document doc,
571 final String path)
572 throws DocumentException {
573 final List<Node> list = doc.selectNodes(path);
574 if (list == null || list.isEmpty()) {
575 throw new DocumentException("Nodes not found: " + path);
576 }
577 return list;
578 }
579
580
581
582
583
584
585
586
587 public static String getExtraTrimed(final String string) {
588 return string.replaceAll("[\\s]+", " ").trim();
589
590 }
591
592
593
594
595
596
597
598
599
600 public static XmlValue[] read(final Document doc, final XmlDecl[] decls) {
601 final XmlValue[] values;
602 final int len = decls.length;
603 values = new XmlValue[len];
604 for (int i = 0; i < len; i++) {
605 final XmlValue value = new XmlValue(decls[i]);
606 values[i] = value;
607 if (decls[i].isSubXml()) {
608 if (decls[i].isMultiple()) {
609 final List<Node> elts;
610 try {
611 elts = getElementMultiple(doc, decls[i].getXmlPath());
612 } catch (final DocumentException e) {
613 continue;
614 }
615 addValueToNodes(value, elts, decls[i]);
616 } else {
617 final Element element;
618 try {
619 element = getElement(doc, decls[i].getXmlPath());
620 } catch (final DocumentException e) {
621 continue;
622 }
623 setValueToElement(value, read(element, decls[i].getSubXml()));
624 }
625 } else if (decls[i].isMultiple()) {
626 final List<Node> elts;
627 try {
628 elts = getElementMultiple(doc, decls[i].getXmlPath());
629 } catch (final DocumentException e) {
630 continue;
631 }
632 addFromStringToElements(value, elts);
633 } else {
634 final Element element;
635 try {
636 element = getElement(doc, decls[i].getXmlPath());
637 } catch (final DocumentException e) {
638 continue;
639 }
640 final String svalue = element.getText();
641 try {
642 value.setFromString(getExtraTrimed(svalue));
643 } catch (final InvalidArgumentException e) {
644
645 }
646 }
647 }
648 return values;
649 }
650
651
652
653
654
655
656
657
658
659 public static XmlValue[] read(final Element ref, final XmlDecl[] decls) {
660 final XmlValue[] values;
661 final int len = decls.length;
662 values = new XmlValue[len];
663 for (int i = 0; i < len; i++) {
664 final XmlValue value = new XmlValue(decls[i]);
665 values[i] = value;
666 if (decls[i].isSubXml()) {
667 if (decls[i].isMultiple()) {
668 final List<Node> elts;
669 try {
670 elts = getElementMultiple(ref, decls[i].getXmlPath());
671 } catch (final DocumentException e) {
672 continue;
673 }
674 addValueToNodes(value, elts, decls[i]);
675 } else {
676 final Element element;
677 try {
678 element = getElement(ref, decls[i].getXmlPath());
679 } catch (final DocumentException e) {
680 continue;
681 }
682 setValueToElement(value, read(element, decls[i].getSubXml()));
683 }
684 } else if (decls[i].isMultiple()) {
685 final List<Node> elts;
686 try {
687 elts = getElementMultiple(ref, decls[i].getXmlPath());
688 } catch (final DocumentException e) {
689 continue;
690 }
691 addFromStringToElements(value, elts);
692 } else {
693 final Element element;
694 try {
695 element = getElement(ref, decls[i].getXmlPath());
696 } catch (final DocumentException e) {
697 continue;
698 }
699 final String svalue = element.getText();
700 try {
701 value.setFromString(getExtraTrimed(svalue));
702 } catch (final InvalidArgumentException e) {
703
704 }
705 }
706 }
707 return values;
708 }
709
710 private static void addFromStringToElements(final XmlValue value,
711 final List<Node> elts) {
712 for (final Node element : elts) {
713 final String svalue = element.getText();
714 try {
715 value.addFromString(getExtraTrimed(svalue));
716 } catch (final InvalidObjectException e) {
717
718 } catch (final InvalidArgumentException e) {
719
720 }
721 }
722 }
723
724 private static void setValueToElement(final XmlValue value,
725 final XmlValue[] read) {
726 if (read == null) {
727 return;
728 }
729 try {
730 value.setValue(read);
731 } catch (final InvalidObjectException e) {
732
733 }
734 }
735
736 private static void addValueToNodes(final XmlValue value,
737 final List<Node> elts,
738 final XmlDecl decl) {
739 for (final Node element : elts) {
740 final XmlValue[] newValue = read((Element) element, decl.getSubXml());
741 try {
742 value.addValue(newValue);
743 } catch (final InvalidObjectException e) {
744
745 }
746 }
747 }
748
749
750
751
752
753
754
755 @SuppressWarnings("unchecked")
756 public static void write(final Document doc, final XmlValue[] values) {
757 for (final XmlValue value : values) {
758 if (value != null) {
759 if (value.isSubXml()) {
760 if (value.isMultiple()) {
761 final List<XmlValue[]> list = (List<XmlValue[]>) value.getList();
762 for (final XmlValue[] object : list) {
763 final Element ref =
764 addAndGetElementMultiple(doc, value.getXmlPath());
765 write(ref, object);
766 }
767 } else {
768 final Element ref = addOrGetElement(doc, value.getXmlPath());
769 write(ref, value.getSubXml());
770 }
771 } else if (value.isMultiple()) {
772 final List<?> list = value.getList();
773 for (final Object object : list) {
774 addAndSetElementMultiple(doc, value.getXmlPath(),
775 object.toString());
776 }
777 } else {
778 addOrSetElement(doc, value.getXmlPath(), value.getIntoString());
779 }
780 }
781 }
782 }
783
784
785
786
787
788
789
790 @SuppressWarnings("unchecked")
791 public static void write(final Element ref, final XmlValue[] values) {
792 for (final XmlValue value : values) {
793 if (value != null) {
794 if (value.isSubXml()) {
795 if (value.isMultiple()) {
796 final List<XmlValue[]> list = (List<XmlValue[]>) value.getList();
797 for (final XmlValue[] object : list) {
798 final Element newref =
799 addAndGetElementMultiple(ref, value.getXmlPath());
800 write(newref, object);
801 }
802 } else {
803 final Element newref = addOrGetElement(ref, value.getXmlPath());
804 write(newref, value.getSubXml());
805 }
806 } else if (value.isMultiple()) {
807 final List<?> list = value.getList();
808 for (final Object object : list) {
809 addAndSetElementMultiple(ref, value.getXmlPath(),
810 object.toString());
811 }
812 } else {
813 addOrSetElement(ref, value.getXmlPath(), value.getIntoString());
814 }
815 }
816 }
817 }
818
819
820
821
822
823
824
825
826
827
828 public static void writeXML(final String filename, final String encoding,
829 final Document document) throws IOException {
830 final OutputFormat format = OutputFormat.createPrettyPrint();
831 if (encoding != null) {
832 format.setEncoding(encoding);
833 } else {
834 format.setEncoding(WaarpStringUtils.UTF8.name());
835 }
836 final XMLWriter writer;
837 writer = new XMLWriter(new FileWriter(filename), format);
838 writer.write(document);
839 try {
840 writer.close();
841 } catch (final IOException ignored) {
842
843 }
844 }
845 }