package org.simantics.scl.data.xml; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import org.jdom2.CDATA; import org.jdom2.Content; import org.jdom2.Content.CType; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.IllegalAddException; import org.jdom2.JDOMException; import org.jdom2.Namespace; import org.jdom2.filter.Filters; import org.jdom2.input.SAXBuilder; import org.jdom2.input.sax.XMLReaderJDOMFactory; import org.jdom2.input.sax.XMLReaderXSDFactory; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.jdom2.xpath.XPathExpression; import org.jdom2.xpath.XPathFactory; import org.simantics.scl.runtime.function.Function; import org.simantics.scl.runtime.function.FunctionImpl1; import org.simantics.scl.runtime.reporting.SCLReporting; public class JDomHelper { private static final SAXBuilder BUILDER = new SAXBuilder(); private static final XMLOutputter OUTPUTTER = new XMLOutputter(Format.getPrettyFormat()); private static final XPathFactory XPATH_FACTORY = XPathFactory.instance(); private static final int XPATH_CACHE_MAX = 50; private static final Map> XPATH_CACHE = Collections.synchronizedMap( new LinkedHashMap>(XPATH_CACHE_MAX) { private static final long serialVersionUID = 2546245625L; @Override protected boolean removeEldestEntry(Map.Entry> eldest) { return size() > XPATH_CACHE_MAX; } }); public static Document parseString(String xmlDocument) throws JDOMException, IOException { return BUILDER.build(new StringReader(xmlDocument)); } public static Document parseFile(String xmlFileName) throws JDOMException, IOException { return BUILDER.build(new File(xmlFileName)); } public static String outputString(Document document) throws IOException { StringWriter writer = new StringWriter(); OUTPUTTER.output(document, writer); return writer.toString(); } private static XPathExpression getXPathExpression(String xPathText) { XPathExpression expression = XPATH_CACHE.get(xPathText); if(expression == null) { expression = XPATH_FACTORY.compile(xPathText, Filters.element()); XPATH_CACHE.put(xPathText, expression); } return expression; } public static List elementsByXPath(Element element, String xPathText) { XPathExpression expr = getXPathExpression(xPathText); return expr.evaluate(element); } public static void addNamedChild(Element parent, String name, Element child) { child.setName(name); try { parent.addContent(child); } catch(IllegalAddException e) { SCLReporting.printError("Failed to set the parent of an element " + name + ":"); SCLReporting.printError(" " + e.getMessage()); } } public static void setNamespace(Document document, String namespace) { setElementNamespace(document.getRootElement(), namespace); } public static void setElementNamespace(Element element, String namespace) { Namespace ns = Namespace.getNamespace(namespace); setNamespaceRecursively(element, ns); } private static void setNamespaceRecursively(Element element, Namespace ns) { element.setNamespace(ns); for(Element child : element.getChildren()) if(child.getNamespace() == Namespace.NO_NAMESPACE) setNamespaceRecursively(child, ns); } public static void clearNamespace(Document document) { clearElementNamespace(document.getRootElement()); } public static void clearElementNamespace(Element element) { element.setNamespace(null); for (Element child : element.getChildren()) clearElementNamespace(child); } public static Function parseStringWithSchemaFile(String xsdFile) throws JDOMException { XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(new File(xsdFile)); SAXBuilder builder = new SAXBuilder(factory); return parseStringWithBuilder(builder); } public static Function parseStringWithSchemaURL(URL xsd) throws JDOMException { XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(xsd); SAXBuilder builder = new SAXBuilder(factory); return parseStringWithBuilder(builder); } public static Function parseFileWithSchemaFile(String xsdFile) throws JDOMException { XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(new File(xsdFile)); SAXBuilder builder = new SAXBuilder(factory); return parseFileWithBuilder(builder); } public static Function parseFileWithSchemaURL(URL xsd) throws JDOMException { XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(xsd); SAXBuilder builder = new SAXBuilder(factory); return parseFileWithBuilder(builder); } private static Function parseStringWithBuilder(final SAXBuilder builder) { return new FunctionImpl1() { @Override public Document apply(String xml) { try { return builder.build(new StringReader(xml)); } catch (JDOMException | IOException e) { throw new RuntimeException(e); } }; }; } private static Function parseFileWithBuilder(final SAXBuilder builder) { return new FunctionImpl1() { @Override public Document apply(String xml) { try { return builder.build(new File(xml)); } catch (JDOMException | IOException e) { throw new RuntimeException(e); } }; }; } public static void sortChildrenWith(final Function comparator, Element element) { element.sortChildren(new Comparator() { @Override public int compare(Object o1, Object o2) { return (Integer)comparator.apply(o1, o2); } }); } public static void addCDATA(Element element, String cdata) { element.addContent(new CDATA(cdata)); } public static List getCDATAs(Element element) { ArrayList result = new ArrayList<>(); for(Content c : element.getContent()) { if(CType.CDATA.equals(c.getCType())) result.add(c.getValue()); } return result; } }