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 }