Refactoring XMLUtil.write to deal with *part of* #61938 (not enough to make the IDE work under Mustang b46
however): try to use JAXP for serialization whenever possible, i.e. on JDK 1.5+.
1.1 --- a/openide.util/nbproject/project.properties Mon Aug 01 21:07:38 2005 +0000
1.2 +++ b/openide.util/nbproject/project.properties Tue Aug 09 03:11:41 2005 +0000
1.3 @@ -6,14 +6,17 @@
1.4 # http://www.sun.com/
1.5 #
1.6 # The Original Code is NetBeans. The Initial Developer of the Original
1.7 -# Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
1.8 +# Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
1.9 # Microsystems, Inc. All Rights Reserved.
1.10
1.11 module.jar.dir=lib
1.12 +
1.13 +# For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4:
1.14 +test.unit.run.cp.extra=\
1.15 + ${libs/xerces.dir}/modules/ext/xerces-2.6.2.jar:\
1.16 + ${libs/xerces.dir}/modules/ext/xml-commons-dom-ranges-1.0.b2.jar
1.17 +
1.18 javadoc.title=Utilities API
1.19 javadoc.main.page=org/openide/util/doc-files/api.html
1.20 javadoc.arch=${basedir}/arch.xml
1.21 javadoc.apichanges=${basedir}/apichanges.xml
1.22 -#javadoc.check.failonerror=true
1.23 -
1.24 -
2.1 --- a/openide.util/src/org/openide/xml/XMLUtil.java Mon Aug 01 21:07:38 2005 +0000
2.2 +++ b/openide.util/src/org/openide/xml/XMLUtil.java Tue Aug 09 03:11:41 2005 +0000
2.3 @@ -7,19 +7,39 @@
2.4 * http://www.sun.com/
2.5 *
2.6 * The Original Code is NetBeans. The Initial Developer of the Original
2.7 - * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
2.8 + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
2.9 * Microsystems, Inc. All Rights Reserved.
2.10 */
2.11 +
2.12 package org.openide.xml;
2.13
2.14 +import java.io.CharConversionException;
2.15 +import java.io.IOException;
2.16 +import java.io.OutputStream;
2.17 +import java.io.StringReader;
2.18 +import java.lang.reflect.Method;
2.19 +import javax.xml.parsers.DocumentBuilder;
2.20 +import javax.xml.parsers.DocumentBuilderFactory;
2.21 +import javax.xml.parsers.ParserConfigurationException;
2.22 +import javax.xml.parsers.SAXParserFactory;
2.23 +import javax.xml.transform.OutputKeys;
2.24 +import javax.xml.transform.Result;
2.25 +import javax.xml.transform.Source;
2.26 +import javax.xml.transform.Transformer;
2.27 +import javax.xml.transform.TransformerFactory;
2.28 +import javax.xml.transform.dom.DOMSource;
2.29 +import javax.xml.transform.stream.StreamResult;
2.30 +import javax.xml.transform.stream.StreamSource;
2.31 import org.openide.ErrorManager;
2.32 -import org.w3c.dom.*;
2.33 -import org.xml.sax.*;
2.34 -
2.35 -import java.io.*;
2.36 -
2.37 -import javax.xml.parsers.*;
2.38 -
2.39 +import org.w3c.dom.DOMException;
2.40 +import org.w3c.dom.DOMImplementation;
2.41 +import org.w3c.dom.Document;
2.42 +import org.w3c.dom.DocumentType;
2.43 +import org.xml.sax.EntityResolver;
2.44 +import org.xml.sax.ErrorHandler;
2.45 +import org.xml.sax.InputSource;
2.46 +import org.xml.sax.SAXException;
2.47 +import org.xml.sax.XMLReader;
2.48
2.49 /**
2.50 * Utility class collecting library methods related to XML processing.
2.51 @@ -304,19 +324,101 @@
2.52 }
2.53
2.54 /**
2.55 - * Write Document into OutputStream using given encoding.
2.56 - * It is a shortcut for writing configurations etc. It guarantees
2.57 - * just that data will be written. Structure and indentation may change.
2.58 - *
2.59 - * @param doc DOM Document to be written
2.60 + * Identity transformation in XSLT with indentation added.
2.61 + * Just using the identity transform and calling
2.62 + * t.setOutputProperty(OutputKeys.INDENT, "yes");
2.63 + * t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
2.64 + * does not work currently.
2.65 + * You really have to use this bogus stylesheet.
2.66 + * @see "JDK bug #5064280"
2.67 + */
2.68 + private static final String IDENTITY_XSLT_WITH_INDENT =
2.69 + "<xsl:stylesheet version='1.0' " + // NOI18N
2.70 + "xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " + // NOI18N
2.71 + "xmlns:xalan='http://xml.apache.org/xslt' " + // NOI18N
2.72 + "exclude-result-prefixes='xalan'>" + // NOI18N
2.73 + "<xsl:output method='xml' indent='yes' xalan:indent-amount='4'/>" + // NOI18N
2.74 + "<xsl:template match='@*|node()'>" + // NOI18N
2.75 + "<xsl:copy>" + // NOI18N
2.76 + "<xsl:apply-templates select='@*|node()'/>" + // NOI18N
2.77 + "</xsl:copy>" + // NOI18N
2.78 + "</xsl:template>" + // NOI18N
2.79 + "</xsl:stylesheet>"; // NOI18N
2.80 + /**
2.81 + * Writes a DOM document to a stream.
2.82 + * The precise output format is not guaranteed but this method will attempt to indent it sensibly.
2.83 + *
2.84 + * @param doc DOM document to be written
2.85 * @param out data sink
2.86 - * @param enc XML defined encoding name (i.e. IANA defined, one of UTF-8, UNICODE, ASCII)
2.87 - *
2.88 - * @throws IOException if an I/O exception occurs
2.89 + * @param enc XML-defined encoding name (e.g. "UTF-8")
2.90 + * @throws IOException if JAXP fails or the stream cannot be written to
2.91 */
2.92 - public static void write(Document doc, OutputStream out, String enc)
2.93 - throws IOException {
2.94 - XMLUtilImpl.write(doc, out, enc);
2.95 + public static void write(Document doc, OutputStream out, String enc) throws IOException {
2.96 + if (enc == null) {
2.97 + throw new NullPointerException("You must set an encoding; use \"UTF-8\" unless you have a good reason not to!"); // NOI18N
2.98 + }
2.99 + if (System.getProperty("java.specification.version").startsWith("1.4")) { // NOI18N
2.100 + // Hack for JDK 1.4. Using JAXP won't work; e.g. JDK bug #6308026.
2.101 + // Try using Xerces instead - let's hope it's loadable...
2.102 + try {
2.103 + writeXerces(doc, out, enc);
2.104 + return;
2.105 + } catch (ClassNotFoundException e) {
2.106 + throw (IOException) new IOException("You need to have xerces.jar available to use XMLUtil.write under JDK 1.4: " + e).initCause(e); // NOI18N
2.107 + } catch (Exception e) {
2.108 + throw (IOException) new IOException(e.toString()).initCause(e);
2.109 + }
2.110 + }
2.111 + try {
2.112 + Transformer t = TransformerFactory.newInstance().newTransformer(
2.113 + new StreamSource(new StringReader(IDENTITY_XSLT_WITH_INDENT)));
2.114 + DocumentType dt = doc.getDoctype();
2.115 + if (dt != null) {
2.116 + String pub = dt.getPublicId();
2.117 + if (pub != null) {
2.118 + t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, pub);
2.119 + }
2.120 + t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dt.getSystemId());
2.121 + }
2.122 + t.setOutputProperty(OutputKeys.ENCODING, enc);
2.123 + Source source = new DOMSource(doc);
2.124 + Result result = new StreamResult(out);
2.125 + t.transform(source, result);
2.126 + } catch (Exception e) {
2.127 + throw (IOException) new IOException(e.toString()).initCause(e);
2.128 + }
2.129 + }
2.130 + /**
2.131 + * Serialize a document using Xerces' library.
2.132 + * This library is available in the JDK starting with version 1.5 (where we do not need it anyway),
2.133 + * but in 1.4 you need to have Xerces loaded in the system somewhere.
2.134 + */
2.135 + private static void writeXerces(Document doc, OutputStream out, String encoding) throws ClassNotFoundException, Exception {
2.136 + ClassLoader cl = Thread.currentThread().getContextClassLoader();
2.137 + Class xmlSerializerClazz = Class.forName("org.apache.xml.serialize.XMLSerializer", true, cl); // NOI18N
2.138 + Class outputFormatClazz = Class.forName("org.apache.xml.serialize.OutputFormat", true, cl); // NOI18N
2.139 + Object xmlSerializer = xmlSerializerClazz.newInstance();
2.140 + Object outputFormat = outputFormatClazz.newInstance();
2.141 + Method setMethod = outputFormatClazz.getMethod("setMethod", new Class[] {String.class}); // NOI18N
2.142 + setMethod.invoke(outputFormat, new Object[] {"xml"}); // NOI18N
2.143 + Method setIndenting = outputFormatClazz.getMethod("setIndenting", new Class[] {Boolean.TYPE}); // NOI18N
2.144 + setIndenting.invoke(outputFormat, new Object[] {Boolean.TRUE}); // NOI18N
2.145 + Method setLineWidth = outputFormatClazz.getMethod("setLineWidth", new Class[] {Integer.TYPE}); // NOI18N
2.146 + setLineWidth.invoke(outputFormat, new Object[] {new Integer(0)});
2.147 + Method setLineSeparator = outputFormatClazz.getMethod("setLineSeparator", new Class[] {String.class}); // NOI18N
2.148 + setLineSeparator.invoke(outputFormat, new String[] {System.getProperty("line.separator")}); // NOI18N
2.149 + Method setOutputByteStream = xmlSerializerClazz.getMethod("setOutputByteStream", new Class[] {OutputStream.class}); // NOI18N
2.150 + setOutputByteStream.invoke(xmlSerializer, new Object[] {out});
2.151 + Method setEncoding = outputFormatClazz.getMethod("setEncoding", new Class[] {String.class}); // NOI18N
2.152 + setEncoding.invoke(outputFormat, new Object[] {encoding});
2.153 + Method setOutputFormat = xmlSerializerClazz.getMethod("setOutputFormat", new Class[] {outputFormatClazz}); // NOI18N
2.154 + setOutputFormat.invoke(xmlSerializer, new Object[] {outputFormat});
2.155 + Method setNamespaces = xmlSerializerClazz.getMethod("setNamespaces", new Class[] {Boolean.TYPE}); // NOI18N
2.156 + setNamespaces.invoke(xmlSerializer, new Object[] {Boolean.TRUE});
2.157 + Method asDOMSerializer = xmlSerializerClazz.getMethod("asDOMSerializer", new Class[0]); // NOI18N
2.158 + Object impl = asDOMSerializer.invoke(xmlSerializer, null);
2.159 + Method serialize = impl.getClass().getMethod("serialize", new Class[] {Document.class}); // NOI18N
2.160 + serialize.invoke(impl, new Object[] {doc});
2.161 }
2.162
2.163 /**
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/openide.util/test/unit/src/org/openide/xml/XMLUtilTest.java Tue Aug 09 03:11:41 2005 +0000
3.3 @@ -0,0 +1,282 @@
3.4 +/*
3.5 + * Sun Public License Notice
3.6 + *
3.7 + * The contents of this file are subject to the Sun Public License
3.8 + * Version 1.0 (the "License"). You may not use this file except in
3.9 + * compliance with the License. A copy of the License is available at
3.10 + * http://www.sun.com/
3.11 + *
3.12 + * The Original Code is NetBeans. The Initial Developer of the Original
3.13 + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
3.14 + * Microsystems, Inc. All Rights Reserved.
3.15 + */
3.16 +
3.17 +package org.openide.xml;
3.18 +
3.19 +import java.io.ByteArrayInputStream;
3.20 +import java.io.ByteArrayOutputStream;
3.21 +import java.io.CharConversionException;
3.22 +import java.io.IOException;
3.23 +import java.io.StringReader;
3.24 +import junit.framework.Test;
3.25 +import org.netbeans.junit.NbTestCase;
3.26 +import org.netbeans.junit.NbTestSuite;
3.27 +import org.w3c.dom.Document;
3.28 +import org.w3c.dom.DocumentType;
3.29 +import org.w3c.dom.Element;
3.30 +import org.w3c.dom.NodeList;
3.31 +import org.xml.sax.EntityResolver;
3.32 +import org.xml.sax.ErrorHandler;
3.33 +import org.xml.sax.InputSource;
3.34 +import org.xml.sax.SAXException;
3.35 +import org.xml.sax.SAXParseException;
3.36 +import org.xml.sax.XMLReader;
3.37 +
3.38 +public class XMLUtilTest extends NbTestCase {
3.39 +
3.40 + public XMLUtilTest(String testName) {
3.41 + super(testName);
3.42 + }
3.43 +
3.44 + public void testCreateXMLReader() {
3.45 +
3.46 + XMLReader parser = null;
3.47 +
3.48 + try {
3.49 + parser = XMLUtil.createXMLReader();
3.50 + } catch (Exception ex) {
3.51 + ex.printStackTrace();
3.52 + }
3.53 +
3.54 + // Add your test code below by replacing the default call to fail.
3.55 + if (parser == null) fail("Cannot create XML reader");
3.56 + }
3.57 +
3.58 + public void testCreateDocument() {
3.59 +
3.60 + Document doc = null;
3.61 + try {
3.62 + doc = XMLUtil.createDocument("root", null, null, null);
3.63 + } catch (Exception ex) {
3.64 + ex.printStackTrace();
3.65 + }
3.66 +
3.67 + // Add your test code below by replacing the default call to fail.
3.68 + if (doc == null) fail("The test case is empty.");
3.69 + }
3.70 +
3.71 + public void testWrite() throws Exception {
3.72 + String data = "<foo bar=\"val\"><baz/></foo>";
3.73 + Document doc = XMLUtil.parse(new InputSource(new StringReader(data)), false, true, null, null);
3.74 + //System.err.println("XMLUtil.parse impl class: " + doc.getClass().getName());
3.75 + Element el = doc.getDocumentElement();
3.76 + assertEquals("foo", el.getNodeName());
3.77 + assertEquals("val", el.getAttribute("bar"));
3.78 + NodeList l = el.getElementsByTagName("*");
3.79 + assertEquals(1, l.getLength());
3.80 + Element el2 = (Element)l.item(0);
3.81 + assertEquals("baz", el2.getLocalName());
3.82 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
3.83 + XMLUtil.write(doc, baos, "UTF-8");
3.84 + String data2 = baos.toString("UTF-8");
3.85 + //System.err.println("testWrite: data2:\n" + data2);
3.86 + assertTrue(data2, data2.indexOf("foo") != -1);
3.87 + assertTrue(data2, data2.indexOf("bar") != -1);
3.88 + assertTrue(data2, data2.indexOf("baz") != -1);
3.89 + assertTrue(data2, data2.indexOf("val") != -1);
3.90 + }
3.91 +
3.92 + /** Test that read/write DOCTYPE works too. */
3.93 + public void testDocType() throws Exception {
3.94 + String data = "<!DOCTYPE foo PUBLIC \"The foo DTD\" \"http://nowhere.net/foo.dtd\"><foo><x/><x/></foo>";
3.95 + Document doc = XMLUtil.parse(new InputSource(new StringReader(data)), true, true, new Handler(), new Resolver());
3.96 + DocumentType t = doc.getDoctype();
3.97 + assertNotNull(t);
3.98 + assertEquals("foo", t.getName());
3.99 + assertEquals("The foo DTD", t.getPublicId());
3.100 + assertEquals("http://nowhere.net/foo.dtd", t.getSystemId());
3.101 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
3.102 + XMLUtil.write(doc, baos, "UTF-8");
3.103 + String data2 = baos.toString("UTF-8");
3.104 + //System.err.println("data2:\n" + data2);
3.105 + assertTrue(data2, data2.indexOf("foo") != -1);
3.106 + assertTrue(data2, data2.indexOf("x") != -1);
3.107 + assertTrue(data2, data2.indexOf("DOCTYPE") != -1);
3.108 + assertTrue(data2, data2.indexOf("The foo DTD") != -1);
3.109 + assertTrue(data2, data2.indexOf("http://nowhere.net/foo.dtd") != -1);
3.110 + }
3.111 + private static final class Handler implements ErrorHandler {
3.112 + public void error(SAXParseException exception) throws SAXException {
3.113 + throw exception;
3.114 + }
3.115 + public void fatalError(SAXParseException exception) throws SAXException {
3.116 + throw exception;
3.117 + }
3.118 + public void warning(SAXParseException exception) throws SAXException {
3.119 + throw exception;
3.120 + }
3.121 + }
3.122 + private static final class Resolver implements EntityResolver {
3.123 + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
3.124 + assertEquals("The foo DTD", publicId);
3.125 + assertEquals("http://nowhere.net/foo.dtd", systemId);
3.126 + String data = "<!ELEMENT foo (x+)><!ELEMENT x EMPTY>";
3.127 + return new InputSource(new StringReader(data));
3.128 + }
3.129 + }
3.130 +
3.131 + public void testToAttributeValue() throws IOException {
3.132 + String result = null;
3.133 + try {
3.134 + result = XMLUtil.toAttributeValue("\t\r\n &'<\"");
3.135 + } catch (CharConversionException ex) {
3.136 + }
3.137 +
3.138 + assertEquals("Basic escape test failed", "\t\r\n &'<"", result);
3.139 +
3.140 + try {
3.141 + XMLUtil.toAttributeValue(new String(new byte[] { 0 }));
3.142 + fail("Forbidden character accepted.");
3.143 + } catch (CharConversionException ex) {
3.144 + }
3.145 +
3.146 + try {
3.147 + XMLUtil.toAttributeValue(new String(new byte[] { 31 }));
3.148 + fail("Forbidden character accepted.");
3.149 + } catch (CharConversionException ex) {
3.150 + }
3.151 + }
3.152 +
3.153 + public void testElementToContent() {
3.154 + String result = null;
3.155 +
3.156 + try {
3.157 + result = XMLUtil.toElementContent("]]>\t\r\n &<>");
3.158 + } catch (CharConversionException ex) {
3.159 + }
3.160 +
3.161 + assertEquals("Basic escape test failed", "]]>\t\r\n &<>", result);
3.162 +
3.163 + try {
3.164 + XMLUtil.toElementContent(new String(new byte[] { 0 }));
3.165 + fail("Forbidden character accepted.");
3.166 + } catch (CharConversionException ex) {
3.167 + }
3.168 +
3.169 + try {
3.170 + XMLUtil.toElementContent(new String(new byte[] { 31 }));
3.171 + fail("Forbidden character accepted.");
3.172 + } catch (CharConversionException ex) {
3.173 + }
3.174 +
3.175 + }
3.176 +
3.177 + public void testToHex() {
3.178 +
3.179 + byte[] data = new byte[] {0, 1, 15, 16, (byte)255};
3.180 + String s = XMLUtil.toHex(data, 0, data.length);
3.181 +
3.182 + // Add your test code below by replacing the default call to fail.
3.183 + if (s.equalsIgnoreCase("00010f10ff") == false) {
3.184 + fail("toHex() =" + s);
3.185 + }
3.186 + }
3.187 +
3.188 + public void testFromHex() {
3.189 +
3.190 + char[] hex = "00010f10ff".toCharArray();
3.191 + try {
3.192 + byte[] ret = XMLUtil.fromHex(hex, 0, hex.length);
3.193 + if (ret[0] != 0 || ret[1] != 1 || ret[2] != 15 || ret[3] != 16 || ret[4] != (byte)255) {
3.194 + fail("fromHex()");
3.195 + }
3.196 + } catch (IOException ex) {
3.197 + fail(ex.getMessage());
3.198 + }
3.199 +
3.200 + }
3.201 +
3.202 + /**
3.203 + * Check that reading and writing namespaces works.
3.204 + * @see "#36294"
3.205 + */
3.206 + public void testNamespaces() throws Exception {
3.207 + String data = "<foo xmlns='bar'><baz/></foo>";
3.208 + Document doc = XMLUtil.parse(new InputSource(new StringReader(data)), false, true, null, null);
3.209 + //System.err.println("XMLUtil.parse impl class: " + doc.getClass().getName());
3.210 + Element el = doc.getDocumentElement();
3.211 + assertEquals("foo", el.getNodeName());
3.212 + assertEquals("foo", el.getTagName());
3.213 + assertEquals("foo", el.getLocalName());
3.214 + assertEquals("bar", el.getNamespaceURI());
3.215 + NodeList l = el.getElementsByTagName("*");
3.216 + assertEquals(1, l.getLength());
3.217 + Element el2 = (Element)l.item(0);
3.218 + assertEquals("baz", el2.getLocalName());
3.219 + assertEquals("bar", el2.getNamespaceURI());
3.220 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
3.221 + XMLUtil.write(doc, baos, "UTF-8");
3.222 + String data2 = baos.toString("UTF-8");
3.223 + //System.err.println("testNamespaces: data2:\n" + data2);
3.224 + assertTrue(data2, data2.indexOf("foo") != -1);
3.225 + assertTrue(data2, data2.indexOf("bar") != -1);
3.226 + doc = XMLUtil.parse(new InputSource(new ByteArrayInputStream(baos.toByteArray())), false, true, null, null);
3.227 + el = doc.getDocumentElement();
3.228 + assertEquals("foo", el.getLocalName());
3.229 + assertEquals("bar", el.getNamespaceURI());
3.230 + l = el.getElementsByTagName("*");
3.231 + assertEquals(1, l.getLength());
3.232 + el2 = (Element)l.item(0);
3.233 + assertEquals("baz", el2.getLocalName());
3.234 + assertEquals("bar", el2.getNamespaceURI());
3.235 + doc = XMLUtil.createDocument("foo2", "bar2", null, null);
3.236 + //System.err.println("XMLUtil.createDocument impl class: " + doc.getClass().getName());
3.237 + doc.getDocumentElement().appendChild(doc.createElementNS("bar2", "baz2"));
3.238 + baos = new ByteArrayOutputStream();
3.239 + XMLUtil.write(doc, baos, "UTF-8");
3.240 + data2 = baos.toString("UTF-8");
3.241 + assertTrue(data2, data2.indexOf("foo2") != -1);
3.242 + assertTrue("namespace 'bar2' of root element mentioned in output: " + data2, data2.indexOf("bar2") != -1);
3.243 + doc = XMLUtil.parse(new InputSource(new ByteArrayInputStream(baos.toByteArray())), false, true, null, null);
3.244 + el = doc.getDocumentElement();
3.245 + assertEquals("foo2", el.getLocalName());
3.246 + assertEquals("bar2", el.getNamespaceURI());
3.247 + l = el.getElementsByTagName("*");
3.248 + assertEquals(1, l.getLength());
3.249 + el2 = (Element)l.item(0);
3.250 + assertEquals("baz2", el2.getLocalName());
3.251 + assertEquals("bar2", el2.getNamespaceURI());
3.252 + }
3.253 +
3.254 + /**
3.255 + * Check more namespace stuff, since JAXP has a lot of bugs...
3.256 + * @see "#6308026"
3.257 + */
3.258 + public void testNamespaces2() throws Exception {
3.259 + String data = "<root xmlns='root'/>";
3.260 + Document doc = XMLUtil.parse(new InputSource(new StringReader(data)), false, true, null, null);
3.261 + doc.getDocumentElement().appendChild(doc.createElementNS("child", "child"));
3.262 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
3.263 + XMLUtil.write(doc, baos, "UTF-8");
3.264 + //System.err.println("testNamespaces2:\n" + baos);
3.265 + doc = XMLUtil.parse(new InputSource(new ByteArrayInputStream(baos.toByteArray())), false, true, null, null);
3.266 + Element el = doc.getDocumentElement();
3.267 + assertEquals("root", el.getLocalName());
3.268 + assertEquals("root", el.getNamespaceURI());
3.269 + NodeList l = el.getElementsByTagName("*");
3.270 + assertEquals(1, l.getLength());
3.271 + el = (Element) l.item(0);
3.272 + assertEquals("child", el.getLocalName());
3.273 + assertEquals("child", el.getNamespaceURI());
3.274 + }
3.275 +
3.276 + public void testIndentation() throws Exception {
3.277 + Document doc = XMLUtil.createDocument("root", null, null, null);
3.278 + doc.getDocumentElement().appendChild(doc.createElement("child"));
3.279 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
3.280 + XMLUtil.write(doc, baos, "UTF-8");
3.281 + String data = baos.toString();
3.282 + assertTrue("had reasonable indentation in\n" + data, data.indexOf("<root>\n <child/>\n</root>\n") != -1);
3.283 + }
3.284 +
3.285 +}