What is a good technique for markup (HTML) generation?
Some time ago I asked here about a good html object model in java. I received a good answer pointing to the Element Construction Set project:
I used happily this API to quickly build some HTML reports.
When visiting the project site recently, I found that it has been moved to "The Apache Attic" and that the author of the project encourages its user to switch to other techniques for markup generation.
My question is about this last sentence:
what is a good other technique for markup generation ?I'm not building an HTML client, I just need to generate some reports in HTML from server side data. I have considered some replacement tools but I can't find my next one:
- groovy and its markup builder
- free marker
- xslt
- jasper report
What I like with ECS is that it is purely in Java (no new syntax and concepts to learn, other project libs available), it is quite small, it contains definition for all commons html elements and properties (easy to use with auto completion, without having to have an HTML doc around -> good for server side developer with only basic knowledge of HTML)
At the moment I'm wasting time doing investigation, playing around with some potential replacer, but I would be glad to have feedback to help me refocus on doing my task.
What ot开发者_C百科her techniques would you recommend for this kind of usage and having the same ease of use than ECS ?
From my experience, what works best is a templating mechanism and a function for escaping markup (handling <
&
"
and '
will do). Pick any templating engine that supports basic control structures like loops and conditionals.
Don't bother with object models for generating HTML.
Here are 4 solutions.
The first one is probably the best one: https://j2html.com/
// https://j2html.com/examples.html
@Test
public void test() {
String s = document(
html(
head(
title("Title"),
link().withRel("stylesheet").withHref("/css/main.css")),
body(
main(attrs("#main.content"),
h1("Heading!"))))).toString();
assertEquals("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
+ "<html>\n"
+ " <head>\n"
+ " <title>\n"
+ " Title\n"
+ " </title>\n"
+ " <link type=\"text/css\" rel=\"stylesheet\" href=\"/css/main.css\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <main id=\"main\" class=\"content\">\n"
+ " <h1>\n"
+ " Heading!\n"
+ " </h1>\n"
+ " </main>\n"
+ " </body>\n"
+ "</html>\n", JtidyTest.tidyHtml(s));
}
It does not support pretty-print. Use jtidy for that:
public static String tidyHtml(String inputHtml) {
Properties oProps = new Properties();
oProps.setProperty("new-blocklevel-tags", "main");
Tidy tidy = new Tidy();
tidy.setConfigurationFromProps(oProps);
tidy.setXHTML(false);
tidy.setDocType("loose");
tidy.setQuiet(true);
tidy.setShowWarnings(false);
tidy.setTidyMark(false);
tidy.setIndentContent(true);
StringWriter writer = new StringWriter();
tidy.parse(new StringReader(inputHtml), writer);
return writer.toString().replace("\r", "");
}
The following two examples/solutions use only Java's own XML stuff and therefore don't provide explicit HTML support, which is a bit inconvenient.
From object model:
@Test
public void test() throws Exception {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element htmlElement = doc.createElement("html");
htmlElement.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
doc.appendChild(htmlElement);
Element headElement = doc.createElement("head");
htmlElement.appendChild(headElement);
Element titleElement = doc.createElement("title");
titleElement.appendChild(doc.createTextNode("The title of the page &"));
headElement.appendChild(titleElement);
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+ "<head>\n"
+ "<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"
+ "<title>The title of the page &</title>\n"
+ "</head>\n"
+ "</html>\n",
transform(doc));
}
static String transform(Document doc) {
try {
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString().replace("\r", "");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
Full code: https://github.com/jjYBdx4IL/java-evaluation/blob/master/src/test/java/tests/javax/xml/XhtmlGenTest.java
Directly to stream:
@Test
public void testGenerateXHTML() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
XMLStreamWriter xml = outputFactory.createXMLStreamWriter(baos);
xml.writeStartDocument();
xml.writeStartElement("html");
xml.writeDefaultNamespace("http://www.w3.org/1999/xhtml");
xml.writeStartElement("head");
xml.writeStartElement("title");
xml.writeCharacters("The title of the page");
xml.writeEndElement();
xml.writeEndElement();
xml.writeEndElement();
xml.writeEndDocument();
assertEquals("<?xml version='1.0' encoding='UTF-8'?><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>The title of the page</title></head></html>",
baos.toString("UTF-8"));
}
Full code: https://github.com/jjYBdx4IL/java-evaluation/blob/master/src/test/java/tests/javax/xml/stream/XMLStreamWriterTest.java
You might also consider ECS, but it is retired and does not support implicit handling of special characters like &. I have updated it to compile with Java 8: https://github.com/jjYBdx4IL/misc/tree/master/ecs Not sure when I'll deploy it to maven central tho. I have also modified it to include javadoc, sources and debug symbols, all of which the existing distribution on maven central does not provide.
精彩评论