/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package common;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
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.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/*
* @test
* @bug 6439439 8087303
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
* @run testng/othervm -DrunSecMngr=true common.PrettyPrintTest
* @run testng/othervm common.PrettyPrintTest
* @summary Test serializing xml and html with indentation.
*/
@Listeners({jaxp.library.BasePolicy.class})
public class PrettyPrintTest {
/*
* test pure text content, CDATA, elements only, text and element,
* whitespace and element, xml:space property and nested xml:space property,
* mixed node types, sequent Text nodes.
*/
@DataProvider(name = "xml-data")
public Object[][] xmlData() throws Exception {
return new Object[][] {
{ newTextNode(" abc def \nline2 &a \n test"),
" abc def \n" +
"line2 &a \n" +
" test" },
{ toXmlDocument(""),
"\n" +
" \n" +
"\n" },
{ toXmlDocument(""),
"\n" +
" \n" +
"\n" },
{ toXmlDocument(""),
"\n" +
" \n" +
" \n" +
" \n" +
"\n" },
{ toXmlDocument("child1"
+ " abc test"),
"\n" +
" \n" +
" child1\n" +
" abc test\n" +
" \n" +
"\n" },
{ toXmlDocument(" Java Tutorials and Examples 1 "
+ "en-us \n \n"),
"\n" +
" \n" +
" Java Tutorials and Examples 1\n" +
" en-us\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
"\n" },
{ toXmlDocument(" "
+ "Java Tutorials and Examples 1 en-us"),
"\n" +
" Java Tutorials and Examples 1 en-us\n" +
"\n" },
{ toXmlDocument(" Java "
+ " "
+ " 5 \n "
+ " "
+ " "
+ " "
+ " "
+ " "),
"\n" +
" Java \n" +
" 5\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
"\n" },
{ toXmlDocument(MIXED_NODE_TYPES_XML),
"\n" +
" \n" +
" t\n" +
" \n" +
" \n" +
"t \n" +
" \n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
"\n" },
{ createDocWithSequentTextNodes(),
"\n" +
" t\n" +
"t \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" t\n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" \n" +
" \n" +
"\n" } };
}
/*
* @bug 8087303
* Test the whitespace text nodes are serialized with pretty-print by LSSerializer and transformer correctly
*
*/
@Test(dataProvider = "xml-data")
public void testXMLPrettyPrint(Node xml, String expected) throws Exception {
assertEquals(serializerWrite(xml), expected);
assertEquals(transform(xml).replaceAll("\r\n", "\n"), expected);
}
/*
* test block element, inline element, text, and mixed elements.
*/
@DataProvider(name = "html-data")
public Object[][] htmlData() throws Exception {
return new Object[][] {
{ "Java Tutorials and Examples 1" +
" en-us",
"\n" +
" \n" +
" Java Tutorials and Examples 1\n" +
" en-us\n" +
" \n" +
"\n" },
{ "Java
TM",
"\n" +
" Java
TM\n" +
"\n" },
{ "
this is a test page
",
"\n" +
" this is a test page\n" +
"
\n" },
{ "A heading
new paragraph
" +
"test",
"\n" +
" \n" +
" A heading
\n" +
" \n" +
" new paragraph\n" +
"
\n" +
" test\n" +
" \n" +
" \n" +
"\n" },
{ "this is a mixed test clickto the test" +
"
pagelink end
",
"\n" +
" \n" +
" this is a mixed test click\n" +
" to the test
\n" +
" pagelink end\n" +
"
\n" +
"\n" },
{ "text
another",
"\n" +
" text\n" +
"
\n" +
" another\n" +
" \n" +
"\n" },
{ MIXED_NODE_TYPES_XML,
"\n" +
" \n" +
" t\n" +
" \n" +
" \n" +
"t \n" +
" \n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
"\n" } };
}
/*
* @bug 8087303
* Transform to HTML, test Pretty Print for HTML.
*
*/
@Test(dataProvider = "html-data")
public void testTransformToHTML(String source, String expected) throws Exception {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "html");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new StreamSource(new StringReader(source)), new StreamResult(writer));
assertEquals(writer.toString().replaceAll("\r\n", "\n"), expected);
}
@Test
public void testLSSerializerFormatPrettyPrint() {
final String XML_DOCUMENT = "\n"
+ "before child elementafter child element";
/**JDK-8035467
* no newline in default output
*/
final String XML_DOCUMENT_DEFAULT_PRINT =
""
+ ""
+ "before child element"
+ ""
+ "after child element";
final String XML_DOCUMENT_PRETTY_PRINT = "\n" +
" before child element\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" after child element\n" +
"\n";
// it all begins with a Document
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException parserConfigurationException) {
parserConfigurationException.printStackTrace();
Assert.fail(parserConfigurationException.toString());
}
Document document = null;
StringReader stringReader = new StringReader(XML_DOCUMENT);
InputSource inputSource = new InputSource(stringReader);
try {
document = documentBuilder.parse(inputSource);
} catch (SAXException saxException) {
saxException.printStackTrace();
Assert.fail(saxException.toString());
} catch (IOException ioException) {
ioException.printStackTrace();
Assert.fail(ioException.toString());
}
// query DOM Interfaces to get to a LSSerializer
DOMImplementation domImplementation = documentBuilder.getDOMImplementation();
DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation;
LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
System.out.println("Serializer is: " + lsSerializer.getClass().getName() + " " + lsSerializer);
// get configuration
DOMConfiguration domConfiguration = lsSerializer.getDomConfig();
// query current configuration
Boolean defaultFormatPrettyPrint = (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT);
Boolean canSetFormatPrettyPrintFalse = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
Boolean canSetFormatPrettyPrintTrue = (Boolean) domConfiguration.canSetParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
System.out.println(DOM_FORMAT_PRETTY_PRINT + " default/can set false/can set true = " + defaultFormatPrettyPrint + "/"
+ canSetFormatPrettyPrintFalse + "/" + canSetFormatPrettyPrintTrue);
// test values
assertEquals(defaultFormatPrettyPrint, Boolean.FALSE, "Default value of " + DOM_FORMAT_PRETTY_PRINT + " should be " + Boolean.FALSE);
assertEquals(canSetFormatPrettyPrintFalse, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.FALSE + " should be "
+ Boolean.TRUE);
assertEquals(canSetFormatPrettyPrintTrue, Boolean.TRUE, "Can set " + DOM_FORMAT_PRETTY_PRINT + " to " + Boolean.TRUE + " should be "
+ Boolean.TRUE);
// get default serialization
String prettyPrintDefault = lsSerializer.writeToString(document);
System.out.println("(default) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+ ": \n\"" + prettyPrintDefault + "\"");
assertEquals(prettyPrintDefault, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with default value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+ (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
// configure LSSerializer to not format-pretty-print
domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.FALSE);
String prettyPrintFalse = lsSerializer.writeToString(document);
System.out.println("(FALSE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+ ": \n\"" + prettyPrintFalse + "\"");
assertEquals(prettyPrintFalse, XML_DOCUMENT_DEFAULT_PRINT, "Invalid serialization with FALSE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+ (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
// configure LSSerializer to format-pretty-print
domConfiguration.setParameter(DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
String prettyPrintTrue = lsSerializer.writeToString(document);
System.out.println("(TRUE) " + DOM_FORMAT_PRETTY_PRINT + "==" + (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT)
+ ": \n\"" + prettyPrintTrue + "\"");
assertEquals(prettyPrintTrue, XML_DOCUMENT_PRETTY_PRINT, "Invalid serialization with TRUE value, " + DOM_FORMAT_PRETTY_PRINT + "=="
+ (Boolean) domConfiguration.getParameter(DOM_FORMAT_PRETTY_PRINT));
}
private String serializerWrite(Node xml) throws Exception {
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
DOMImplementationLS domImplementation = (DOMImplementationLS) registry.getDOMImplementation("LS");
StringWriter writer = new StringWriter();
LSOutput formattedOutput = domImplementation.createLSOutput();
formattedOutput.setCharacterStream(writer);
LSSerializer domSerializer = domImplementation.createLSSerializer();
domSerializer.getDomConfig().setParameter(DOM_FORMAT_PRETTY_PRINT, true);
domSerializer.getDomConfig().setParameter("xml-declaration", false);
domSerializer.write(xml, formattedOutput);
return writer.toString();
}
private String transform(Node xml) throws Exception {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(xml), new StreamResult(writer));
return writer.toString();
}
private Document toXmlDocument(String xmlString) throws Exception {
InputSource xmlInputSource = new InputSource(new StringReader(xmlString));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);
DocumentBuilder xmlDocumentBuilder = dbf.newDocumentBuilder();
Document node = xmlDocumentBuilder.parse(xmlInputSource);
return node;
}
private Text newTextNode(String text) throws Exception {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
return db.newDocument().createTextNode(text);
}
private Document createDocWithSequentTextNodes() throws Exception {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.newDocument();
Node root = doc.createElement("root");
doc.appendChild(root);
root.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode("t"));
root.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createTextNode("t"));
root.appendChild(doc.createTextNode(" "));
Node child1 = doc.createElement("child1");
root.appendChild(child1);
child1.appendChild(doc.createTextNode(" "));
child1.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createTextNode("t"));
Node child2 = doc.createElement("child2");
root.appendChild(child2);
child2.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
Node child3 = doc.createElement("child3");
root.appendChild(child3);
child3.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
Node child4 = doc.createElement("child4");
root.appendChild(child4);
child4.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
Node child5 = doc.createElement("child5");
root.appendChild(child5);
child5.appendChild(doc.createTextNode("t"));
Node child51 = doc.createElement("child51");
child5.appendChild(child51);
child51.appendChild(doc.createTextNode(" "));
Node child511 = doc.createElement("child511");
child51.appendChild(child511);
child511.appendChild(doc.createTextNode("t"));
child51.appendChild(doc.createTextNode(" "));
child5.appendChild(doc.createTextNode("t"));
root.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createComment(" test comment "));
root.appendChild(doc.createTextNode(" \n"));
root.appendChild(doc.createComment(" "));
root.appendChild(doc.createTextNode("\n"));
root.appendChild(doc.createProcessingInstruction("target1", "test"));
root.appendChild(doc.createTextNode(" "));
root.appendChild(doc.createTextNode(" "));
return doc;
}
private static final String DOM_FORMAT_PRETTY_PRINT = "format-pretty-print";
private static final String MIXED_NODE_TYPES_XML = "\n" +
" t\n" +
"t \n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" t\n" +
" \n" +
" t\n" +
" \n" +
" t\n" +
" \n" +
" \n" +
" \n";
}