slightly more robust XML parsing of the GPX track (elevation is now
[utils] / support / src / org / wamblee / xml / DomUtils.java
index 05eae128640fa9b70a829a7e7c33814e379ca891..5651e34137f8caeec1c419a630a6840a947b1a82 100644 (file)
@@ -12,7 +12,7 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */ 
+ */
 
 package org.wamblee.xml;
 
@@ -26,9 +26,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -45,84 +49,160 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
+import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
+import com.sun.org.apache.xerces.internal.jaxp.validation.xs.SchemaFactoryImpl;
+
 /**
- * Some basic XML utilities for common reoccuring tasks for 
- * DOM documents.  
+ * Some basic XML utilities for common reoccuring tasks for DOM documents.
  */
 public final class DomUtils {
-    
+
     private static final Log LOG = LogFactory.getLog(DomUtils.class);
-    
+
     /**
-     * Disabled default constructor. 
-     *
+     * Disabled default constructor.
+     * 
      */
-    private DomUtils() { 
-        // Empty. 
+    private DomUtils() {
+        // Empty.
     }
-    
+
     /**
-     * Parses an XML document from a string. 
-     * @param aDocument document. 
-     * @return 
+     * Parses an XML document from a string.
+     * 
+     * @param aDocument
+     *            document.
+     * @return
      */
-    public static Document read(String aDocument) throws SAXException, ParserConfigurationException, IOException {
+    public static Document read(String aDocument) throws XMLException {
         ByteArrayInputStream is = new ByteArrayInputStream(aDocument.getBytes());
-        return read(is);          
+        return read(is);
     }
-    
+
     /**
-     * Parses an XML document from a stream. 
-     * @param aIs Input stream. 
+     * Parses an XML document from a stream.
+     * 
+     * @param aIs
+     *            Input stream.
      * @return
      */
-    public static Document read(InputStream aIs) throws SAXException, ParserConfigurationException, IOException { 
-        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
-        return builder.parse(aIs);     
+    public static Document read(InputStream aIs) throws XMLException {
+        try {
+            DocumentBuilder builder = DocumentBuilderFactory.newInstance()
+                    .newDocumentBuilder();
+            return builder.parse(aIs);
+        }  catch (SAXException e) {
+            throw new XMLException(e.getMessage(), e);
+        } catch (IOException e) {
+            throw new XMLException(e.getMessage(), e);
+        } catch (ParserConfigurationException e) {
+            throw new XMLException(e.getMessage(), e);
+        } finally {
+            try {
+                aIs.close();
+            } catch (Exception e) {
+                LOG.warn("Error closing XML file", e);
+            }
+        }
     }
 
     /**
-     * Serializes an XML document to a stream. 
-     * @param aDocument Document to serialize. 
-     * @param aOs Output stream. 
+     * Reads and validates a document against a schema.
+     * 
+     * @param aIs
+     *            Input stream.
+     * @param aSchema
+     *            Schema.
+     * @return Parsed and validated document.
      */
-    public static void serialize(Document aDocument, OutputStream aOs) throws IOException { 
+    public static Document readAndValidate(InputStream aIs, InputStream aSchema)
+            throws XMLException {
+
+        try {
+            final Schema schema = SchemaFactory.newInstance(
+                    XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
+                    new StreamSource(aSchema));
+
+            final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setValidating(true);
+            factory.setNamespaceAware(true);
+            factory.setSchema(schema);
+
+            return factory.newDocumentBuilder().parse(aIs);
+        } catch (SAXException e) {
+            throw new XMLException(e.getMessage(), e);
+        } catch (IOException e) {
+            throw new XMLException(e.getMessage(), e);
+        } catch (ParserConfigurationException e) {
+            throw new XMLException(e.getMessage(), e);
+        } finally {
+            try {
+                aSchema.close();
+            } catch (Exception e) {
+                LOG.warn("Error closing schema", e);
+            }
+            try {
+                aIs.close();
+            } catch (Exception e) {
+                LOG.warn("Error closing XML file", e);
+            }
+        }
+
+    }
+
+    /**
+     * Serializes an XML document to a stream.
+     * 
+     * @param aDocument
+     *            Document to serialize.
+     * @param aOs
+     *            Output stream.
+     */
+    public static void serialize(Document aDocument, OutputStream aOs)
+            throws IOException {
         XMLSerializer serializer = new XMLSerializer(aOs, new OutputFormat());
         serializer.serialize(aDocument);
     }
-    
+
     /**
-     * Serializes an XML document. 
-     * @param aDocument Document to serialize. 
-     * @return Serialized document. 
+     * Serializes an XML document.
+     * 
+     * @param aDocument
+     *            Document to serialize.
+     * @return Serialized document.
      */
     public static String serialize(Document aDocument) throws IOException {
         ByteArrayOutputStream os = new ByteArrayOutputStream();
-        serialize(aDocument, os); 
-        return os.toString(); 
+        serialize(aDocument, os);
+        return os.toString();
     }
-    
+
     /**
-     * Converts a dom4j document into a w3c DOM document. 
-     * @param aDocument Document to convert. 
-     * @return W3C DOM document. 
+     * Converts a dom4j document into a w3c DOM document.
+     * 
+     * @param aDocument
+     *            Document to convert.
+     * @return W3C DOM document.
      */
-    public static Document convert(org.dom4j.Document aDocument) throws DocumentException {
+    public static Document convert(org.dom4j.Document aDocument)
+            throws DocumentException {
         return new DOMWriter().write(aDocument);
     }
 
     /**
-     * Converts a W3C DOM document into a dom4j document. 
-     * @param aDocument Document to convert. 
+     * Converts a W3C DOM document into a dom4j document.
+     * 
+     * @param aDocument
+     *            Document to convert.
      * @return Dom4j document.
      */
-    public static org.dom4j.Document convert(Document aDocument) { 
-        return new DOMReader().read(aDocument); 
+    public static org.dom4j.Document convert(Document aDocument) {
+        return new DOMReader().read(aDocument);
     }
-    
+
     /**
-     * Removes duplicate attributes from a DOM tree.This is useful for postprocessing the
-     * output of JTidy as a workaround for a bug in JTidy. 
+     * Removes duplicate attributes from a DOM tree.This is useful for
+     * postprocessing the output of JTidy as a workaround for a bug in JTidy.
      * 
      * @param aNode
      *            Node to remove duplicate attributes from (recursively).