Java tutorial
//package com.java2s; /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun * Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashSet; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.CDATASection; import org.w3c.dom.DOMException; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; public class Main { private static DocumentBuilderFactory[][] doms = new DocumentBuilderFactory[2][2]; /** * Identity transformation in XSLT with indentation added. Just using the * identity transform and calling t.setOutputProperty(OutputKeys.INDENT, * "yes"); t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", * "4"); does not work currently. You really have to use this bogus * stylesheet. * * @see "JDK bug #5064280" */ private static final String IDENTITY_XSLT_WITH_INDENT = "<xsl:stylesheet version='1.0' " + // NOI18N "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " + // NOI18N "xmlns:xalan='http://xml.apache.org/xslt' " + // NOI18N "exclude-result-prefixes='xalan'>" + // NOI18N "<xsl:output method='xml' indent='yes' xalan:indent-amount='4'/>" + // NOI18N "<xsl:template match='@*|node()'>" + // NOI18N "<xsl:copy>" + // NOI18N "<xsl:apply-templates select='@*|node()'/>" + // NOI18N "</xsl:copy>" + // NOI18N "</xsl:template>" + // NOI18N "</xsl:stylesheet>"; /** * Workaround for JAXP bug 7150637 / XALANJ-1497. */ private static final String ORACLE_IS_STANDALONE = "http://www.oracle.com/xml/is-standalone"; /** * Writes a DOM document to a stream. The precise output format is not * guaranteed but this method will attempt to indent it sensibly. * * <p class="nonnormative"><b>Important</b>: There might be some problems * with <code><![CDATA[ ]]></code> sections in the DOM tree you pass * into this method. Specifically, some CDATA sections my not be written as * CDATA section or may be merged with other CDATA section at the same * level. Also if plain text nodes are mixed with CDATA sections at the same * level all text is likely to end up in one big CDATA section. * <br> * For nodes that only have one CDATA section this method should work fine. * </p> * * @param doc DOM document to be written * @param out data sink * @param enc XML-defined encoding name (for example, "UTF-8") * @throws IOException if JAXP fails or the stream cannot be written to */ public static void write(Document doc, OutputStream out, String enc) throws IOException { if (enc == null) { throw new NullPointerException( "You must set an encoding; use \"UTF-8\" unless you have a good reason not to!"); // NOI18N } Document doc2 = normalize(doc); ClassLoader orig = Thread.currentThread().getContextClassLoader(); Thread.currentThread() .setContextClassLoader(AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { // #195921 @Override public ClassLoader run() { return new ClassLoader(ClassLoader.getSystemClassLoader().getParent()) { @Override public InputStream getResourceAsStream(String name) { if (name.startsWith("META-INF/services/")) { return new ByteArrayInputStream(new byte[0]); // JAXP #6723276 } return super.getResourceAsStream(name); } }; } })); try { TransformerFactory tf = TransformerFactory.newInstance(); Transformer t = tf.newTransformer(new StreamSource(new StringReader(IDENTITY_XSLT_WITH_INDENT))); DocumentType dt = doc2.getDoctype(); if (dt != null) { String pub = dt.getPublicId(); if (pub != null) { t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, pub); } String sys = dt.getSystemId(); if (sys != null) { t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, sys); } } t.setOutputProperty(OutputKeys.ENCODING, enc); try { t.setOutputProperty(ORACLE_IS_STANDALONE, "yes"); } catch (IllegalArgumentException x) { // fine, introduced in JDK 7u4 } // See #123816 Set<String> cdataQNames = new HashSet<String>(); collectCDATASections(doc2, cdataQNames); if (cdataQNames.size() > 0) { StringBuilder cdataSections = new StringBuilder(); for (String s : cdataQNames) { cdataSections.append(s).append(' '); //NOI18N } t.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, cdataSections.toString()); } Source source = new DOMSource(doc2); Result result = new StreamResult(out); t.transform(source, result); } catch (javax.xml.transform.TransformerException | RuntimeException e) { // catch anything that happens throw new IOException(e); } finally { Thread.currentThread().setContextClassLoader(orig); } } /** * Try to normalize a document by removing nonsignificant whitespace. * * @see "#62006" */ private static Document normalize(Document orig) throws IOException { DocumentBuilder builder = null; DocumentBuilderFactory factory = getFactory(false, false); try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new IOException("Cannot create parser satisfying configuration parameters: " + e, e); //NOI18N } DocumentType doctype = null; NodeList nl = orig.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { if (nl.item(i) instanceof DocumentType) { // We cannot import DocumentType's, so we need to manually copy it. doctype = (DocumentType) nl.item(i); } } Document doc; if (doctype != null) { doc = builder.getDOMImplementation().createDocument(orig.getDocumentElement().getNamespaceURI(), orig.getDocumentElement().getTagName(), builder.getDOMImplementation().createDocumentType(orig.getDoctype().getName(), orig.getDoctype().getPublicId(), orig.getDoctype().getSystemId())); // XXX what about entity decls inside the DOCTYPE? doc.removeChild(doc.getDocumentElement()); } else { doc = builder.newDocument(); } for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (!(node instanceof DocumentType)) { try { doc.appendChild(doc.importNode(node, true)); } catch (DOMException x) { // Thrown in NB-Core-Build #2896 & 2898 inside GeneratedFilesHelper.applyBuildExtensions throw new IOException("Could not import or append " + node + " of " + node.getClass(), x); } } } doc.normalize(); nl = doc.getElementsByTagName("*"); // NOI18N for (int i = 0; i < nl.getLength(); i++) { Element e = (Element) nl.item(i); removeXmlBase(e); NodeList nl2 = e.getChildNodes(); for (int j = 0; j < nl2.getLength(); j++) { Node n = nl2.item(j); if (n instanceof Text && ((Text) n).getNodeValue().trim().length() == 0) { e.removeChild(n); j--; // since list is dynamic } } } return doc; } private static void collectCDATASections(Node node, Set<String> cdataQNames) { if (node instanceof CDATASection) { Node parent = node.getParentNode(); if (parent != null) { String uri = parent.getNamespaceURI(); if (uri != null) { cdataQNames.add("{" + uri + "}" + parent.getNodeName()); //NOI18N } else { cdataQNames.add(parent.getNodeName()); } } } NodeList children = node.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { collectCDATASections(children.item(i), cdataQNames); } } private static synchronized DocumentBuilderFactory getFactory(boolean validate, boolean namespaceAware) { DocumentBuilderFactory factory = doms[validate ? 0 : 1][namespaceAware ? 0 : 1]; if (factory == null) { factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validate); factory.setNamespaceAware(namespaceAware); doms[validate ? 0 : 1][namespaceAware ? 0 : 1] = factory; } return factory; } /** * Creates an empty DOM document. E.g.: * <pre> * Document doc = createDocument("book", null, null, null); * </pre> creates new DOM of a well-formed document with root element named * book. * * @param rootQName qualified name of root element, for example * <code>myroot</code> or <code>ns:myroot</code> * @param namespaceURI URI of root element namespace or <code>null</code> * @param doctypePublicID public ID of DOCTYPE or <code>null</code> * @param doctypeSystemID system ID of DOCTYPE or <code>null</code> if no * DOCTYPE required and doctypePublicID is also * <code>null</code> * * @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 <code>NOT_SUPPORTED_ERR</code> 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 = getFactory(false, false); 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); } } private static void removeXmlBase(Element e) { e.removeAttributeNS("http://www.w3.org/XML/1998/namespace", "base"); // NOI18N e.removeAttribute("xml:base"); // NOI18N } }