Java XML Document to Stream write(Document doc, OutputStream out, String enc)

Here you can find the source of write(Document doc, OutputStream out, String enc)

Description

Writes a DOM document to a stream.

License

Open Source License

Parameter

Parameter Description
doc DOM document to be written
out data sink
enc XML-defined encoding name (e.g. "UTF-8")

Exception

Parameter Description
IOException if JAXP fails or the stream cannot be written to

Declaration

public static void write(Document doc, OutputStream out, String enc) throws IOException 

Method Source Code


//package com.java2s;
/*/*from w w w  .  j  a v  a 2 s .  co m*/
 * 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>&lt;![CDATA[ ]]&gt;</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 (e.g. "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 (Exception e) {
            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.:
     * <p><pre>
     * Document doc = createDocument("book", null, null, null);
     * </pre><p>
     * creates new DOM of a well-formed document with root element named book.
     *
     * @param rootQName qualified name of root element. e.g. <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
    }
}

Related

  1. documentToStream(Document document, OutputStream outputStream, String encoding)
  2. dom2InputStream(Document doc)
  3. dumpDoc(Document domTree, PrintStream out)
  4. dumpToStream(Document doc, OutputStream out)
  5. toXml(Document doc, OutputStream out)
  6. write(Document document, OutputStream byteStream)
  7. writeDocument(Document doc, OutputStream os)
  8. writeDocument(Document doc, OutputStream os)
  9. writeDocument(Document doc, Transformer transformer, OutputStream out)