alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.xml;

import java.io.*;

import javax.xml.parsers.*;
import org.openide.ErrorManager;

import org.w3c.dom.*;
import org.xml.sax.*;

/**
 * Utility class collecting library methods related to XML processing.
 *
 * 
* *

Remember that when parsing XML files you often want to set an explicit * entity resolver. For example, consider a file such as this:

* *
 * <?xml version="1.0" encoding="UTF-8"?>
 * <!DOCTYPE root PUBLIC "-//NetBeans//DTD Foo 1.0//EN" "http://www.netbeans.org/dtds/foo-1_0.dtd">
 * <root/>
 * 
* *

If you parse this with a null entity resolver, or you use the * default resolver ({@link EntityCatalog#getDefault}) but do not do * anything special with this DTD, you will probably find the parse * blocking to make a network connection even when you are not * validating. That is because DTDs can be used to define * entities and other XML oddities, and are not a pure constraint * language like Schema or RELAX-NG.

* *

There are three basic ways to avoid the network connection.

* *
    * *
  1. Register the DTD. This is generally the best thing to do. See * {@link EntityCatalog}'s documentation for details, but for example * in your layer use:

    * *
     * <filesystem>
     *   <folder name="xml">
     *     <folder name="entities">
     *       <folder name="NetBeans">
     *         <file name="DTD_Foo_1_0"
     *               url="nbres:/org/netbeans/modules/mymod/resources/foo-1_0.dtd">
     *           <attr name="hint.originalPublicID"
     *                 stringvalue="-//NetBeans//DTD Foo 1.0//EN"/>
     *         </file>
     *       </folder>
     *     </folder>
     *   </folder>
     * </filesystem>
     * 
    * *

    Now the default system entity catalog will resolve the public ID * to the local copy in your module, not the network copy. * Additionally, anyone who mounts the "NetBeans Catalog" in the XML * Entity Catalogs node in the Runtime tab will be able to use your * local copy of the DTD automatically, for validation, code * completion, etc. (The network URL should really exist, though, for * the benefit of other tools!)

  2. * *
  3. You can also set an explicit entity resolver which maps that * particular public ID to some local copy of the DTD, if you do not * want to register it globally in the system for some reason. If * handed other public IDs, just return null to indicate that the * system ID should be loaded.

  4. * *
  5. In some cases where XML parsing is very * performance-sensitive, and you know that you do not need validation * and furthermore that the DTD defines no infoset (there are no * entity or character definitions, etc.), you can speed up the parse. * Turn off validation, but also supply a custom entity resolver that * does not even bother to load the DTD at all:

    * *
     * public InputSource resolveEntity(String pubid, String sysid)
     *     throws SAXException, IOException {
     *   if (pubid.equals("-//NetBeans//DTD Foo 1.0//EN")) {
     *     return new InputSource(new ByteArrayInputStream(new byte[0]));
     *   } else {
     *     return EntityCatalog.getDefault().resolveEntity(pubid, sysid);
     *   }
     * }
     * 
  6. * *
* *
* * @author Petr Kuzel * @since release 3.2 */ public final class XMLUtil extends Object { /** Use fast SAX parser factory until someone asks for validating parser. */ private static boolean useFastSAXParserFactory = true; /** Forbids creating new XMLUtil */ private XMLUtil() { } // ~~~~~~~~~~~~~~~~~~~~~ SAX related ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** Create a simple parser. * @return createXMLReader(false, false) */ public static XMLReader createXMLReader() throws SAXException { return createXMLReader(false, false); } /** Create a simple parser, possibly validating. * @param validate if true, a validating parser is returned * @return createXMLReader(validate, false) */ public static XMLReader createXMLReader(boolean validate) throws SAXException{ return createXMLReader(validate, false); } /** Create a SAX parser from the JAXP factory. * The result can be used to parse XML files. * *

See class Javadoc for hints on setting an entity resolver. * This parser has its entity resolver set to the system entity resolver chain. * * @param validate if true, a validating parser is returned * @param namespaceAware if true, a namespace aware parser is returned * * @throws FactoryConfigurationError Application developers should never need to directly catch errors of this type. * @throws SAXException if a parser fulfilling given parameters can not be created * * @return XMLReader configured according to passed parameters */ public static XMLReader createXMLReader(boolean validate, boolean namespaceAware) throws SAXException { SAXParserFactory factory; if (!validate && useFastSAXParserFactory) { try { factory = createFastSAXParserFactory(); } catch (ParserConfigurationException ex) { factory = SAXParserFactory.newInstance(); } catch (SAXException ex) { factory = SAXParserFactory.newInstance(); } } else { useFastSAXParserFactory = false; factory = SAXParserFactory.newInstance(); } factory.setValidating(validate); factory.setNamespaceAware(namespaceAware); try { return factory.newSAXParser().getXMLReader(); } catch (ParserConfigurationException ex) { throw new SAXException("Cannot create parser satisfying configuration parameters", ex); //NOI18N } } // ~~~~~~~~~~~~~~~~~~~~~ DOM related ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Creates empty DOM Document using JAXP factoring. E.g.: *

     * Document doc = createDocument("book", null, null, null);
     * 

* creates new DOM of a well-formed document with root element named book. * * @param rootQName qualified name of root element. e.g. myroot or ns:myroot * @param namespaceURI URI of root element namespace or null * @param doctypePublicID public ID of DOCTYPE or null * @param doctypeSystemID system ID of DOCTYPE or null if no DOCTYPE * required and doctypePublicID is also null * * @throws DOMException if new DOM with passed parameters can not be created * @throws FactoryConfigurationError Application developers should never need to directly catch errors of this type. * * @return new DOM Document */ public static Document createDocument(String rootQName, String namespaceURI, String doctypePublicID, String doctypeSystemID) throws DOMException { DOMImplementation impl = getDOMImplementation(); if (doctypePublicID != null && doctypeSystemID == null) { throw new IllegalArgumentException("System ID cannot be null if public ID specified. "); //NOI18N } DocumentType dtd = null; if (doctypeSystemID != null) { dtd = impl.createDocumentType(rootQName, doctypePublicID, doctypeSystemID); } return impl.createDocument(namespaceURI, rootQName, dtd); } /** * Obtains DOMImpementaton interface providing a number of methods for performing * operations that are independent of any particular DOM instance. * * @throw DOMException NOT_SUPPORTED_ERR if cannot get DOMImplementation * @throw FactoryConfigurationError Application developers should never need to directly catch errors of this type. * * @return DOMImplementation implementation */ private static DOMImplementation getDOMImplementation() throws DOMException { //can be made public DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { return factory.newDocumentBuilder().getDOMImplementation(); } catch (ParserConfigurationException ex) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR , "Cannot create parser satisfying configuration parameters"); //NOI18N } catch (RuntimeException e) { // E.g. #36578, IllegalArgumentException. Try to recover gracefully. throw (DOMException)new DOMException(DOMException.NOT_SUPPORTED_ERR, e.toString()).initCause(e); } } /** * Create from factory a DocumentBuilder and let it create a org.w3c.dom.Document. * This method takes InputSource. After successful finish the document tree is returned. * * @param input a parser input (for URL users use: new InputSource(url.toExternalForm()) * @param validate if true validating parser is used * @param namespaceAware if true DOM is created by namespace aware parser * @param errorHandler a error handler to notify about exception or null * @param entityResolver SAX entity resolver or null; see class Javadoc for hints * * @throws IOException if an I/O problem during parsing occurs * @throws SAXException is thrown if a parser error occurs * @throws FactoryConfigurationError Application developers should never need to directly catch errors of this type. * * @return document representing given input, or null if a parsing error occurs */ public static Document parse ( InputSource input, boolean validate, boolean namespaceAware, ErrorHandler errorHandler, EntityResolver entityResolver ) throws IOException, SAXException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validate); factory.setNamespaceAware(namespaceAware); DocumentBuilder builder = null; try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException ex) { throw new SAXException("Cannot create parser satisfying configuration parameters", ex); //NOI18N } if (errorHandler != null) { builder.setErrorHandler(errorHandler); } if (entityResolver != null) { builder.setEntityResolver(entityResolver); } return builder.parse(input); } /** * Write Document into OutputStream using given encoding. * It is a shortcut for writing configurations etc. It guarantees * just that data will be written. Structure and indentation may change. * * @param doc DOM Document to be written * @param out data sink * @param enc XML defined encoding name (i.e. IANA defined, one of UTF-8, UNICODE, ASCII) * * @throws IOException if an I/O exception occurs */ public static void write(Document doc, OutputStream out, String enc) throws IOException { XMLUtilImpl.write(doc, out, enc); } /** * Escape passed string as XML attibute value * (<, &, ' and " * will be escaped. * Note: An XML processor returns normalized value that can be different. * * @param val a string to be escaped * * @return escaped value * @throws CharConversionException if val contains an improper XML character * * @since 1.40 */ public static String toAttributeValue(String val) throws CharConversionException { if (val == null) throw new CharConversionException("null"); // NOI18N if (checkAttributeCharacters(val)) return val; StringBuffer buf = new StringBuffer(); for (int i = 0; i<, * & and > in ]]> sequences). * * @param val a string to be escaped * * @return escaped value * @throws CharConversionException if val contains an improper XML character * * @since 1.40 */ public static String toElementContent(String val) throws CharConversionException { if (val == null) throw new CharConversionException("null"); // NOI18N if (checkContentCharacters(val)) return val; StringBuffer buf = new StringBuffer(); for (int i = 0; i' == ch && i>1 && val.charAt(i-2) == ']' && val.charAt(i-1) == ']') { buf.append(">"); continue; } buf.append(ch); } return buf.toString(); } /* public static String toCDATA(String val) throws IOException { } */ private static final char[] DEC2HEX = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; /** * Can be used to encode values that contain invalid XML characters. * At SAX parser end must be used pair method to get original value. * * @param val data to be converted * @param start offset * @param len count * * @since 1.29 */ public static String toHex(byte[] val, int start, int len) { StringBuffer buf = new StringBuffer(); for (int i = 0; i> 4]); buf.append(DEC2HEX[b & 0x0f]); } return buf.toString(); } /** * Decodes data encoded using {@link #toHex(byte[],int,int) toHex}. * * @param hex data to be converted * @param start offset * @param len count * * @throws IOException if input does not represent hex encoded value * * @since 1.29 */ public static byte[] fromHex(char[] hex, int start, int len) throws IOException { if (hex == null) throw new IOException("null"); int i = hex.length; if (i % 2 != 0) throw new IOException("odd length"); byte[] magic = new byte[i/2]; for (;i>0; i-=2) { String g = new String(hex, i-2, 2); try { magic[(i/2) -1] = (byte) Integer.parseInt(g, 16); } catch (NumberFormatException ex) { throw new IOException(ex.getLocalizedMessage()); } } return magic; } /** * Check if all passed characters match XML expression [2]. * @return true if no escaping necessary * @throws CharConversionException if contains invalid chars */ private static boolean checkAttributeCharacters(String chars) throws CharConversionException { boolean escape = false; for (int i = 0; i': // only ]]> is dangerous if (escape) continue; escape = i > 0 && (chars.charAt(i - 1) == ']'); continue; case '<': case '&': escape = true; continue; default: if (((int) ch) < 0x20) { throw new CharConversionException("Invalid XML character &#" + ((int)ch) + ";."); } } } } return escape == false; } private static Class fastParserFactoryClass = null; private static SAXParserFactory createFastSAXParserFactory() throws ParserConfigurationException, SAXException { if (fastParserFactoryClass == null) { try { fastParserFactoryClass = Class.forName("org.apache.crimson.jaxp.SAXParserFactoryImpl"); // NOI18N } catch (Exception ex) { useFastSAXParserFactory = false; if (System.getProperty("java.version").startsWith("1.4")) { // NOI18N ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); } } } if (fastParserFactoryClass != null) { try { SAXParserFactory factory = (SAXParserFactory) fastParserFactoryClass.newInstance(); return factory; } catch (Exception ex) { useFastSAXParserFactory = false; throw new ParserConfigurationException(ex.getMessage()); } } return SAXParserFactory.newInstance(); } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.