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.ArrayList;
9 import java.util.Collections;
10 import java.util.Comparator;
11 import java.util.LinkedHashMap;
12 import java.util.List;
14 import java.util.concurrent.ArrayBlockingQueue;
16 import org.jdom2.CDATA;
17 import org.jdom2.Content;
18 import org.jdom2.Content.CType;
19 import org.jdom2.Document;
20 import org.jdom2.Element;
21 import org.jdom2.IllegalAddException;
22 import org.jdom2.JDOMException;
23 import org.jdom2.Namespace;
24 import org.jdom2.filter.Filters;
25 import org.jdom2.input.SAXBuilder;
26 import org.jdom2.input.sax.XMLReaderJDOMFactory;
27 import org.jdom2.input.sax.XMLReaderXSDFactory;
28 import org.jdom2.output.Format;
29 import org.jdom2.output.XMLOutputter;
30 import org.jdom2.xpath.XPathExpression;
31 import org.jdom2.xpath.XPathFactory;
32 import org.simantics.scl.runtime.function.Function;
33 import org.simantics.scl.runtime.function.FunctionImpl1;
34 import org.simantics.scl.runtime.reporting.SCLReporting;
36 public class JDomHelper {
37 private static final SAXBuilder BUILDER = new SAXBuilder();
38 private static final XMLOutputter OUTPUTTER = new XMLOutputter(Format.getPrettyFormat());
39 private static final XPathFactory XPATH_FACTORY = XPathFactory.instance();
41 private static final int XPATH_CACHE_MAX = 50;
43 private static final Map<String,XPathExpression<Element>> XPATH_CACHE = Collections.synchronizedMap(
44 new LinkedHashMap<String,XPathExpression<Element>>(XPATH_CACHE_MAX) {
45 private static final long serialVersionUID = 2546245625L;
48 protected boolean removeEldestEntry(Map.Entry<String,XPathExpression<Element>> eldest) {
49 return size() > XPATH_CACHE_MAX;
53 public static Document parseString(String xmlDocument) throws JDOMException, IOException {
54 return BUILDER.build(new StringReader(xmlDocument));
57 public static Document parseFile(String xmlFileName) throws JDOMException, IOException {
58 return BUILDER.build(new File(xmlFileName));
61 public static String outputString(Document document) throws IOException {
62 StringWriter writer = new StringWriter();
63 OUTPUTTER.output(document, writer);
64 return writer.toString();
67 private static XPathExpression<Element> getXPathExpression(String xPathText) {
68 XPathExpression<Element> expression = XPATH_CACHE.get(xPathText);
69 if(expression == null) {
70 expression = XPATH_FACTORY.compile(xPathText, Filters.element());
71 XPATH_CACHE.put(xPathText, expression);
76 public static List<Element> elementsByXPath(Element element, String xPathText) {
77 XPathExpression<Element> expr = getXPathExpression(xPathText);
78 return expr.evaluate(element);
81 public static void addNamedChild(Element parent, String name, Element child) {
84 parent.addContent(child);
85 } catch(IllegalAddException e) {
86 SCLReporting.printError("Failed to set the parent of an element " + name + ":");
87 SCLReporting.printError(" " + e.getMessage());
91 public static void setNamespace(Document document, String namespace) {
92 setElementNamespace(document.getRootElement(), namespace);
95 public static void setElementNamespace(Element element, String namespace) {
96 Namespace ns = Namespace.getNamespace(namespace);
97 setNamespaceRecursively(element, ns);
100 private static void setNamespaceRecursively(Element element, Namespace ns) {
101 element.setNamespace(ns);
102 for(Element child : element.getChildren())
103 if(child.getNamespace() == Namespace.NO_NAMESPACE)
104 setNamespaceRecursively(child, ns);
107 public static void clearNamespace(Document document) {
108 clearElementNamespace(document.getRootElement());
111 public static void clearElementNamespace(Element element) {
112 element.setNamespace(null);
113 for (Element child : element.getChildren())
114 clearElementNamespace(child);
117 public static Function parseStringWithSchemaFile(String xsdFile) throws JDOMException {
118 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(new File(xsdFile));
119 SAXBuilder builder = new SAXBuilder(factory);
120 return parseStringWithBuilder(builder);
123 public static Function parseStringWithSchemaURL(URL xsd) throws JDOMException {
124 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(xsd);
125 SAXBuilder builder = new SAXBuilder(factory);
126 return parseStringWithBuilder(builder);
129 public static Function parseFileWithSchemaFile(String xsdFile) throws JDOMException {
130 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(new File(xsdFile));
131 SAXBuilder builder = new SAXBuilder(factory);
132 return parseFileWithBuilder(builder);
135 public static Function parseFileWithSchemaURL(URL xsd) throws JDOMException {
136 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(xsd);
137 SAXBuilder builder = new SAXBuilder(factory);
138 return parseFileWithBuilder(builder);
141 private static Function parseStringWithBuilder(final SAXBuilder builder) {
142 return new FunctionImpl1<String, Document>() {
144 public Document apply(String xml) {
146 return builder.build(new StringReader(xml));
148 catch (JDOMException | IOException e) {
149 throw new RuntimeException(e);
155 private static Function parseFileWithBuilder(final SAXBuilder builder) {
156 return new FunctionImpl1<String, Document>() {
158 public Document apply(String xml) {
160 return builder.build(new File(xml));
162 catch (JDOMException | IOException e) {
163 throw new RuntimeException(e);
169 public static void sortChildrenWith(final Function comparator, Element element) {
170 element.sortChildren(new Comparator() {
172 public int compare(Object o1, Object o2) {
173 return (Integer)comparator.apply(o1, o2);
178 public static void addCDATA(Element element, String cdata) {
179 element.addContent(new CDATA(cdata));
182 public static List<String> getCDATAs(Element element) {
183 ArrayList<String> result = new ArrayList<>();
184 for(Content c : element.getContent()) {
185 if(CType.CDATA.equals(c.getCType())) result.add(c.getValue());