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><![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 (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
- documentToStream(Document document, OutputStream outputStream, String encoding)
- dom2InputStream(Document doc)
- dumpDoc(Document domTree, PrintStream out)
- dumpToStream(Document doc, OutputStream out)
- toXml(Document doc, OutputStream out)
- write(Document document, OutputStream byteStream)
- writeDocument(Document doc, OutputStream os)
- writeDocument(Document doc, OutputStream os)
- writeDocument(Document doc, Transformer transformer, OutputStream out)