1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.xmlfield.core.impl.dom;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.StringReader;
21 import java.io.StringWriter;
22 import java.io.Writer;
23 import java.util.HashMap;
24 import java.util.Map;
25
26 import javax.xml.parsers.DocumentBuilder;
27 import javax.xml.parsers.DocumentBuilderFactory;
28 import javax.xml.parsers.ParserConfigurationException;
29 import javax.xml.transform.OutputKeys;
30 import javax.xml.transform.Transformer;
31 import javax.xml.transform.TransformerConfigurationException;
32 import javax.xml.transform.TransformerException;
33 import javax.xml.transform.TransformerFactory;
34 import javax.xml.transform.TransformerFactoryConfigurationError;
35 import javax.xml.transform.dom.DOMSource;
36 import javax.xml.transform.stream.StreamResult;
37
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Node;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44 import org.xmlfield.core.api.XmlFieldNode;
45 import org.xmlfield.core.api.XmlFieldNodeParser;
46 import org.xmlfield.core.exception.XmlFieldParsingException;
47 import org.xmlfield.core.impl.dom.cleanup.EntitySanitizingInputStream;
48 import org.xmlfield.core.impl.dom.cleanup.InputSanitizer;
49
50
51
52
53
54
55
56
57
58
59
60 public class DomNodeParser implements XmlFieldNodeParser {
61
62
63
64
65
66
67
68
69
70
71 public static final String CONFIG_CLEANUP_XML = "xmlfield.dom.cleanupXmlFirst";
72
73
74
75
76
77
78
79 @Deprecated
80 public static String CONFIG_INDENT_XML = OutputKeys.INDENT;
81
82 private static final Logger logger = LoggerFactory
83 .getLogger(DomNodeParser.class);
84
85
86
87
88
89 boolean cleanupXmlFirst = false;
90 Map<String, String> configuration = null;
91 DocumentBuilder documentBuilder = null;
92 boolean indent = false;
93
94 Transformer t = null;
95
96 public DomNodeParser() throws TransformerConfigurationException,
97 TransformerFactoryConfigurationError {
98 this(null);
99 }
100
101
102
103
104
105
106
107
108
109
110 public DomNodeParser(Map<String, String> configurationParam)
111 throws TransformerConfigurationException,
112 TransformerFactoryConfigurationError {
113
114 if (configurationParam != null) {
115
116 this.configuration = new HashMap<String, String>(configurationParam);
117
118
119
120 if ("true".equals(configuration.get(OutputKeys.INDENT))) {
121 logger.warn("Use of deprecated value \"true\" for configuration OutputKeys.INDENT. "
122 + "Please use \"yes\" instead");
123 configuration.put(OutputKeys.INDENT, "yes");
124 }
125
126
127
128 if ("true".equals(configuration.get(CONFIG_CLEANUP_XML))) {
129 cleanupXmlFirst = true;
130 configuration.remove(CONFIG_CLEANUP_XML);
131 }
132
133 }
134 }
135
136 private void ensureBuilder() throws ParserConfigurationException {
137
138 if (documentBuilder == null) {
139 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
140 .newInstance();
141
142 documentBuilderFactory.setNamespaceAware(true);
143
144 documentBuilderFactory.setExpandEntityReferences(false);
145 documentBuilderFactory.setValidating(false);
146
147 documentBuilder = documentBuilderFactory.newDocumentBuilder();
148
149 }
150 }
151
152 private void ensureTransformer() throws TransformerConfigurationException,
153 TransformerFactoryConfigurationError {
154 if (t == null) {
155 t = TransformerFactory.newInstance().newTransformer();
156
157
158 t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
159
160
161 if (configuration != null) {
162 for (String key : configuration.keySet()) {
163 t.setOutputProperty(key, configuration.get(key));
164 }
165 }
166 }
167 }
168
169 @Override
170 public String nodeToXml(XmlFieldNode node) throws XmlFieldParsingException {
171 StringWriter sw;
172 try {
173
174 sw = new StringWriter();
175 ensureTransformer();
176 t.transform(new DOMSource((Node) node.getNode()), new StreamResult(
177 sw));
178 } catch (TransformerConfigurationException e) {
179 throw new XmlFieldParsingException(e);
180 } catch (IllegalArgumentException e) {
181 throw new XmlFieldParsingException(e);
182 } catch (TransformerFactoryConfigurationError e) {
183 throw new XmlFieldParsingException(e);
184 } catch (TransformerException e) {
185 throw new XmlFieldParsingException(e);
186 }
187
188 return sw.toString();
189 }
190
191 @Override
192 public void nodeToXml(XmlFieldNode node, Writer writer)
193 throws XmlFieldParsingException {
194 try {
195 ensureTransformer();
196
197 t.transform(new DOMSource((Node) node.getNode()), new StreamResult(
198 writer));
199 } catch (TransformerConfigurationException e) {
200 throw new XmlFieldParsingException(e);
201 } catch (IllegalArgumentException e) {
202 throw new XmlFieldParsingException(e);
203 } catch (TransformerFactoryConfigurationError e) {
204 throw new XmlFieldParsingException(e);
205 } catch (TransformerException e) {
206 throw new XmlFieldParsingException(e);
207 }
208
209 }
210
211
212
213
214
215
216
217
218 private Node xmlToNode(final InputSource xmlInputSource)
219 throws XmlFieldParsingException {
220
221 new InputSource() {
222
223 };
224 Document document = null;
225 try {
226 ensureBuilder();
227 document = documentBuilder.parse(xmlInputSource);
228 } catch (ParserConfigurationException e) {
229 throw new XmlFieldParsingException(e);
230 } catch (SAXException e) {
231 throw new XmlFieldParsingException(e);
232 } catch (IOException e) {
233 throw new XmlFieldParsingException(e);
234 }
235
236 return document.getDocumentElement();
237 }
238
239 @Override
240 public XmlFieldNode xmlToNode(InputStream xmlContent)
241 throws XmlFieldParsingException {
242
243 InputStream stream = xmlContent;
244 if (cleanupXmlFirst) {
245 stream = new EntitySanitizingInputStream(stream);
246 }
247
248 return new DomNode(xmlToNode(new InputSource(stream)));
249 }
250
251 @Override
252 public XmlFieldNode xmlToNode(String xml) throws XmlFieldParsingException {
253 String xmlData = xml;
254 if (cleanupXmlFirst) {
255 xmlData = InputSanitizer.sanitizeXml(xml);
256 }
257
258 return new DomNode(
259 xmlToNode(new InputSource(new StringReader(xmlData))));
260 }
261 }