21 package org.matsim.core.utils.io;
23 import com.ctc.wstx.sax.WstxSAXParserFactory;
24 import org.apache.logging.log4j.LogManager;
25 import org.apache.logging.log4j.Logger;
30 import org.xml.sax.helpers.DefaultHandler;
32 import javax.xml.parsers.ParserConfigurationException;
33 import javax.xml.parsers.SAXParser;
34 import javax.xml.parsers.SAXParserFactory;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.UncheckedIOException;
40 import java.net.URLConnection;
41 import java.util.Stack;
61 private final Stack<StringBuffer>
buffers =
new Stack<>();
98 public abstract void startTag(String name, Attributes atts, Stack<String> context);
108 public abstract void endTag(String name, String content, Stack<String> context);
118 this.isValidating = validateXml;
129 this.isNamespaceAware = awareness;
139 this.localDtdBase = localDtdDirectory;
152 public final void readFile(
final String filename)
throws UncheckedIOException {
153 log.info(
"starting to parse xml from file " + filename +
" ...");
154 this.theSource = filename;
159 public final void readURL(
final URL url )
throws UncheckedIOException {
163 public final void readStream(InputStream stream)
throws UncheckedIOException {
167 public final void parse(
final URL url)
throws UncheckedIOException {
169 this.theSource = url.toString();
170 log.info(
"starting to parse xml from url " + this.theSource +
" ...");
175 public final void parse(
final InputStream stream)
throws UncheckedIOException {
176 this.theSource =
"stream";
177 parse(
new InputSource(stream));
180 public final void parse(
final InputSource input)
throws UncheckedIOException {
188 WstxSAXParserFactory factory =
new WstxSAXParserFactory();
189 factory.setValidating(validating);
190 factory.setNamespaceAware(this.isNamespaceAware);
191 factory.setFeature(
"http://xml.org/sax/features/external-general-entities",
false);
194 factory.setFeature(
"http://xml.org/sax/features/validation",
true);
195 SAXParser parser = factory.newSAXParser();
196 XMLReader reader = parser.getXMLReader();
197 reader.setContentHandler(
this);
198 reader.setErrorHandler(
this);
199 reader.setEntityResolver(
this);
202 SAXParser parser = factory.newSAXParser();
203 parser.parse(input,
this);
209 SAXParserFactory factory = SAXParserFactory.newInstance();
210 factory.setValidating(validating);
211 factory.setNamespaceAware(this.isNamespaceAware);
212 factory.setFeature(
"http://xml.org/sax/features/external-general-entities",
false);
216 factory.setFeature(
"http://apache.org/xml/features/validation/schema",
true);
217 SAXParser parser = factory.newSAXParser();
218 XMLReader reader = parser.getXMLReader();
219 reader.setContentHandler(
this);
220 reader.setErrorHandler(
this);
221 reader.setEntityResolver(
this);
224 SAXParser parser = factory.newSAXParser();
225 parser.parse(input,
this);
228 }
catch (IOException e) {
229 throw new UncheckedIOException(e);
230 }
catch (SAXException | ParserConfigurationException e) {
231 throw new UncheckedIOException(
new IOException(e));
248 public final InputSource
resolveEntity(
final String publicId,
final String systemId) {
252 int index = systemId.replace(
'\\',
'/').lastIndexOf(
'/');
253 String shortSystemId = systemId.substring(index + 1);
255 if (this.doctype == null) {
262 if (this.preferLocalDtds) {
264 if (source == null) {
267 if (source == null) {
270 if (source == null) {
275 if (source == null) {
278 if (source == null) {
281 if (source == null) {
286 if (source == null) {
288 log.warn(
"Could neither get the DTD from the web nor a local one. " + systemId);
290 source.setSystemId(systemId);
296 log.info(
"Trying to load " + fullSystemId +
". In some cases (e.g. network interface up but no connection), this may take a bit.");
298 URL url =
new URL(fullSystemId);
299 URLConnection urlConn = url.openConnection();
300 urlConn.setConnectTimeout(5000);
301 urlConn.setReadTimeout(5000);
302 urlConn.setAllowUserInteraction(
false);
304 InputStream is = urlConn.getInputStream();
308 return new InputSource(is);
309 }
catch (IOException e) {
311 log.info(e.toString() +
". May not be fatal, will try to load it locally.");
317 if (this.localDtdBase != null) {
318 String localFileName = this.localDtdBase +
"/" + shortSystemId;
319 File dtdFile =
new File(localFileName);
321 if (dtdFile.exists() && dtdFile.isFile() && dtdFile.canRead()) {
322 log.info(
"Using the local DTD " + localFileName +
" with absolute path " + dtdFile.getAbsolutePath() );
323 return new InputSource(dtdFile.getAbsolutePath());
331 InputStream stream = this.getClass().getResourceAsStream(
"/dtd/" + shortSystemId);
332 if (stream != null) {
333 log.info(
"Using local DTD from classpath:dtd/" + shortSystemId);
334 return new InputSource(stream);
340 log.info(
"Trying to access local dtd folder at standard location ./dtd...");
341 File dtdFile =
new File(
"./dtd/" + shortSystemId);
342 if (dtdFile.exists() && dtdFile.isFile() && dtdFile.canRead()) {
343 log.info(
"Using the local DTD " + dtdFile.getAbsolutePath());
344 return new InputSource(dtdFile.getAbsolutePath());
352 public void characters(
final char[]
ch,
final int start,
final int length)
throws SAXException {
355 StringBuffer buffer = this.buffers.peek();
356 if (buffer != null) {
357 buffer.append(
ch, start, length);
362 public final void startElement(
final String uri,
final String localName,
final String qName, Attributes atts) {
365 String tag = (uri.length() == 0) ? qName : localName;
366 this.buffers.push(
new StringBuffer());
367 this.
startTag(tag, atts, this.theContext);
368 this.theContext.push(tag);
372 public final void endElement(
final String uri,
final String localName,
final String qName)
throws SAXException {
375 String tag = (uri.length() == 0) ? qName : localName;
376 this.theContext.pop();
377 StringBuffer buffer = this.buffers.pop();
384 public final void error(
final SAXParseException ex)
throws SAXException {
385 if (this.theContext.isEmpty()) {
386 System.err.println(
"Missing DOCTYPE.");
388 System.err.println(
"XML-ERROR: " +
getInputSource(ex) +
", line " + ex.getLineNumber() +
", column " + ex.getColumnNumber() +
":");
389 System.err.println(ex.toString());
394 public final void fatalError(
final SAXParseException ex)
throws SAXException {
395 System.err.println(
"XML-FATAL: " +
getInputSource(ex) +
", line " + ex.getLineNumber() +
", column " + ex.getColumnNumber() +
":");
396 System.err.println(ex.toString());
401 public final void warning(
final SAXParseException ex)
throws SAXException {
402 System.err.println(
"XML-WARNING: " +
getInputSource(ex) +
", line " + ex.getLineNumber() +
", column " + ex.getColumnNumber() +
":");
403 System.err.println(ex.getMessage());
407 System.out.println(ex.getPublicId());
408 System.out.println(ex.getSystemId());
409 if (ex.getCause() != null) {
410 System.out.println(ex.getCause().getMessage());
412 System.out.println(ex.getLocalizedMessage());
413 System.out.println(ex.getMessage());
414 if (ex.getSystemId() != null) {
415 return ex.getSystemId();
417 else if (ex.getPublicId() != null) {
418 return ex.getPublicId();
426 public static double parseDouble(String value)
throws NumberFormatException {
427 if (
"INF".equals(value)) {
428 return Double.POSITIVE_INFINITY;
430 if (
"-INF".equals(value)) {
431 return Double.NEGATIVE_INFINITY;
433 if (
"NaN".equals(value)) {
436 return Double.parseDouble(value);
void characters(final char[] ch, final int start, final int length)
static InputSource findDtdInDefaultLocation(final String shortSystemId)
final Stack< StringBuffer > buffers
final void setValidating(final boolean validateXml)
String getInputSource(final SAXParseException ex)
static InputSource findDtdInRemoteLocation(final String fullSystemId)
final Stack< String > theContext
InputSource findDtdInLocalFilesystem(final String shortSystemId)
abstract void startTag(String name, Attributes atts, Stack< String > context)
final void parse(final InputSource input)
final void setLocalDtdDirectory(final String localDtdDirectory)
static BufferedReader getBufferedReader(URL url, Charset charset)
final void setNamespaceAware(final boolean awareness)
final void error(final SAXParseException ex)
final ValidationType validationType
final InputSource resolveEntity(final String publicId, final String systemId)
final void parse(final InputStream stream)
static boolean preferLocalDTDs()
final void readURL(final URL url)
final void parse(final URL url)
final String getDoctype()
InputSource findDtdInClasspath(final String shortSystemId)
final void warning(final SAXParseException ex)
final void startElement(final String uri, final String localName, final String qName, Attributes atts)
static void assertNotNull(Object obj)
final void readStream(InputStream stream)
abstract void endTag(String name, String content, Stack< String > context)
final void readFile(final String filename)
MatsimXmlParser(ValidationType validationType)
final void endElement(final String uri, final String localName, final String qName)
final boolean preferLocalDtds
void setDoctype(final String doctype)
static double parseDouble(String value)
final void fatalError(final SAXParseException ex)