1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.configuration2;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.Reader;
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.io.Writer;
26 import java.net.URL;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Map;
33
34 import javax.xml.parsers.DocumentBuilder;
35 import javax.xml.parsers.DocumentBuilderFactory;
36 import javax.xml.parsers.ParserConfigurationException;
37 import javax.xml.transform.OutputKeys;
38 import javax.xml.transform.Result;
39 import javax.xml.transform.Source;
40 import javax.xml.transform.Transformer;
41 import javax.xml.transform.dom.DOMSource;
42 import javax.xml.transform.stream.StreamResult;
43
44 import org.apache.commons.configuration2.convert.ListDelimiterHandler;
45 import org.apache.commons.configuration2.ex.ConfigurationException;
46 import org.apache.commons.configuration2.io.ConfigurationLogger;
47 import org.apache.commons.configuration2.io.FileLocator;
48 import org.apache.commons.configuration2.io.FileLocatorAware;
49 import org.apache.commons.configuration2.io.InputStreamSupport;
50 import org.apache.commons.configuration2.resolver.DefaultEntityResolver;
51 import org.apache.commons.configuration2.tree.ImmutableNode;
52 import org.apache.commons.configuration2.tree.NodeTreeWalker;
53 import org.apache.commons.configuration2.tree.ReferenceNodeHandler;
54 import org.apache.commons.lang3.StringUtils;
55 import org.apache.commons.lang3.mutable.MutableObject;
56 import org.w3c.dom.Attr;
57 import org.w3c.dom.CDATASection;
58 import org.w3c.dom.Document;
59 import org.w3c.dom.Element;
60 import org.w3c.dom.NamedNodeMap;
61 import org.w3c.dom.Node;
62 import org.w3c.dom.NodeList;
63 import org.w3c.dom.Text;
64 import org.xml.sax.EntityResolver;
65 import org.xml.sax.InputSource;
66 import org.xml.sax.SAXException;
67 import org.xml.sax.SAXParseException;
68 import org.xml.sax.helpers.DefaultHandler;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 public class XMLConfiguration extends BaseHierarchicalConfiguration implements FileBasedConfiguration, FileLocatorAware, InputStreamSupport {
172
173
174
175 static class XMLBuilderVisitor extends BuilderVisitor {
176
177
178
179
180
181 private static void clearAttributes(final Element elem) {
182 final NamedNodeMap attributes = elem.getAttributes();
183 for (int i = 0; i < attributes.getLength(); i++) {
184 elem.removeAttribute(attributes.item(i).getNodeName());
185 }
186 }
187
188
189
190
191
192
193
194
195
196 private static Text findTextNodeForUpdate(final Element elem) {
197 Text result = null;
198
199 final NodeList children = elem.getChildNodes();
200 final Collection<Node> textNodes = new ArrayList<>();
201 for (int i = 0; i < children.getLength(); i++) {
202 final Node nd = children.item(i);
203 if (nd instanceof Text) {
204 if (result == null) {
205 result = (Text) nd;
206 } else {
207 textNodes.add(nd);
208 }
209 }
210 }
211
212
213 if (result instanceof CDATASection) {
214 textNodes.add(result);
215 result = null;
216 }
217
218
219 textNodes.forEach(elem::removeChild);
220 return result;
221 }
222
223
224
225
226
227
228
229 private static void updateAttributes(final ImmutableNode node, final Element elem) {
230 if (node != null && elem != null) {
231 clearAttributes(elem);
232 node.getAttributes().forEach((k, v) -> {
233 if (v != null) {
234 elem.setAttribute(k, v.toString());
235 }
236 });
237 }
238 }
239
240
241 private final Document document;
242
243
244 private final Map<Node, Node> elementMapping;
245
246
247 private final Map<ImmutableNode, Element> newElements;
248
249
250 private final ListDelimiterHandler listDelimiterHandler;
251
252
253
254
255
256
257
258 public XMLBuilderVisitor(final XMLDocumentHelper docHelper, final ListDelimiterHandler handler) {
259 document = docHelper.getDocument();
260 elementMapping = docHelper.getElementMapping();
261 listDelimiterHandler = handler;
262 newElements = new HashMap<>();
263 }
264
265
266
267
268
269
270
271
272 private Element getElement(final ImmutableNode node, final ReferenceNodeHandler refHandler) {
273 final Element elementNew = newElements.get(node);
274 if (elementNew != null) {
275 return elementNew;
276 }
277
278
279 final Object reference = refHandler.getReference(node);
280 final Node element;
281 if (reference instanceof XMLDocumentHelper) {
282 element = ((XMLDocumentHelper) reference).getDocument().getDocumentElement();
283 } else if (reference instanceof XMLListReference) {
284 element = ((XMLListReference) reference).getElement();
285 } else {
286 element = (Node) reference;
287 }
288 return element != null ? (Element) elementMapping.get(element) : document.getDocumentElement();
289 }
290
291
292
293
294
295
296
297 public void handleRemovedNodes(final ReferenceNodeHandler refHandler) {
298 refHandler.removedReferences().stream().filter(Node.class::isInstance).forEach(ref -> removeReference(elementMapping.get(ref)));
299 }
300
301
302
303
304
305 @Override
306 protected void insert(final ImmutableNode newNode, final ImmutableNode parent, final ImmutableNode sibling1, final ImmutableNode sibling2,
307 final ReferenceNodeHandler refHandler) {
308 if (XMLListReference.isListNode(newNode, refHandler)) {
309 return;
310 }
311
312 final Element elem = document.createElement(newNode.getNodeName());
313 newElements.put(newNode, elem);
314 updateAttributes(newNode, elem);
315 if (newNode.getValue() != null) {
316 final String txt = String.valueOf(listDelimiterHandler.escape(newNode.getValue(), ListDelimiterHandler.NOOP_TRANSFORMER));
317 elem.appendChild(document.createTextNode(txt));
318 }
319 if (sibling2 == null) {
320 getElement(parent, refHandler).appendChild(elem);
321 } else if (sibling1 != null) {
322 getElement(parent, refHandler).insertBefore(elem, getElement(sibling1, refHandler).getNextSibling());
323 } else {
324 getElement(parent, refHandler).insertBefore(elem, getElement(parent, refHandler).getFirstChild());
325 }
326 }
327
328
329
330
331
332
333 public void processDocument(final ReferenceNodeHandler refHandler) {
334 updateAttributes(refHandler.getRootNode(), document.getDocumentElement());
335 NodeTreeWalker.INSTANCE.walkDFS(refHandler.getRootNode(), this, refHandler);
336 }
337
338
339
340
341
342
343 private void removeReference(final Node element) {
344 final Node parentElem = element.getParentNode();
345 if (parentElem != null) {
346 parentElem.removeChild(element);
347 }
348 }
349
350
351
352
353
354 @Override
355 protected void update(final ImmutableNode node, final Object reference, final ReferenceNodeHandler refHandler) {
356 if (XMLListReference.isListNode(node, refHandler)) {
357 if (XMLListReference.isFirstListItem(node, refHandler)) {
358 final String value = XMLListReference.listValue(node, refHandler, listDelimiterHandler);
359 updateElement(node, refHandler, value);
360 }
361 } else {
362 final Object value = listDelimiterHandler.escape(refHandler.getValue(node), ListDelimiterHandler.NOOP_TRANSFORMER);
363 updateElement(node, refHandler, value);
364 }
365 }
366
367
368
369
370
371
372
373 private void updateElement(final Element element, final Object value) {
374 Text txtNode = findTextNodeForUpdate(element);
375 if (value == null) {
376
377 if (txtNode != null) {
378 element.removeChild(txtNode);
379 }
380 } else {
381 final String newValue = String.valueOf(value);
382 if (txtNode == null) {
383 txtNode = document.createTextNode(newValue);
384 if (element.getFirstChild() != null) {
385 element.insertBefore(txtNode, element.getFirstChild());
386 } else {
387 element.appendChild(txtNode);
388 }
389 } else {
390 txtNode.setNodeValue(newValue);
391 }
392 }
393 }
394
395 private void updateElement(final ImmutableNode node, final ReferenceNodeHandler refHandler, final Object value) {
396 final Element element = getElement(node, refHandler);
397 updateElement(element, value);
398 updateAttributes(node, element);
399 }
400 }
401
402
403 static final int DEFAULT_INDENT_SIZE = 2;
404
405
406 static final String INDENT_AMOUNT_PROPERTY = "{http://xml.apache.org/xslt}indent-amount";
407
408
409 private static final String DEFAULT_ROOT_NAME = "configuration";
410
411
412 private static final String ATTR_SPACE = "xml:space";
413
414
415 private static final String ATTR_SPACE_INTERNAL = "config-xml:space";
416
417
418 private static final String VALUE_PRESERVE = "preserve";
419
420
421 private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
422
423
424 private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
425
426
427
428
429
430
431
432
433 private static int countChildElements(final Node parent, final String name) {
434 final NodeList childNodes = parent.getChildNodes();
435 int count = 0;
436 for (int i = 0; i < childNodes.getLength(); i++) {
437 final Node item = childNodes.item(i);
438 if (item instanceof Element && name.equals(((Element) item).getTagName())) {
439 count++;
440 }
441 }
442 return count;
443 }
444
445
446
447
448
449
450
451
452
453
454
455 private static String determineValue(final String content, final boolean hasChildren, final boolean trimFlag) {
456 final boolean shouldTrim = trimFlag || StringUtils.isBlank(content) && hasChildren;
457 return shouldTrim ? content.trim() : content;
458 }
459
460
461
462
463
464
465
466 private static boolean isSingleElementList(final Element element) {
467 final Node parentNode = element.getParentNode();
468 return countChildElements(parentNode, element.getTagName()) == 1;
469 }
470
471
472
473
474
475
476
477 private static Map<String, String> processAttributes(final Element element) {
478 final NamedNodeMap attributes = element.getAttributes();
479 final Map<String, String> attrmap = new HashMap<>();
480
481 for (int i = 0; i < attributes.getLength(); ++i) {
482 final Node w3cNode = attributes.item(i);
483 if (w3cNode instanceof Attr) {
484 final Attr attr = (Attr) w3cNode;
485 attrmap.put(attr.getName(), attr.getValue());
486 }
487 }
488
489 return attrmap;
490 }
491
492
493
494
495
496
497
498
499
500
501
502 private static boolean shouldTrim(final Element element, final boolean currentTrim) {
503 final Attr attr = element.getAttributeNode(ATTR_SPACE);
504
505 if (attr == null) {
506 return currentTrim;
507 }
508 return !VALUE_PRESERVE.equals(attr.getValue());
509 }
510
511
512 private String rootElementName;
513
514
515 private String publicID;
516
517
518 private String systemID;
519
520
521 private DocumentBuilder documentBuilder;
522
523
524 private boolean validating;
525
526
527 private boolean schemaValidation;
528
529
530 private EntityResolver entityResolver = new DefaultEntityResolver();
531
532
533 private FileLocator locator;
534
535
536
537
538 public XMLConfiguration() {
539 initLogger(new ConfigurationLogger(XMLConfiguration.class));
540 }
541
542
543
544
545
546
547
548
549
550 public XMLConfiguration(final HierarchicalConfiguration<ImmutableNode> c) {
551 super(c);
552 rootElementName = c != null ? c.getRootElementName() : null;
553 initLogger(new ConfigurationLogger(XMLConfiguration.class));
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569 private Map<String, String> constructHierarchy(final ImmutableNode.Builder node, final MutableObject<String> refValue, final Element element,
570 final Map<ImmutableNode, Object> elemRefs, final boolean trim, final int level) {
571 final boolean trimFlag = shouldTrim(element, trim);
572 final Map<String, String> attributes = processAttributes(element);
573 attributes.put(ATTR_SPACE_INTERNAL, String.valueOf(trimFlag));
574 final StringBuilder buffer = new StringBuilder();
575 final NodeList list = element.getChildNodes();
576 boolean hasChildren = false;
577
578 for (int i = 0; i < list.getLength(); i++) {
579 final Node w3cNode = list.item(i);
580 if (w3cNode instanceof Element) {
581 final Element child = (Element) w3cNode;
582 final ImmutableNode.Builder childNode = new ImmutableNode.Builder();
583 childNode.name(child.getTagName());
584 final MutableObject<String> refChildValue = new MutableObject<>();
585 final Map<String, String> attrmap = constructHierarchy(childNode, refChildValue, child, elemRefs, trimFlag, level + 1);
586 final boolean childTrim = Boolean.parseBoolean(attrmap.remove(ATTR_SPACE_INTERNAL));
587 childNode.addAttributes(attrmap);
588 final ImmutableNode newChild = createChildNodeWithValue(node, childNode, child, refChildValue.getValue(), childTrim, attrmap, elemRefs);
589 if (elemRefs != null && !elemRefs.containsKey(newChild)) {
590 elemRefs.put(newChild, child);
591 }
592 hasChildren = true;
593 } else if (w3cNode instanceof Text) {
594 final Text data = (Text) w3cNode;
595 buffer.append(data.getData());
596 }
597 }
598
599 boolean childrenFlag = false;
600 if (hasChildren || trimFlag) {
601 childrenFlag = hasChildren || attributes.size() > 1;
602 }
603 final String text = determineValue(buffer.toString(), childrenFlag, trimFlag);
604 if (!text.isEmpty() || !childrenFlag && level != 0) {
605 refValue.setValue(text);
606 }
607 return attributes;
608 }
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 private ImmutableNode createChildNodeWithValue(final ImmutableNode.Builder parent, final ImmutableNode.Builder child, final Element elem,
626 final String value, final boolean trim, final Map<String, String> attrmap, final Map<ImmutableNode, Object> elemRefs) {
627 final ImmutableNode addedChildNode;
628 final Collection<String> values;
629
630 if (value != null) {
631 values = getListDelimiterHandler().split(value, trim);
632 } else {
633 values = Collections.emptyList();
634 }
635
636 if (values.size() > 1) {
637 final Map<ImmutableNode, Object> refs = isSingleElementList(elem) ? elemRefs : null;
638 final Iterator<String> it = values.iterator();
639
640 child.value(it.next());
641 addedChildNode = child.create();
642 parent.addChild(addedChildNode);
643 XMLListReference.assignListReference(refs, addedChildNode, elem);
644
645
646 while (it.hasNext()) {
647 final ImmutableNode.Builder c = new ImmutableNode.Builder();
648 c.name(addedChildNode.getNodeName());
649 c.value(it.next());
650 c.addAttributes(attrmap);
651 final ImmutableNode newChild = c.create();
652 parent.addChild(newChild);
653 XMLListReference.assignListReference(refs, newChild, null);
654 }
655 } else {
656 if (values.size() == 1) {
657
658
659 child.value(values.iterator().next());
660 }
661 addedChildNode = child.create();
662 parent.addChild(addedChildNode);
663 }
664
665 return addedChildNode;
666 }
667
668
669
670
671
672
673
674 private Document createDocument() throws ConfigurationException {
675 final ReferenceNodeHandler handler = getReferenceHandler();
676 final XMLDocumentHelper docHelper = (XMLDocumentHelper) handler.getReference(handler.getRootNode());
677 final XMLDocumentHelper newHelper = docHelper == null ? XMLDocumentHelper.forNewDocument(getRootElementName()) : docHelper.createCopy();
678
679 final XMLBuilderVisitor builder = new XMLBuilderVisitor(newHelper, getListDelimiterHandler());
680 builder.handleRemovedNodes(handler);
681 builder.processDocument(handler);
682 initRootElementText(newHelper.getDocument(), getModel().getNodeHandler().getRootNode().getValue());
683 return newHelper.getDocument();
684 }
685
686
687
688
689
690
691
692
693
694
695
696 protected DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
697 if (getDocumentBuilder() != null) {
698 return getDocumentBuilder();
699 }
700 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
701 if (isValidating()) {
702 factory.setValidating(true);
703 if (isSchemaValidation()) {
704 factory.setNamespaceAware(true);
705 factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
706 }
707 }
708
709 final DocumentBuilder result = factory.newDocumentBuilder();
710 result.setEntityResolver(this.entityResolver);
711
712 if (isValidating()) {
713
714 result.setErrorHandler(new DefaultHandler() {
715 @Override
716 public void error(final SAXParseException ex) throws SAXException {
717 throw ex;
718 }
719 });
720 }
721 return result;
722 }
723
724
725
726
727
728
729
730
731
732
733 protected Transformer createTransformer() throws ConfigurationException {
734 final Transformer transformer = XMLDocumentHelper.createTransformer();
735
736 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
737 transformer.setOutputProperty(INDENT_AMOUNT_PROPERTY, Integer.toString(DEFAULT_INDENT_SIZE));
738 if (locator != null && locator.getEncoding() != null) {
739 transformer.setOutputProperty(OutputKeys.ENCODING, locator.getEncoding());
740 }
741 if (publicID != null) {
742 transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicID);
743 }
744 if (systemID != null) {
745 transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemID);
746 }
747
748 return transformer;
749 }
750
751
752
753
754
755
756
757 public Document getDocument() {
758 final XMLDocumentHelper docHelper = getDocumentHelper();
759 return docHelper != null ? docHelper.getDocument() : null;
760 }
761
762
763
764
765
766
767
768
769 public DocumentBuilder getDocumentBuilder() {
770 return documentBuilder;
771 }
772
773
774
775
776
777
778 private XMLDocumentHelper getDocumentHelper() {
779 final ReferenceNodeHandler handler = getReferenceHandler();
780 return (XMLDocumentHelper) handler.getReference(handler.getRootNode());
781 }
782
783
784
785
786
787
788
789 public EntityResolver getEntityResolver() {
790 return this.entityResolver;
791 }
792
793
794
795
796
797
798
799
800 public String getPublicID() {
801 return syncReadValue(publicID, false);
802 }
803
804
805
806
807
808
809 private ReferenceNodeHandler getReferenceHandler() {
810 return getSubConfigurationParentModel().getReferenceNodeHandler();
811 }
812
813
814
815
816
817
818
819
820 @Override
821 protected String getRootElementNameInternal() {
822 final Document doc = getDocument();
823 if (doc == null) {
824 return rootElementName == null ? DEFAULT_ROOT_NAME : rootElementName;
825 }
826 return doc.getDocumentElement().getNodeName();
827 }
828
829
830
831
832
833
834
835
836 public String getSystemID() {
837 return syncReadValue(systemID, false);
838 }
839
840
841
842
843 @Override
844 public void initFileLocator(final FileLocator loc) {
845 locator = loc;
846 }
847
848
849
850
851
852
853
854 private void initProperties(final XMLDocumentHelper docHelper, final boolean elemRefs) {
855 final Document document = docHelper.getDocument();
856 setPublicID(docHelper.getSourcePublicID());
857 setSystemID(docHelper.getSourceSystemID());
858
859 final ImmutableNode.Builder rootBuilder = new ImmutableNode.Builder();
860 final MutableObject<String> rootValue = new MutableObject<>();
861 final Map<ImmutableNode, Object> elemRefMap = elemRefs ? new HashMap<>() : null;
862 final Map<String, String> attributes = constructHierarchy(rootBuilder, rootValue, document.getDocumentElement(), elemRefMap, true, 0);
863 attributes.remove(ATTR_SPACE_INTERNAL);
864 final ImmutableNode top = rootBuilder.value(rootValue.getValue()).addAttributes(attributes).create();
865 getSubConfigurationParentModel().mergeRoot(top, document.getDocumentElement().getTagName(), elemRefMap, elemRefs ? docHelper : null, this);
866 }
867
868
869
870
871
872
873
874 private void initRootElementText(final Document doc, final Object value) {
875 final Element elem = doc.getDocumentElement();
876 final NodeList children = elem.getChildNodes();
877
878
879 for (int i = 0; i < children.getLength(); i++) {
880 final Node nd = children.item(i);
881 if (nd.getNodeType() == Node.TEXT_NODE) {
882 elem.removeChild(nd);
883 }
884 }
885
886 if (value != null) {
887
888 elem.appendChild(doc.createTextNode(String.valueOf(value)));
889 }
890 }
891
892
893
894
895
896
897
898 public boolean isSchemaValidation() {
899 return schemaValidation;
900 }
901
902
903
904
905
906
907
908 public boolean isValidating() {
909 return validating;
910 }
911
912
913
914
915
916
917
918 private void load(final InputSource source) throws ConfigurationException {
919 if (locator == null) {
920 throw new ConfigurationException(
921 "Load operation not properly " + "initialized! Do not call read(InputStream) directly," + " but use a FileHandler to load a configuration.");
922 }
923
924 try {
925 final URL sourceURL = locator.getSourceURL();
926 if (sourceURL != null) {
927 source.setSystemId(sourceURL.toString());
928 }
929
930 final DocumentBuilder builder = createDocumentBuilder();
931 final Document newDocument = builder.parse(source);
932 final Document oldDocument = getDocument();
933 initProperties(XMLDocumentHelper.forSourceDocument(newDocument), oldDocument == null);
934 } catch (final SAXParseException spe) {
935 throw new ConfigurationException("Error parsing " + source.getSystemId(), spe);
936 } catch (final Exception e) {
937 getLogger().debug("Unable to load the configuration: " + e);
938 throw new ConfigurationException("Unable to load the configuration", e);
939 }
940 }
941
942
943
944
945
946
947
948
949
950
951 @Override
952 public void read(final InputStream in) throws ConfigurationException, IOException {
953 load(new InputSource(in));
954 }
955
956
957
958
959
960
961
962
963
964 @Override
965 public void read(final Reader in) throws ConfigurationException, IOException {
966 load(new InputSource(in));
967 }
968
969
970
971
972
973
974
975
976
977 public void setDocumentBuilder(final DocumentBuilder documentBuilder) {
978 this.documentBuilder = documentBuilder;
979 }
980
981
982
983
984
985
986
987 public void setEntityResolver(final EntityResolver resolver) {
988 this.entityResolver = resolver;
989 }
990
991
992
993
994
995
996
997
998 public void setPublicID(final String publicID) {
999 syncWrite(() -> this.publicID = publicID, false);
1000 }
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011 public void setRootElementName(final String name) {
1012 beginRead(true);
1013 try {
1014 if (getDocument() != null) {
1015 throw new UnsupportedOperationException("The name of the root element " + "cannot be changed when loaded from an XML document!");
1016 }
1017 rootElementName = name;
1018 } finally {
1019 endRead();
1020 }
1021 }
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031 public void setSchemaValidation(final boolean schemaValidation) {
1032 this.schemaValidation = schemaValidation;
1033 if (schemaValidation) {
1034 this.validating = true;
1035 }
1036 }
1037
1038
1039
1040
1041
1042
1043
1044
1045 public void setSystemID(final String systemID) {
1046 syncWrite(() -> this.systemID = systemID, false);
1047 }
1048
1049
1050
1051
1052
1053
1054
1055
1056 public void setValidating(final boolean validating) {
1057 if (!schemaValidation) {
1058 this.validating = validating;
1059 }
1060 }
1061
1062
1063
1064
1065
1066
1067 public void validate() throws ConfigurationException {
1068 syncWrite(() -> {
1069 try {
1070 final StringWriter writer = new StringWriter();
1071 final Result result = new StreamResult(writer);
1072 XMLDocumentHelper.transform(createTransformer(), new DOMSource(createDocument()), result);
1073 final Reader reader = new StringReader(writer.getBuffer().toString());
1074 createDocumentBuilder().parse(new InputSource(reader));
1075 } catch (final SAXException | IOException | ParserConfigurationException pce) {
1076 throw new ConfigurationException("Validation failed", pce);
1077 }
1078 }, false);
1079 }
1080
1081
1082
1083
1084
1085
1086
1087
1088 @Override
1089 public void write(final Writer writer) throws ConfigurationException, IOException {
1090 write(writer, createTransformer());
1091 }
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101 public void write(final Writer writer, final Transformer transformer) throws ConfigurationException {
1102 final Source source = new DOMSource(createDocument());
1103 final Result result = new StreamResult(writer);
1104 XMLDocumentHelper.transform(transformer, source, result);
1105 }
1106 }