package de.saring.sportstracker.storage; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.jdom2.input.sax.XMLReaders; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.time.format.DateTimeFormatter; /** * Helper class for common functions when reading and writing XML files. * * @author Stefan Saring * @version 1.0 */ public final class XMLUtils { /** The date and time parser and formatter instance. */ public static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ISO_LOCAL_DATE_TIME; private XMLUtils() { } /** * Parses the specified XML file and creates the JDOM document. The XML will * be verified against the specified XSD schema (will be read from classpath). * * @param xmlFile the XML file to parse * @param xsdFilename the name of the XSD (just the filename) * @return the created JDOM Document * @throws java.io.IOException * @throws org.jdom2.JDOMException */ public static Document getJDOMDocument(final File xmlFile, final String xsdFilename) throws IOException, JDOMException { // create a SAX parser with XSD validation SAXBuilder builder = new SAXBuilder(XMLReaders.DTDVALIDATING); builder.setFeature("http://apache.org/xml/features/validation/schema", true); builder.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", "file://" + xsdFilename); // define the EntityResolver for loading the XSD schema as a resource // from the classpath instead from filesystem builder.setEntityResolver(new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if (systemId.toLowerCase().endsWith(xsdFilename)) { return new InputSource(this.getClass().getResourceAsStream("/xml/" + xsdFilename)); } else { return null; } } }); // create JDOM Document return builder.build(xmlFile); } /** * Creates the element with the specified name and comment and adds it to the parent. * * @param eParent the parent element * @param name name of the new element * @param comment comment of the new element */ public static void addElement(Element eParent, String name, String comment) { Element element = new Element(name); element.setText(comment); eParent.addContent(element); } /** * Writes the specified JDOM element to the XML file specified by filename. * The file will use UTF-8 encoding and has 4-space indentation. * * @param eRoot root element of the XML document * @param filename filename of the XML file to create * @throws IOException */ public static void writeXMLFile(Element eRoot, String filename) throws IOException { Document document = new Document(eRoot); XMLOutputter outputter = new XMLOutputter(); Format format = Format.getPrettyFormat(); format.setLineSeparator(System.getProperty("line.separator")); format.setIndent(" "); outputter.setFormat(format); // FileWriter can't be used here, because default encoding on Win32 isn't UTF-8 try (OutputStreamWriter osWriter = new OutputStreamWriter(new FileOutputStream(filename), "UTF-8")) { outputter.output(document, osWriter); osWriter.flush(); } } }