What follows looks to be roughly a builder candidate for Curl web content markup using "{" and "}" as the delimiters. As with XHTML, the Curl content may require a 'prolog' and a few non-hierarchical items comparable to the !DOCTYPE of XML. Web markup is often more than simply a hierarchy of nested nodes.
/**
* A helper class for creating Curl markup
* borrowed from http://docs.codehaus.org/display/GROOVY/Make+a+builder
* original MarkupBuilder by James Strathan
* mods by RS
*/
public class CurlBuilder extends BuilderSupport {
private IndentPrinter out;
private boolean nospace;
private int state;
private boolean nodeIsEmpty = true;
public CurlBuilder() {
this(new IndentPrinter());
}
public CurlBuilder(PrintWriter writer) {
this(new IndentPrinter(writer));
}
public CurlBuilder(Writer writer) {
this(new IndentPrinter(new PrintWriter(writer)));
}
public CurlBuilder(IndentPrinter out) {
this.out = out;
}
protected void setParent(Object parent, Object child) {
}
protected Object createNode(Object name) {
toState(1, name);
return name;
}
protected Object createNode(Object name, Object value) {
toState(2, name);
// out.print(">");
out.print(value.toString());
return name;
}
protected Object createNode(Object name, Map attributes, Object value) {
toState(1, name);
for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
out.print(" ");
print(transformName(entry.getKey().toString()));
out.print("='");
print(transformValue(entry.getValue().toString()));
out.print("'");
}
if (value != null)
{
nodeIsEmpty = false;
out.print(" " + value + "}");
}
return name;
}
protected Object createNode(Object name, Map attributes) {
return createNode(name, attributes, null);
}
protected void nodeCompleted(Object parent, Object node) {
toState(3, node);
out.flush();
}
protected void print(Object node) {
out.print(node == null ? "null" : node.toString());
}
protected Object getName(String methodName) {
return super.getName(transformName(methodName));
}
protected String transformName(String name) {
if (name.startsWith("_")) name = name.substring(1);
return name.replace('_', '-');
}
protected String transformValue(String value) {
return value.replaceAll("\\'", """); }
protected void toState(int next, Object name) {
switch (state) {
case 0:
switch (next) {
case 1:
case 2:
out.print("{");
print(name);
break;
case 3:
throw new Error();
}
break;
case 1:
switch (next) {
case 1:
case 2:
out.print(" ");
if (nospace) {
nospace = false;
} else {
out.println();
out.incrementIndent();
out.printIndent();
}
out.print("{");
print(name);
break;
case 3:
if (nodeIsEmpty) {
out.print(" }");
}
break;
}
break;
case 2:
switch (next) {
case 1:
case 2:
throw new Error();
case 3:
out.print(" }");
break;
}
break;
case 3:
switch (next) {
case 1:
case 2:
if (nospace) {
nospace = false;
} else {
out.println();
out.printIndent();
}
out.print("{");
print(name);
break;
case 3:
if (nospace) {
nospace = false;
} else {
out.println();
out.decrementIndent();
out.printIndent();
}
out.print(" }");
break;
}
break;
}
state = next;
}}That could have been so elegant if the MarkupBuilder class had understood markup itself as a pattern rather than hard-coding the SGML-style tag delimiters and assuming the tagging style (close before content, reopen after content.)
The ability to inject a markup builder for non-SGML markup for an entire site is lost: we still have to look into such things as 404 and 500 errors because we have only covered where we explicitly instantiate a builder. DI should have solved that web container-wide.
As I never tire of saying, when we get beyond HTML5 and the mere browser, this SGML-bias will look like an unquestioned assumption as curious as any other in the history of data format oddities and over-sights.
To get from <br/> to {br} should not be a coding intervention task of this magnitude or this nature.
No comments:
Post a Comment