1 package org.simantics.scl.data.xml;
4 import java.io.IOException;
5 import java.io.StringReader;
6 import java.io.StringWriter;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.LinkedHashMap;
11 import java.util.List;
14 import org.jdom2.Document;
15 import org.jdom2.Element;
16 import org.jdom2.IllegalAddException;
17 import org.jdom2.JDOMException;
18 import org.jdom2.Namespace;
19 import org.jdom2.filter.Filters;
20 import org.jdom2.input.SAXBuilder;
21 import org.jdom2.input.sax.XMLReaderJDOMFactory;
22 import org.jdom2.input.sax.XMLReaderXSDFactory;
23 import org.jdom2.output.Format;
24 import org.jdom2.output.XMLOutputter;
25 import org.jdom2.xpath.XPathExpression;
26 import org.jdom2.xpath.XPathFactory;
27 import org.simantics.scl.runtime.function.Function;
28 import org.simantics.scl.runtime.function.FunctionImpl1;
29 import org.simantics.scl.runtime.reporting.SCLReporting;
31 public class JDomHelper {
32 private static final SAXBuilder BUILDER = new SAXBuilder();
33 private static final XMLOutputter OUTPUTTER = new XMLOutputter(Format.getPrettyFormat());
34 private static final XPathFactory XPATH_FACTORY = XPathFactory.instance();
36 private static final int XPATH_CACHE_MAX = 50;
38 private static final Map<String,XPathExpression<Element>> XPATH_CACHE = Collections.synchronizedMap(
39 new LinkedHashMap<String,XPathExpression<Element>>(XPATH_CACHE_MAX) {
40 private static final long serialVersionUID = 2546245625L;
43 protected boolean removeEldestEntry(Map.Entry<String,XPathExpression<Element>> eldest) {
44 return size() > XPATH_CACHE_MAX;
48 public static Document parseString(String xmlDocument) throws JDOMException, IOException {
49 return BUILDER.build(new StringReader(xmlDocument));
52 public static Document parseFile(String xmlFileName) throws JDOMException, IOException {
53 return BUILDER.build(new File(xmlFileName));
56 public static String outputString(Document document) throws IOException {
57 StringWriter writer = new StringWriter();
58 OUTPUTTER.output(document, writer);
59 return writer.toString();
62 private static XPathExpression<Element> getXPathExpression(String xPathText) {
63 XPathExpression<Element> expression = XPATH_CACHE.get(xPathText);
64 if(expression == null) {
65 expression = XPATH_FACTORY.compile(xPathText, Filters.element());
66 XPATH_CACHE.put(xPathText, expression);
71 public static List<Element> elementsByXPath(Element element, String xPathText) {
72 XPathExpression<Element> expr = getXPathExpression(xPathText);
73 return expr.evaluate(element);
76 public static void addNamedChild(Element parent, String name, Element child) {
79 parent.addContent(child);
80 } catch(IllegalAddException e) {
81 SCLReporting.printError("Failed to set the parent of an element " + name + ":");
82 SCLReporting.printError(" " + e.getMessage());
86 public static void setNamespace(Document document, String namespace) {
87 setElementNamespace(document.getRootElement(), namespace);
90 public static void setElementNamespace(Element element, String namespace) {
91 Namespace ns = Namespace.getNamespace(namespace);
92 setNamespaceRecursively(element, ns);
95 private static void setNamespaceRecursively(Element element, Namespace ns) {
96 element.setNamespace(ns);
97 for(Element child : element.getChildren())
98 if(child.getNamespace() == Namespace.NO_NAMESPACE)
99 setNamespaceRecursively(child, ns);
102 public static void clearNamespace(Document document) {
103 clearElementNamespace(document.getRootElement());
106 public static void clearElementNamespace(Element element) {
107 element.setNamespace(null);
108 for (Element child : element.getChildren())
109 clearElementNamespace(child);
112 public static Function parseStringWithSchemaFile(String xsdFile) throws JDOMException {
113 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(new File(xsdFile));
114 SAXBuilder builder = new SAXBuilder(factory);
115 return parseStringWithBuilder(builder);
118 public static Function parseStringWithSchemaURL(URL xsd) throws JDOMException {
119 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(xsd);
120 SAXBuilder builder = new SAXBuilder(factory);
121 return parseStringWithBuilder(builder);
124 public static Function parseFileWithSchemaFile(String xsdFile) throws JDOMException {
125 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(new File(xsdFile));
126 SAXBuilder builder = new SAXBuilder(factory);
127 return parseFileWithBuilder(builder);
130 public static Function parseFileWithSchemaURL(URL xsd) throws JDOMException {
131 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(xsd);
132 SAXBuilder builder = new SAXBuilder(factory);
133 return parseFileWithBuilder(builder);
136 private static Function parseStringWithBuilder(final SAXBuilder builder) {
137 return new FunctionImpl1<String, Document>() {
139 public Document apply(String xml) {
141 return builder.build(new StringReader(xml));
143 catch (JDOMException | IOException e) {
144 throw new RuntimeException(e);
150 private static Function parseFileWithBuilder(final SAXBuilder builder) {
151 return new FunctionImpl1<String, Document>() {
153 public Document apply(String xml) {
155 return builder.build(new File(xml));
157 catch (JDOMException | IOException e) {
158 throw new RuntimeException(e);
164 public static void sortChildrenWith(final Function comparator, Element element) {
165 element.sortChildren(new Comparator() {
167 public int compare(Object o1, Object o2) {
168 return (Integer)comparator.apply(o1, o2);