From 84f637fc994efcc0ed05833833a8e5c633b1c797 Mon Sep 17 00:00:00 2001 From: ronnyshapiro Date: Tue, 14 Jul 2026 16:57:45 +0300 Subject: [PATCH] asXml(): emit formatting line breaks only where the document contains whitespace Adjacent elements without whitespace in between no longer gain a fabricated line break, which rendered as a visible space between inline elements after a parse round-trip. Whitespace-only text nodes now mark where the formatting break belongs instead of being silently dropped, so the output follows the whitespace actually present in the document. --- src/changes/changes.xml | 4 ++ .../java/org/htmlunit/html/DomElement.java | 4 +- src/main/java/org/htmlunit/html/DomText.java | 3 ++ .../java/org/htmlunit/WebClient8Test.java | 48 +++++++++++++++---- .../java/org/htmlunit/html/HtmlFormTest.java | 9 +--- .../org/htmlunit/html/HtmlNoScript2Test.java | 8 +--- .../htmlunit/html/HtmlOrderedListTest.java | 8 +--- .../java/org/htmlunit/html/HtmlPageTest.java | 11 ++--- .../org/htmlunit/html/HtmlScriptTest.java | 11 +---- .../htmlunit/html/HtmlUnorderedList2Test.java | 8 +--- 10 files changed, 61 insertions(+), 53 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 6cd635e87f3..8215f79b217 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -8,6 +8,10 @@ + + asXml(): emit formatting line breaks only where the document contains whitespace; + adjacent elements no longer gain a fabricated line break that renders as a space. + Checkstyle rule set updated: JavadocStyle -> SummaryJavadoc. diff --git a/src/main/java/org/htmlunit/html/DomElement.java b/src/main/java/org/htmlunit/html/DomElement.java index cd1a6080c1c..c8e671e60bc 100644 --- a/src/main/java/org/htmlunit/html/DomElement.java +++ b/src/main/java/org/htmlunit/html/DomElement.java @@ -360,7 +360,7 @@ protected boolean printXml(final String indent, final boolean tagBefore, final P if (hasChildren) { printWriter.print(">"); - final boolean tag = printChildrenAsXml(indent, true, printWriter); + final boolean tag = printChildrenAsXml(indent, false, printWriter); if (tag) { printWriter.print("\r\n"); printWriter.print(indent); @@ -378,7 +378,7 @@ else if (isEmptyXmlTagExpanded()) { printWriter.print("/>"); } - return true; + return false; } /** diff --git a/src/main/java/org/htmlunit/html/DomText.java b/src/main/java/org/htmlunit/html/DomText.java index 2f27a884621..2dc140b2319 100644 --- a/src/main/java/org/htmlunit/html/DomText.java +++ b/src/main/java/org/htmlunit/html/DomText.java @@ -141,6 +141,9 @@ protected boolean printXml(final String indent, final boolean tagBefore, final P printWriter.print(data); tag = false; } + else if (data != null && !data.isEmpty()) { + tag = true; + } return printChildrenAsXml(indent, tag, printWriter); } diff --git a/src/test/java/org/htmlunit/WebClient8Test.java b/src/test/java/org/htmlunit/WebClient8Test.java index 195cd6b2586..3b4f0ecb950 100644 --- a/src/test/java/org/htmlunit/WebClient8Test.java +++ b/src/test/java/org/htmlunit/WebClient8Test.java @@ -59,15 +59,45 @@ public void asXml() throws Exception { try (WebClient webClient = new WebClient(getBrowserVersion(), false, null, -1)) { final HtmlPage page = loadPage(webClient, html, null, URL_FIRST); - assertEquals("\r\n\r\n" - + " \r\n" - + " foo\r\n" - + " \r\n" - + " \r\n" - + "
Hello HtmlUnit\r\n" - + "
\r\n" - + " \r\n" - + "", + assertEquals("\r\n" + + "foo" + + "
Hello HtmlUnit
", + page.asXml()); + } + } + + /** + * @throws Exception if something goes wrong + */ + @Test + public void asXmlNoWhitespaceBetweenAdjacentElements() throws Exception { + final String html = DOCTYPE_HTML + + "foo" + + "
ab
"; + + try (WebClient webClient = new WebClient(getBrowserVersion(), false, null, -1)) { + final HtmlPage page = loadPage(webClient, html, null, URL_FIRST); + assertEquals("\r\n" + + "foo" + + "
ab
", + page.asXml()); + } + } + + /** + * @throws Exception if something goes wrong + */ + @Test + public void asXmlWhitespaceOnlyTextBetweenElements() throws Exception { + final String html = DOCTYPE_HTML + + "foo" + + "
a b
"; + + try (WebClient webClient = new WebClient(getBrowserVersion(), false, null, -1)) { + final HtmlPage page = loadPage(webClient, html, null, URL_FIRST); + assertEquals("\r\n" + + "foo" + + "
a\r\n b
", page.asXml()); } } diff --git a/src/test/java/org/htmlunit/html/HtmlFormTest.java b/src/test/java/org/htmlunit/html/HtmlFormTest.java index 93d27f15aa3..8ac393446e1 100644 --- a/src/test/java/org/htmlunit/html/HtmlFormTest.java +++ b/src/test/java/org/htmlunit/html/HtmlFormTest.java @@ -1199,13 +1199,8 @@ public void asXml_emptyTag() throws Exception { final String xml = "\r\n" - + "\r\n" - + " \r\n" - + " \r\n" - + "
\r\n" - + "
test
\r\n" - + " \r\n" - + ""; + + "\r\n
\r\n
test
\r\n" + + " "; final HtmlPage page = loadPage(html); assertEquals(xml, page.asXml()); diff --git a/src/test/java/org/htmlunit/html/HtmlNoScript2Test.java b/src/test/java/org/htmlunit/html/HtmlNoScript2Test.java index 0645c5d75b6..5a541914400 100644 --- a/src/test/java/org/htmlunit/html/HtmlNoScript2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlNoScript2Test.java @@ -34,8 +34,7 @@ public class HtmlNoScript2Test extends SimpleWebTestCase { */ @Test @Alerts("\r\n" - + " \r\n" - + "") + + " ") public void asXml_jsEnabled() throws Exception { final String html = DOCTYPE_HTML + "\n" @@ -57,10 +56,7 @@ public void asXml_jsDisabled() throws Exception { + ""; final String expected = "\r\n" - + " \r\n" - + ""; + + " "; final WebClient client = getWebClient(); client.getOptions().setJavaScriptEnabled(false); diff --git a/src/test/java/org/htmlunit/html/HtmlOrderedListTest.java b/src/test/java/org/htmlunit/html/HtmlOrderedListTest.java index e840b46f1b7..994daacb8df 100644 --- a/src/test/java/org/htmlunit/html/HtmlOrderedListTest.java +++ b/src/test/java/org/htmlunit/html/HtmlOrderedListTest.java @@ -70,12 +70,8 @@ public void asXml() throws Exception { // assertEquals("
    ", element.asXml()); assertEquals("\r\n" - + "\r\n" - + " \r\n" - + " \r\n" - + "
      \n" + + "\r\n
        \n" + "foo\n" - + "\r\n" - + "", page.asXml()); + + "", page.asXml()); } } diff --git a/src/test/java/org/htmlunit/html/HtmlPageTest.java b/src/test/java/org/htmlunit/html/HtmlPageTest.java index 9835fa088b2..b874be1bb34 100644 --- a/src/test/java/org/htmlunit/html/HtmlPageTest.java +++ b/src/test/java/org/htmlunit/html/HtmlPageTest.java @@ -1042,14 +1042,9 @@ public void asXml_noscript() throws Exception { + ""; final String expected = "\r\n" - + "\r\n" - + " \r\n" - + " \r\n" - + " \r\n" - + " \r\n" - + ""; + + ""; final HtmlPage page = loadPage(html); assertEquals(expected, page.asXml()); diff --git a/src/test/java/org/htmlunit/html/HtmlScriptTest.java b/src/test/java/org/htmlunit/html/HtmlScriptTest.java index 9e48f23dfe4..dac58b871ee 100644 --- a/src/test/java/org/htmlunit/html/HtmlScriptTest.java +++ b/src/test/java/org/htmlunit/html/HtmlScriptTest.java @@ -110,20 +110,13 @@ public void asXml() throws Exception { // asXml() should be reusable final String xml = page.asXml(); assertEquals("\r\n" - + "\r\n" - + " \r\n" - + " foo\r\n" - + " \r\n" - + " \r\n" - + " \r\n" - + " \r\n" - + "", + + " ", xml); loadPageWithAlerts(xml); diff --git a/src/test/java/org/htmlunit/html/HtmlUnorderedList2Test.java b/src/test/java/org/htmlunit/html/HtmlUnorderedList2Test.java index a9743b414b1..d53d7cd115c 100644 --- a/src/test/java/org/htmlunit/html/HtmlUnorderedList2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlUnorderedList2Test.java @@ -68,12 +68,8 @@ public void asXml() throws Exception { assertEquals("", element.asXml()); assertEquals("\r\n" - + "\r\n" - + " \r\n" - + " \r\n" - + " \n" + + "\r\n \n" + "foo\n" - + "\r\n" - + "", page.asXml()); + + "", page.asXml()); } }