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