#62006: normalize whitespace in XMLUtil.write, to guard against weird blocks of whitespace being shuffled around editor_api_20060102 graph1_base version-2-3-50 version-2-3-51
authorjglick@netbeans.org
Wed, 05 Oct 2005 00:53:06 +0000
changeset 69617368fcbdd3
parent 68 f692e5873720
child 70 a557a8b68a58
#62006: normalize whitespace in XMLUtil.write, to guard against weird blocks of whitespace being shuffled around
by AntProjectHelper's defensive cloning. Fix should correct the bug and even heal previously broken project.xml
files, if they are modified in some way.
openide.util/src/org/openide/xml/XMLUtil.java
openide.util/test/unit/src/org/openide/xml/XMLUtilTest.java
     1.1 --- a/openide.util/src/org/openide/xml/XMLUtil.java	Tue Oct 04 09:18:56 2005 +0000
     1.2 +++ b/openide.util/src/org/openide/xml/XMLUtil.java	Wed Oct 05 00:53:06 2005 +0000
     1.3 @@ -35,6 +35,10 @@
     1.4  import org.w3c.dom.DOMImplementation;
     1.5  import org.w3c.dom.Document;
     1.6  import org.w3c.dom.DocumentType;
     1.7 +import org.w3c.dom.Element;
     1.8 +import org.w3c.dom.Node;
     1.9 +import org.w3c.dom.NodeList;
    1.10 +import org.w3c.dom.Text;
    1.11  import org.xml.sax.EntityResolver;
    1.12  import org.xml.sax.ErrorHandler;
    1.13  import org.xml.sax.InputSource;
    1.14 @@ -357,11 +361,12 @@
    1.15          if (enc == null) {
    1.16              throw new NullPointerException("You must set an encoding; use \"UTF-8\" unless you have a good reason not to!"); // NOI18N
    1.17          }
    1.18 +        Document doc2 = normalize(doc);
    1.19          if (System.getProperty("java.specification.version").startsWith("1.4")) { // NOI18N
    1.20              // Hack for JDK 1.4. Using JAXP won't work; e.g. JDK bug #6308026.
    1.21              // Try using Xerces instead - let's hope it's loadable...
    1.22              try {
    1.23 -                writeXerces(doc, out, enc);
    1.24 +                writeXerces(doc2, out, enc);
    1.25                  return;
    1.26              } catch (ClassNotFoundException e) {
    1.27                  throw (IOException) new IOException("You need to have xerces.jar available to use XMLUtil.write under JDK 1.4: " + e).initCause(e); // NOI18N
    1.28 @@ -373,7 +378,7 @@
    1.29          try {
    1.30              Transformer t = TransformerFactory.newInstance().newTransformer(
    1.31                      new StreamSource(new StringReader(IDENTITY_XSLT_WITH_INDENT)));
    1.32 -            DocumentType dt = doc.getDoctype();
    1.33 +            DocumentType dt = doc2.getDoctype();
    1.34              if (dt != null) {
    1.35                  String pub = dt.getPublicId();
    1.36                  if (pub != null) {
    1.37 @@ -382,7 +387,7 @@
    1.38                  t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dt.getSystemId());
    1.39              }
    1.40              t.setOutputProperty(OutputKeys.ENCODING, enc);
    1.41 -            Source source = new DOMSource(doc);
    1.42 +            Source source = new DOMSource(doc2);
    1.43              Result result = new StreamResult(out);
    1.44              t.transform(source, result);
    1.45          } catch (Exception e) {
    1.46 @@ -695,4 +700,43 @@
    1.47  
    1.48          return SAXParserFactory.newInstance();
    1.49      }
    1.50 +
    1.51 +    /**
    1.52 +     * Try to normalize a document by removing nonsignificant whitespace.
    1.53 +     * @see "#62006"
    1.54 +     */
    1.55 +    private static Document normalize(Document orig) throws IOException {
    1.56 +        if (orig.getChildNodes().getLength() != 1) {
    1.57 +            // Don't mess around with it.
    1.58 +            return orig;
    1.59 +        }
    1.60 +        DocumentBuilder builder = (DocumentBuilder) builderTL[0].get();
    1.61 +        if (builder == null) {
    1.62 +            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    1.63 +            factory.setValidating(false);
    1.64 +            factory.setNamespaceAware(false);
    1.65 +            try {
    1.66 +                builder = factory.newDocumentBuilder();
    1.67 +            } catch (ParserConfigurationException e) {
    1.68 +                throw (IOException) new IOException("Cannot create parser satisfying configuration parameters: " + e).initCause(e); //NOI18N
    1.69 +            }
    1.70 +            builderTL[0].set(builder);
    1.71 +        }
    1.72 +        Document doc = builder.newDocument();
    1.73 +        doc.appendChild(doc.importNode(orig.getDocumentElement(), true));
    1.74 +        doc.normalize();
    1.75 +        NodeList nl = doc.getElementsByTagName("*"); // NOI18N
    1.76 +        for (int i = 0; i < nl.getLength(); i++) {
    1.77 +            Element e = (Element) nl.item(i);
    1.78 +            NodeList nl2 = e.getChildNodes();
    1.79 +            for (int j = 0; j < nl2.getLength(); j++) {
    1.80 +                Node n = nl2.item(j);
    1.81 +                if (n instanceof Text && ((Text) n).getNodeValue().trim().length() == 0) {
    1.82 +                    e.removeChild(n);
    1.83 +                    j--; // since list is dynamic
    1.84 +                }
    1.85 +            }
    1.86 +        }
    1.87 +        return doc;
    1.88 +    }
    1.89  }
     2.1 --- a/openide.util/test/unit/src/org/openide/xml/XMLUtilTest.java	Tue Oct 04 09:18:56 2005 +0000
     2.2 +++ b/openide.util/test/unit/src/org/openide/xml/XMLUtilTest.java	Wed Oct 05 00:53:06 2005 +0000
     2.3 @@ -18,6 +18,7 @@
     2.4  import java.io.CharConversionException;
     2.5  import java.io.IOException;
     2.6  import java.io.StringReader;
     2.7 +import javax.xml.parsers.DocumentBuilderFactory;
     2.8  import junit.framework.Test;
     2.9  import org.netbeans.junit.NbTestCase;
    2.10  import org.netbeans.junit.NbTestSuite;
    2.11 @@ -279,4 +280,41 @@
    2.12          assertTrue("had reasonable indentation in\n" + data, data.indexOf("<root>\n    <child/>\n</root>\n") != -1);
    2.13      }
    2.14      
    2.15 +    /** cf. #62006 */
    2.16 +    public void testIndentation2() throws Exception {
    2.17 +        String data =
    2.18 +                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
    2.19 +                "<p>\n" +
    2.20 +                "    <t/>\n" +
    2.21 +                "    <c>\n" +
    2.22 +                "        <d>\n" +
    2.23 +                "            <s/>\n" +
    2.24 +                "        </d>\n" +
    2.25 +                "    </c>\n" +
    2.26 +                "</p>\n";
    2.27 +        Document doc = XMLUtil.parse(new InputSource(new StringReader(data)), false, false, null, null);
    2.28 +        Element d = (Element) doc.getElementsByTagName("d").item(0);
    2.29 +        Element c = (Element) d.getParentNode();
    2.30 +        Element d2 = (Element) DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().importNode(d, true);
    2.31 +        c.removeChild(d);
    2.32 +        c.appendChild(doc.importNode(d2, true));
    2.33 +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    2.34 +        XMLUtil.write(doc, baos, "UTF-8");
    2.35 +        String data2 = baos.toString().replaceAll("\r\n", "\n");
    2.36 +        assertEquals("identity replacement should not mess up indentation", data, data2);
    2.37 +    }
    2.38 +    
    2.39 +    public void testSignificantWhitespace() throws Exception {
    2.40 +        String data =
    2.41 +                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
    2.42 +                "<r>\n" +
    2.43 +                "    <p>This is <em>not</em> a test!</p>\n" +
    2.44 +                "</r>\n";
    2.45 +        Document doc = XMLUtil.parse(new InputSource(new StringReader(data)), false, false, null, null);
    2.46 +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    2.47 +        XMLUtil.write(doc, baos, "UTF-8");
    2.48 +        String data2 = baos.toString().replaceAll("\r\n", "\n");
    2.49 +        assertEquals("identity replacement should not mess up significant whitespace", data, data2);
    2.50 +    }
    2.51 +    
    2.52  }