Coverage Report - net.sf.practicalxml.ParseUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
ParseUtil
69%
45/65
62%
5/8
3.062
 
 1  
 // Copyright 2008-2014 severally by the contributors
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 
 15  
 package net.sf.practicalxml;
 16  
 
 17  
 import java.io.BufferedInputStream;
 18  
 import java.io.File;
 19  
 import java.io.FileInputStream;
 20  
 import java.io.FileNotFoundException;
 21  
 import java.io.IOException;
 22  
 import java.io.InputStream;
 23  
 import java.io.StringReader;
 24  
 
 25  
 import javax.xml.parsers.DocumentBuilder;
 26  
 import javax.xml.parsers.DocumentBuilderFactory;
 27  
 import javax.xml.parsers.ParserConfigurationException;
 28  
 import javax.xml.validation.Schema;
 29  
 
 30  
 import org.w3c.dom.Document;
 31  
 import org.xml.sax.EntityResolver;
 32  
 import org.xml.sax.ErrorHandler;
 33  
 import org.xml.sax.InputSource;
 34  
 import org.xml.sax.SAXException;
 35  
 
 36  
 import net.sf.kdgcommons.io.IOUtil;
 37  
 import net.sf.practicalxml.util.ExceptionErrorHandler;
 38  
 
 39  
 
 40  
 /**
 41  
  *  A collection of static methods for parsing XML into a DOM, with or without
 42  
  *  validation.
 43  
  */
 44  0
 public class ParseUtil
 45  
 {
 46  
     /**
 47  
      *  Parses the supplied source with a namespace-aware, non-validating
 48  
      *  parser, using a caller-supplied error handler.
 49  
      *
 50  
      *  @throws XmlException for any configuration or fatal execution error.
 51  
      */
 52  
     public static Document parse(InputSource source, ErrorHandler errHandler)
 53  
     {
 54  32
         DocumentBuilder db = newNVDocumentBuilder();
 55  32
         if (errHandler != null)
 56  32
             db.setErrorHandler(errHandler);
 57  
 
 58  
         try
 59  
         {
 60  32
             return db.parse(source);
 61  
         }
 62  0
         catch (IOException e)
 63  
         {
 64  0
             throw new XmlException("unable to parse", e);
 65  
         }
 66  0
         catch (SAXException e)
 67  
         {
 68  0
             throw new XmlException("unable to parse", e);
 69  
         }
 70  
     }
 71  
 
 72  
 
 73  
     /**
 74  
      *  Parses the supplied source with a namespace-aware, non-validating
 75  
      *  parser, using the built-in error handler that throws on parse errors
 76  
      *  and ignores warnings.
 77  
      *
 78  
      *  @throws XmlException for any configuration or execution error.
 79  
      */
 80  
     public static Document parse(InputSource source)
 81  
     {
 82  30
         return parse(source, new ExceptionErrorHandler());
 83  
     }
 84  
 
 85  
 
 86  
     /**
 87  
      *  Parses the supplied source with a namespace-aware, non-validating
 88  
      *  parser, using the built-in error handler that throws on parse errors
 89  
      *  and ignores warnings. Closes the stream after parsing is complete.
 90  
      *
 91  
      *  @throws XmlException for any configuration or execution error,
 92  
      *          including <code>IOException</code>
 93  
      *
 94  
      *  @since 1.1.18
 95  
      */
 96  
     public static Document parse(InputStream in)
 97  
     {
 98  
         try
 99  
         {
 100  1
             return parse(new InputSource(new BufferedInputStream(in)));
 101  
         }
 102  
         finally
 103  
         {
 104  1
             IOUtil.closeQuietly(in);
 105  
         }
 106  
     }
 107  
 
 108  
 
 109  
     /**
 110  
      *  Parses a string containing XML, using a namespace-aware, non-validating
 111  
      *  parser. Note that this ignores any encoding specification in the
 112  
      *  prologue; if you read the string from a file, make sure that you used
 113  
      *  the correct encoding.
 114  
      *
 115  
      *  @throws XmlException for any configuration or execution error.
 116  
      */
 117  
     public static Document parse(String xml)
 118  
     {
 119  14
         return parse(new InputSource(new StringReader(xml)));
 120  
     }
 121  
 
 122  
 
 123  
     /**
 124  
      *  Parses a file using a namespace-aware, non-validating parser. Ensures that
 125  
      *  there are no dangling <code>FileInputStream</code>s for the finalizer to
 126  
      *  close.
 127  
      *
 128  
      *  @throws XmlException for any error, including file-not-found.
 129  
      *
 130  
      *  @since 1.1.11
 131  
      */
 132  
     public static Document parse(File file)
 133  
     {
 134  
         try
 135  
         {
 136  2
             return parse(new FileInputStream(file));
 137  
         }
 138  1
         catch (FileNotFoundException ex)
 139  
         {
 140  1
             throw new XmlException("file not found: " + file, ex);
 141  
         }
 142  
     }
 143  
 
 144  
 
 145  
     /**
 146  
      *  Parses the supplied source with a namespace-aware, DTD-validating
 147  
      *  parser, using a caller-supplied error handler and entity resolver.
 148  
      *  Both of these objects may be <code>null</code>, to use the built-in
 149  
      *  defaults.
 150  
      *
 151  
      *  @throws XmlException for any configuration or fatal execution error.
 152  
      */
 153  
     public static Document validatingParse(
 154  
             InputSource source, EntityResolver resolver,
 155  
             ErrorHandler errHandler)
 156  
     {
 157  4
         DocumentBuilder db = newDTDDocumentBuilder();
 158  4
         if (resolver != null)
 159  1
             db.setEntityResolver(resolver);
 160  4
         if (errHandler != null)
 161  4
             db.setErrorHandler(errHandler);
 162  
 
 163  
         try
 164  
         {
 165  4
             return db.parse(source);
 166  
         }
 167  0
         catch (IOException e)
 168  
         {
 169  0
             throw new XmlException("unable to parse", e);
 170  
         }
 171  0
         catch (SAXException e)
 172  
         {
 173  0
             throw new XmlException("unable to parse", e);
 174  
         }
 175  
     }
 176  
 
 177  
 
 178  
     /**
 179  
      *  Parses the supplied source with a namespace-aware, DTD-validating
 180  
      *  parser, using a caller-supplied error handler and default entity
 181  
      *  resolver. This is useful when the DTD is publicly accessible.
 182  
      *
 183  
      *  @throws XmlException for any configuration or fatal execution error.
 184  
      */
 185  
     public static Document validatingParse(
 186  
             InputSource source, ErrorHandler errHandler)
 187  
     {
 188  3
         return validatingParse(source, (EntityResolver)null, errHandler);
 189  
     }
 190  
 
 191  
 
 192  
     /**
 193  
      *  Parses the supplied source with a namespace-aware, XSD-validating
 194  
      *  parser, using a caller-supplied error handler and entity resolver.
 195  
      *  Both of these objects may be <code>null</code>, to use the built-in
 196  
      *  defaults.
 197  
      *
 198  
      *  @throws XmlException for any configuration or fatal execution error.
 199  
      */
 200  
     public static Document validatingParse(
 201  
             InputSource source, Schema schema, ErrorHandler errHandler)
 202  
     {
 203  7
         DocumentBuilder db = newXSDDocumentBuilder(schema);
 204  7
         if (errHandler != null)
 205  7
             db.setErrorHandler(errHandler);
 206  
 
 207  
         try
 208  
         {
 209  7
             return db.parse(source);
 210  
         }
 211  0
         catch (IOException e)
 212  
         {
 213  0
             throw new XmlException("unable to parse", e);
 214  
         }
 215  0
         catch (SAXException e)
 216  
         {
 217  0
             throw new XmlException("unable to parse", e);
 218  
         }
 219  
     }
 220  
 
 221  
 
 222  
     /**
 223  
      *  Parses a resource loaded from the classpath, using the current thread's context
 224  
      *  classloader, and a default error handler.
 225  
      */
 226  
     public static Document parseFromClasspath(String resourcePath)
 227  
     {
 228  1
         return parseFromClasspath(resourcePath, new ExceptionErrorHandler());
 229  
     }
 230  
 
 231  
 
 232  
     /**
 233  
      *  Parses a resource loaded from the classpath, using the current thread's context
 234  
      *  classloader, and a specified error handler.
 235  
      */
 236  
     public static Document parseFromClasspath(String resourcePath, ErrorHandler errorHandler)
 237  
     {
 238  2
         return parseFromClasspath(Thread.currentThread().getContextClassLoader(), resourcePath, errorHandler);
 239  
     }
 240  
 
 241  
 
 242  
     /**
 243  
      *  Parses a resource loaded from the classpath, using the classloader
 244  
      *  associated with the specified class, and a default error handler.
 245  
      */
 246  
     public static Document parseFromClasspath(String resourcePath, Class<?> klass)
 247  
     {
 248  1
         return parseFromClasspath(resourcePath, new ExceptionErrorHandler());
 249  
     }
 250  
 
 251  
 
 252  
     /**
 253  
      *  Parses a resource loaded from the classpath, using the classloader
 254  
      *  associated with the specified class, and the specified error handler.
 255  
      */
 256  
     public static Document parseFromClasspath(String resourcePath, Class<?> klass, ErrorHandler errorHandler)
 257  
     {
 258  0
         return parseFromClasspath(klass.getClassLoader(), resourcePath, errorHandler);
 259  
     }
 260  
 
 261  
 
 262  
 //----------------------------------------------------------------------------
 263  
 //  Internals
 264  
 //----------------------------------------------------------------------------
 265  
 
 266  
     /**
 267  
      *  Returns a namespace-aware, non-validating parser.
 268  
      */
 269  
     private static synchronized DocumentBuilder newNVDocumentBuilder()
 270  
     {
 271  32
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 272  32
         dbf.setNamespaceAware(true);
 273  32
         dbf.setCoalescing(true);
 274  32
         dbf.setValidating(false);
 275  
 
 276  
         try
 277  
         {
 278  32
             return dbf.newDocumentBuilder();
 279  
         }
 280  0
         catch (ParserConfigurationException e)
 281  
         {
 282  0
             throw new XmlException("unable to confiure parser", e);
 283  
         }
 284  
     }
 285  
 
 286  
 
 287  
     /**
 288  
      *  Returns a namespace-aware, DTD-validating parser.
 289  
      */
 290  
     private static synchronized DocumentBuilder newDTDDocumentBuilder()
 291  
     {
 292  4
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 293  4
         dbf.setNamespaceAware(true);
 294  4
         dbf.setValidating(true);
 295  4
         dbf.setCoalescing(true);
 296  
 
 297  
         try
 298  
         {
 299  4
             return dbf.newDocumentBuilder();
 300  
         }
 301  0
         catch (ParserConfigurationException e)
 302  
         {
 303  0
             throw new XmlException("unable to confiure parser", e);
 304  
         }
 305  
     }
 306  
 
 307  
 
 308  
     /**
 309  
      *  Returns a namespace-aware, XSD-validating parser using the supplied
 310  
      *  schema. Note that we don't use a singleton factory, because the schema
 311  
      *  gets applied to the factory, not the parser.
 312  
      */
 313  
     private static synchronized DocumentBuilder newXSDDocumentBuilder(Schema schema)
 314  
     {
 315  7
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 316  7
         dbf.setNamespaceAware(true);
 317  7
         dbf.setCoalescing(true);
 318  7
         dbf.setValidating(false);
 319  7
         dbf.setSchema(schema);
 320  
 
 321  
         try
 322  
         {
 323  7
             return dbf.newDocumentBuilder();
 324  
         }
 325  0
         catch (ParserConfigurationException e)
 326  
         {
 327  0
             throw new XmlException("unable to configure parser", e);
 328  
         }
 329  
     }
 330  
 
 331  
 
 332  
     /**
 333  
      *  Parses the specified classpath resource, in the context of a given classloader.
 334  
      */
 335  
     private static Document parseFromClasspath(ClassLoader classloader, String resourcePath, ErrorHandler errorHandler)
 336  
     {
 337  2
         InputStream in = null;
 338  
         try
 339  
         {
 340  2
             in = classloader.getResourceAsStream(resourcePath);
 341  2
             return parse(new InputSource(in), errorHandler);
 342  
         }
 343  
         finally
 344  
         {
 345  2
             IOUtil.closeQuietly(in);
 346  
         }
 347  
     }
 348  
 }