Design Pattern per la generazione di tag HTML

Per un piccolo sistema che può ottenere una stringa e generare un codice HTML, quale modello di progettazione sarebbe adatto?

Questo è un piccolo esempio:

public String makeStrong(String in) { return "" + in + ""; } 

Ovviamente ha bisogno di modellare una struttura gerarchica in modo che possa adattarsi a

    e

      e ai loro figli. Sto pensando a Decorator ma anche il pattern Composite sembra buono. Cosa dovrei considerare?

        Considera il modello di builder per la costruzione di frammenti HTML validati. Ho scritto qualcosa di simile per convalidare l’HTML da utilizzare nei componenti delle app di Swing, ad esempio i tooltip. Ecco uno scheletro approssimativo di qualcosa su cui potresti build:

         public final class HtmlBuilder() { private final StringBuilder sb = new StringBuilder(); private final Deque tagStack = new ArrayDeque(); public HtmlBuilder() { startTag("html"); } // Consider using an enum of valid tags and extending to support attributes public HtmlBuilder startTag( String tag ) { // TODO preconditions tagStack.push( tag ); sb.append('<').append(tag).append('>'); return this; } public HtmlBuilder endTag( String tag ) { // TODO preconditions, // eg check "!tagStack.isEmpty() && tagStack.peek().equals( tag ) tagStack.pop(); sb.append('<').append('/').append(tag).append('>'); return this; } public HtmlBuilder append( String text ) { // TODO Preconditions, check for/escape special characters etc sb.append( text ); return this; } @Override public String toString() { endTag("html") return sb.toString(); } } 

        Caso d’uso semplice:

         String html = new HtmlBuilder() .startTag( "strong" ).append( "text" ).endTag( "strong" ) .toString(); 

        Puoi aggiungere tutte le convalide che desideri, ad esempio definire “tr” come consentito solo all’interno di una “tabella”. Sospetto che ci sia già qualcosa del genere.

        A prima vista ho pensato a un pattern Builder o una API migliore. Un po ‘più compatto è il seguente:

         import static abcHTML.*; String html = p( ol( li(), li( _("Hello, "), strong(_("World")), _("!") ), li() ) ).toString(); public class HTML { protected final String tag; private final HTML[] items; public HTML(String tag, final HTML... items) { this.tag = tag; this.items = items; } public static HTML _(String text) { return new HTML(text) { @Override public String toString() { return tag; } @Override protected void buildString(StringBuilder sb) { sb.append(tag); } }; } public static HTML li(final HTML... items) { return new HTML("li", items); } public static HTML ol(final HTML... items) { return new HTML("ol", items); } public static HTML p(final HTML... items) { return new HTML("p", items); } public static HTML strong(final HTML... items) { return new HTML("strong", items); } @Override public String toString() { StringBuilder sb = new StringBuilder(); buildString(sb); return sb.toString(); } protected void buildString(StringBuilder sb) { sb.append('<').append(tag); if (items.length == 0) { sb.append(" />"); } else { sb.append('>'); for (HTML item : items) { item.buildString(sb); } sb.append("'); } } } 

        Un approccio minimalista sarebbe il seguente, utilizzando l’interfaccia AutoCloseable :

        Il programma stampa
        some text

        1. a
        2. b
        3. c


        Demo online

         public class Main { public static void main(String args[]) { Page page = new Page(); writeBody(page); page.show(); } static void writeBody(Page page) { try (BodyTag bodyTag = new BodyTag(page)) { writeText(page); writeList(page); } } static void writeText(Page page) { try (StrongTag strongTag = new StrongTag(page)) { strongTag.append(" some text "); } } static void writeList(Page page) { try (ListTag list = new ListTag(page)) { // A twisted way to write a, b and c as elements for (char c=97; c<100; ++c) { appendElem(page, String.valueOf(c)); } } } static void appendElem(Page page, String elem) { try (ListElem li = new ListElem(page)) { li.append(elem); } } } class Page { StringBuilder content = new StringBuilder(); void append(String text) { content.append(text); } void show() { System.out.println(content); } } abstract class Tag implements AutoCloseable { String name; Page content; Tag(Page parent, String tagName) { name = tagName; content = parent; content.append("<"); content.append(name); content.append(">"); } public void append(String text) { content.append(text); } @Override final public void close() { content.append(""); } } final class StrongTag extends Tag { public StrongTag(Page parent) { super(parent, "strong"); } } final class BodyTag extends Tag { public BodyTag(Page parent) { super(parent, "body"); } } final class ListTag extends Tag { public ListTag(Page parent) { super(parent, "ol"); } } final class ListElem extends Tag { public ListElem(Page parent) { super(parent, "li"); } } 

        Sicuramente non a prova di idiota, ma per usi semplici, potrebbe essere un buon inizio.