Re: HTML generieren in Java



Sascha Effert schrieb:

ich suche was ganz triviales, aber leider konnte Google mir nicht helfen:
Ich suche eine Library, die einfach HTML-Elemente als Klassen anbietet.

Sowas wie http://jakarta.apache.org/ecs/index.html ?

Jochen würde wohl sagen, das kann man auch mit Groovy machen. Nur dann könntest du IMHO auch gleich ein Textdokument und Template erstellen, da es nicht mehr typsicher ist. Ich vermute doch, der Grund für deine Suche ist, dass du gerne das ganze statisch typsicher derart zusammenstecken möchtest, dass du kein falsches HTML erzeugen kannst.

Ich würde vorschlagen, das ganze einfach selbst zu bauen, denn ECS scheint mir etwas angestaubt. Statische Funktionen mittels "static import" und Restparameter sollten das ganze lesbarer machen.

Z.B.

html(
head(
title("Ein Beispiel")),
body(
table(
row(th("Smalltalk"), th("Lisp")),
row(td("3 + 4 * 5"), td("(* (+ 3 4) 5)"))),
p("The following special cases..."),
ul(
li("whiteTrue:"),
li("do:"))))

mit

static class Html {
private static class Elem {
String name; Object[] children;

Elem(String name, Object... children) {
this.name = name; this.children = children;
}

void emit(StringBuilder b) {
b.append('<').append(name);
if (children.length == 0) b.append("/>");
else {
for (Object c: children)
if (c instanceof Attr) { b.append(' '); ((Attr) c).emit(b); }
b.append('>');
for (Object c: children) {
if (c instanceof Elem) ((Elem) c).emit(b);
else if (c != null && !(c instanceof Attr)) {
String s = c.toString();
for (int i = 0, len = s.length(); i < len; i++) {
char ch = s.charAt(i);
if (ch == '<') b.append("&lt;");
else if (ch == '&') b.append("&amp;");
else b.append(ch);
}
}
}
b.append("</").append(name).append(">");
}
}

public String toString() {
StringBuilder b = new StringBuilder(4096); emit(b);
return b.toString();
}
}

private static class Attr {
String name; String value;

Attr(String name, String value) {
this.name = name; this.value = value;
}

void emit(StringBuilder b) {
b.append(name).append('=').append('"');
for (int i = 0, len = value.length(); i < len; i++) {
char ch = value.charAt(i);
if (ch == '<') b.append("&lt;");
else if (ch == '&') b.append("&amp;");
else if (ch == '"') b.append("&quot;");
else b.append(ch);
}
b.append('"');
}
}

static Elem html(Object... nodes) { return elem("html", nodes); }
static Elem head(Object... nodes) { return elem("head", nodes); }
...

private static Elem elem(String tag, Object[] nodes) {
return new Elem(tag, nodes);
}
}

Voila, eine DSL in Java.

Für Attribute schlage ich die folgende Funktion vor:

static Attr a(String name, Object value) {
return value != null ? new Attr(name, value.toString()) : null;
}

damit man

body(a("class", "main"), a("style", "background: red"),
...)

schreiben kann. Noch zu viel Syntax? Dann biete ich

static Attr a(String s) {
int i = s.indexOf('=');
return a(s.substring(0, i), s.substring(i + 1));
}

Eine Variante, die aus

a("class=main", "style=background:green")

ein Attr[] macht, braucht noch eine kleine Änderung in emit, sollte aber auch nicht schwer sein. Natürlich kann man sich auch Dinge wie

static Attr clasz(String value) { return attr("class", value); }

bauen, wenn man Lust hat.

Das ganze ist jetzt nicht Typsicher, weil ich einfach nur Elem-Objekte schachtel, aber mit diversen Unterklassen von Elem dafür zu sorgen, dass row() bzw. nur die Ergebnisse von td() und th() annimmt, sei dem Leser überlassen :)

--
Stefan Matthias Aust
.



Relevant Pages

  • Re: HTML generieren in Java
    ... void emitAttrs(StringBuilder b, Object[] nodes) { ... Dies brauche ich, da z.B. der Rumpf von FOREACH aus mehr als einem Kindobjekt bestehen kann, selbst aber kein Elem ist. ... Zwei spezielle Elem-Unterklassen implementieren jetzt das FOREACH und die Möglichkeit, auf die Schleifenvariable mit EACH zuzugreifen. ... static Object IF(boolean cond, Object... ...
    (de.comp.lang.java)
  • Idle Chuckles with FORMAT
    ... how do I derive a string of the form "(elem, elem, ..., elem)" where ... Someone thought about doing it with STRING-JOIN and using FORMAT ... to wrap the string in parentheses. ... I have always thought FORMAT was an ugly beast, ...
    (comp.lang.scheme)
  • RE: Setting a Different DataField for each Label2()
    ... Some Elem names at the Database had a blank space ... right after the last character. ... > Dim FLDSAs String ... > Dim Elem As Integer ...
    (microsoft.public.data.ado)
  • Re: hash, key, problem...
    ... hash.each do |elem| ... puts elem.join ... You can also of course get the string as: ... Katja ...
    (comp.lang.ruby)