source: josm/trunk/src/org/openstreetmap/josm/tools/XmlUtils.java@ 15755

Last change on this file since 15755 was 15755, checked in by simon04, 4 years ago

Introduce Stopwatch class to measure elapsed time

  • Property svn:eol-style set to native
File size: 7.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.io.IOException;
5import java.io.InputStream;
6
7import javax.xml.XMLConstants;
8import javax.xml.parsers.DocumentBuilder;
9import javax.xml.parsers.DocumentBuilderFactory;
10import javax.xml.parsers.ParserConfigurationException;
11import javax.xml.parsers.SAXParser;
12import javax.xml.parsers.SAXParserFactory;
13import javax.xml.stream.XMLInputFactory;
14import javax.xml.transform.TransformerConfigurationException;
15import javax.xml.transform.TransformerFactory;
16import javax.xml.validation.Schema;
17import javax.xml.validation.SchemaFactory;
18import javax.xml.validation.SchemaFactoryConfigurationError;
19import javax.xml.validation.Validator;
20
21import org.w3c.dom.Document;
22import org.w3c.dom.Element;
23import org.w3c.dom.Node;
24import org.w3c.dom.NodeList;
25import org.xml.sax.InputSource;
26import org.xml.sax.SAXException;
27import org.xml.sax.SAXNotRecognizedException;
28import org.xml.sax.SAXNotSupportedException;
29import org.xml.sax.helpers.DefaultHandler;
30
31/**
32 * XML utils, mainly used to construct safe factories.
33 * @since 13901
34 */
35public final class XmlUtils {
36
37 private XmlUtils() {
38 // Hide default constructor for utils classes
39 }
40
41 /**
42 * Returns the W3C XML Schema factory implementation. Robust method dealing with ContextClassLoader problems.
43 * @return the W3C XML Schema factory implementation
44 */
45 public static SchemaFactory newXmlSchemaFactory() {
46 try {
47 return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
48 } catch (SchemaFactoryConfigurationError e) {
49 Logging.debug(e);
50 // Can happen with icedtea-web. Use workaround from https://issues.apache.org/jira/browse/GERONIMO-6185
51 Thread currentThread = Thread.currentThread();
52 ClassLoader old = currentThread.getContextClassLoader();
53 currentThread.setContextClassLoader(null);
54 try {
55 return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
56 } finally {
57 currentThread.setContextClassLoader(old);
58 }
59 }
60 }
61
62 /**
63 * Returns a new secure DOM builder, supporting XML namespaces.
64 * @return a new secure DOM builder, supporting XML namespaces
65 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
66 */
67 public static DocumentBuilder newSafeDOMBuilder() throws ParserConfigurationException {
68 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
69 builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
70 builderFactory.setNamespaceAware(true);
71 builderFactory.setValidating(false);
72 return builderFactory.newDocumentBuilder();
73 }
74
75 /**
76 * Parse the content given {@link InputStream} as XML.
77 * This method uses a secure DOM builder, supporting XML namespaces.
78 *
79 * @param is The InputStream containing the content to be parsed.
80 * @return the result DOM document
81 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
82 * @throws IOException if any IO errors occur.
83 * @throws SAXException for SAX errors.
84 */
85 public static Document parseSafeDOM(InputStream is) throws ParserConfigurationException, IOException, SAXException {
86 Stopwatch stopwatch = Stopwatch.createStarted();
87 Logging.debug("Starting DOM parsing of {0}", is);
88 Document result = newSafeDOMBuilder().parse(is);
89 Logging.debug("DOM parsing done in {0}", stopwatch);
90 return result;
91 }
92
93 /**
94 * Returns a new secure SAX parser, supporting XML namespaces.
95 * @return a new secure SAX parser, supporting XML namespaces
96 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
97 * @throws SAXException for SAX errors.
98 */
99 public static SAXParser newSafeSAXParser() throws ParserConfigurationException, SAXException {
100 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
101 parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
102 parserFactory.setNamespaceAware(true);
103 return parserFactory.newSAXParser();
104 }
105
106 /**
107 * Parse the content given {@link org.xml.sax.InputSource} as XML using the specified {@link org.xml.sax.helpers.DefaultHandler}.
108 * This method uses a secure SAX parser, supporting XML namespaces.
109 *
110 * @param is The InputSource containing the content to be parsed.
111 * @param dh The SAX DefaultHandler to use.
112 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
113 * @throws SAXException for SAX errors.
114 * @throws IOException if any IO errors occur.
115 */
116 public static void parseSafeSAX(InputSource is, DefaultHandler dh) throws ParserConfigurationException, SAXException, IOException {
117 Stopwatch stopwatch = Stopwatch.createStarted();
118 Logging.debug("Starting SAX parsing of {0} using {1}", is, dh);
119 newSafeSAXParser().parse(is, dh);
120 Logging.debug("SAX parsing done in {0}", stopwatch);
121 }
122
123 /**
124 * Returns a new secure {@link XMLInputFactory}.
125 * @return a new secure {@code XMLInputFactory}, for which external entities are not loaded
126 */
127 public static XMLInputFactory newSafeXMLInputFactory() {
128 XMLInputFactory factory = XMLInputFactory.newInstance();
129 // do not try to load external entities, nor validate the XML
130 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
131 factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
132 factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
133 return factory;
134 }
135
136 /**
137 * Returns a new secure {@link TransformerFactory}.
138 * @return a new secure {@link TransformerFactory}
139 * @throws TransformerConfigurationException if the factory or the Transformers or Templates it creates cannot support this feature.
140 */
141 public static TransformerFactory newSafeTransformerFactory() throws TransformerConfigurationException {
142 TransformerFactory factory = TransformerFactory.newInstance();
143 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
144 return factory;
145 }
146
147 /**
148 * Returns a new secure {@link Validator}.
149 * @param schema XML schema
150 * @return a new secure {@link Validator}
151 * @since 14441
152 */
153 public static Validator newSafeValidator(Schema schema) {
154 Validator validator = schema.newValidator();
155 try {
156 validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
157 validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
158 } catch (SAXNotRecognizedException | SAXNotSupportedException e) {
159 // All implementations that implement JAXP 1.5 or newer are required to support these two properties
160 Logging.trace(e);
161 }
162 return validator;
163 }
164
165 /**
166 * Get the first child element
167 * @param parent parent node
168 * @return the first child element
169 * @since 14348
170 */
171 public static Element getFirstChildElement(Node parent) {
172 NodeList children = parent.getChildNodes();
173 for (int i = 0; i < children.getLength(); i++) {
174 Node child = children.item(i);
175 if (child instanceof Element) {
176 return (Element) child;
177 }
178 }
179 return null;
180 }
181}
Note: See TracBrowser for help on using the repository browser.