用于生成HTML标签的设计模式

时间:2014-02-08 20:34:30

标签: java html design-patterns

对于可以获取String并输出HTML的小型系统,哪种设计模式适合?

这是一个小例子:

public String makeStrong(String in) {

    return "<strong>" + in + "</strong>";
}

当然,它需要对某些层次结构进行建模,以使其适合<ul><ol>及其子项。我想的是装饰器,但复合模式听起来也不错。我应该考虑什么?

3 个答案:

答案 0 :(得分:3)

考虑用于构建经过验证的HTML片段的构建器模式。我写了一些类似于验证HTML的内容,以便在Swing应用程序组件中使用,例如提示。以下是您可以构建的粗略骨架:

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,
    // e.g. 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();
  }
}

简单用例:

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

您可以根据需要添加尽可能多的验证,例如将“tr”定义为仅允许在“表”中。我怀疑那里已经存在这样的事情了。

答案 1 :(得分:2)

乍一看,我想到了一个Builder模式或更好的流畅API。 以下更紧凑:

import static a.b.c.HTML.*;

    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("</").append(tag).append('>');
        }

    }
}

答案 2 :(得分:2)

使用AutoCloseable界面的简约方法如下:

程序打印
<body><strong> some text </strong><ol><li>a</li><li>b</li><li>c</li></ol></body>
Online demo

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("</");
        content.append(name);
        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");
    }
}

绝对不是白痴,但对于简单的用途,它可能是一个良好的开端。