001/**
002The contents of this file are subject to the Mozilla Public License Version 1.1 
003(the "License"); you may not use this file except in compliance with the License. 
004You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
005Software distributed under the License is distributed on an "AS IS" basis, 
006WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 
007specific language governing rights and limitations under the License. 
008
009The Original Code is "XMLUtils.java".  Description: 
010"XML utilities" 
011
012The Initial Developer of the Original Code is University Health Network. Copyright (C) 
0132001.  All Rights Reserved. 
014
015Contributor(s): ______________________________________. 
016
017Alternatively, the contents of this file may be used under the terms of the 
018GNU General Public License (the  "GPL"), in which case the provisions of the GPL are 
019applicable instead of those above.  If you wish to allow use of your version of this 
020file only under the terms of the GPL and not to allow others to use your version 
021of this file under the MPL, indicate your decision by deleting  the provisions above 
022and replace  them with the notice and other provisions required by the GPL License.  
023If you do not delete the provisions above, a recipient may use your version of 
024this file under either the MPL or the GPL. 
025 */
026package ca.uhn.hl7v2.util;
027
028import java.io.InputStream;
029import java.io.StringWriter;
030import java.io.Writer;
031
032import org.w3c.dom.DOMConfiguration;
033import org.w3c.dom.DOMErrorHandler;
034import org.w3c.dom.DOMImplementation;
035import org.w3c.dom.Document;
036import org.w3c.dom.bootstrap.DOMImplementationRegistry;
037import org.w3c.dom.ls.DOMImplementationLS;
038import org.w3c.dom.ls.LSInput;
039import org.w3c.dom.ls.LSOutput;
040import org.w3c.dom.ls.LSParser;
041import org.w3c.dom.ls.LSResourceResolver;
042import org.w3c.dom.ls.LSSerializer;
043
044public class XMLUtils {
045
046    private static DOMImplementation IMPL;
047
048    @SuppressWarnings("unchecked")
049    public synchronized static <T> T getDOMImpl() {
050        if (IMPL == null) {
051            try {
052                DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
053                IMPL = registry.getDOMImplementation("LS 3.0");
054            } catch (Exception e) {
055                throw new RuntimeException(e);
056            }
057        }
058        return (T) IMPL;
059    }
060
061    @SuppressWarnings("unchecked")
062    public static <T> T getDOMImplUncached() {
063        try {
064            DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
065            return (T) registry.getDOMImplementation("LS 3.0");
066        } catch (Exception e) {
067            throw new RuntimeException(e);
068        }
069    }
070
071    public static Document parse(String s) {
072        return parse(s, false);
073    }
074
075    public static Document parse(String s, boolean validateIfSchema) {
076        DOMImplementationLS impl = getDOMImpl();
077        LSInput input = impl.createLSInput();
078        input.setStringData(s);
079        return parse(input, validateIfSchema);
080    }
081
082    public static Document parse(InputStream s, boolean validateIfSchema) {
083        DOMImplementationLS impl = getDOMImpl();
084        LSInput input = impl.createLSInput();
085        input.setByteStream(s);
086        return parse(input, validateIfSchema);
087    }
088
089    private static Document parse(LSInput input, boolean validateIfSchema) {
090        DOMImplementationLS impl = getDOMImpl();
091        LSParser parser = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
092        DOMConfiguration config = parser.getDomConfig();
093        config.setParameter("element-content-whitespace", false);
094        config.setParameter("namespaces", true);
095        config.setParameter("validate-if-schema", validateIfSchema);
096        return parser.parse(input);
097    }
098
099    public static void validate(Document d, String schema, DOMErrorHandler handler) {
100        DOMConfiguration config = d.getDomConfig();
101        config.setParameter("schema-type", "http://www.w3.org/2001/XMLSchema");
102        config.setParameter("validate", true);
103        config.setParameter("schema-location", schema);
104        config.setParameter("resource-resolver", new ClasspathResourceResolver());
105        config.setParameter("error-handler", handler);
106        d.normalizeDocument();
107    }
108
109    public static String serialize(Document document, boolean prettyPrint) {
110        DOMImplementationLS impl = getDOMImpl();
111        LSSerializer serializer = impl.createLSSerializer();
112        // document.normalizeDocument();
113        DOMConfiguration config = serializer.getDomConfig();
114        if (prettyPrint && config.canSetParameter("format-pretty-print", Boolean.TRUE)) {
115            config.setParameter("format-pretty-print", true);
116        }
117        config.setParameter("xml-declaration", true);        
118        LSOutput output = impl.createLSOutput();
119        output.setEncoding("UTF-8");
120        Writer writer = new StringWriter();
121        output.setCharacterStream(writer);
122        serializer.write(document, output);
123        return writer.toString();
124    }
125
126    public static Document emptyDocument(String title) {
127        DOMImplementation impl = getDOMImpl();
128        Document doc = impl.createDocument("urn:hl7-org:v2xml", title, null);
129        return doc;
130    }
131
132    /**
133     * This is an implementation of LSResourceResolver that can resolve XML schemas from the
134     * classpath
135     */
136    private static class ClasspathResourceResolver implements LSResourceResolver {
137        private DOMImplementationLS impl;
138
139        ClasspathResourceResolver() {
140            impl = getDOMImpl();
141        }
142
143        public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId,
144                String baseURI) {
145            LSInput lsInput = impl.createLSInput();
146            InputStream is = getClass().getResourceAsStream("/" + systemId);
147            if (is == null)
148                return null;
149            lsInput.setByteStream(is);
150            return lsInput;
151        }
152    }
153
154}