【问题标题】:Programmatic HTMLDocument generation using Java使用 Java 生成程序化 HTMLDocument
【发布时间】:2010-10-31 15:56:19
【问题描述】:

有谁知道如何在 Java 中以编程方式生成 HTMLDocument 对象,而无需求助于外部生成字符串,然后使用 HTMLEditorKit#read 来解析它?我问的两个原因:

首先,我的 HTML 生成例程需要非常快,并且我假设将字符串解析为内部模型比直接构建此模型的成本更高。

其次,面向对象的方法可能会产生更简洁的代码。

我还应该提到,出于许可原因,除了 JVM 附带的库之外,我不能使用任何库。

谢谢, 汤姆

【问题讨论】:

  • 为什么需要解析正在生成的 HTML?您是否需要能够插入可能无效的内联 HTML?
  • 感谢您的问题: mmyers:HTML Oliver:抱歉,我没有说清楚。如果我正确理解您的问题,我将从 HTML 生成一个 HTMLDocument(使用 HTMLEditorKit#read),由 JTextPane 呈现。
  • 再说一次,这并不能解释为什么您需要先生成然后解析。
  • 不是我在做解析。但是,我假设 swing 必须解析隐藏的 HTML 以便在 JTextArea 中呈现 HTML(否则每次它想要重绘窗格时都会不必要地重新解析对象)。我想找到一些跳过这一步的方法,直接生成对象,而不是生成一个字符串(Swing 大概会解析成对象)。
  • 由于您有一个需要生成的已定义目标对象 (HTMLDocument),因此只有为它设计 API 时,代码才会更清晰。如果编写 API 时只考虑了一个字符串作为源,那么将代码强制转换为解析方法可能会更快,也可能不会更快,但几乎肯定不会更干净。

标签: java html construction


【解决方案1】:

基本上,您可以使用插入方法之一将 html 插入 HTMLDocument,insertBeforeEnd()、insertAfterEnd()、insertBeforeStart()、insertAfterStart()。 您为方法提供要插入的 html 以及要插入 html 在文档树中的位置。

例如。

doc.insertBeforeEnd(element, html);

HTMLDocument 类还提供了遍历文档树的方法。

【讨论】:

    【解决方案2】:

    您似乎可以使用直接构造 HTMLDocument.BlockElementHTMLDocument.BlockElement 对象来完成您正在尝试的事情。这些构造函数有一个签名,表明至少可以直接使用。

    我建议检查 OpenJDK 中的 Swing 源代码,以了解解析器如何处理此问题,并从中推导出您的逻辑。

    我还建议这种优化可能为时过早,也许这应该是一种速度优化的替代品,以替代仅在确实成为应用程序中的性能热点时才引入的更简单的方法(即生成 HTML 文本)。

    【讨论】:

      【解决方案3】:

      javax.swing.text.html 有 HTMLWriterHTMLDocument 等类。我没有使用过它们。我在 .Net 中使用了HtmlWriter,它完全符合您的要求,但 java 版本可能不一样。

      这里是文档:http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/html/HTMLWriter.html

      另外,我无法想象StringBuilder 比使用对象层构建要慢。在我看来,任何面向对象的方法都必须构建对象图然后生成字符串。不使用原始字符串的主要原因是您肯定会遇到编码错误以及其他导致格式错误的文档的错误。

      选项 2:您可以使用自己喜欢的 XML api 并生成 XHTML。

      【讨论】:

        【解决方案4】:

        在处理 XHTML 时,我使用 Java 6 的 XMLStreamWriter 接口取得了很大的成功。

        OutputStream destination = ...;
        XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
        XMLStreamWriter xml = outputFactory.createXMLStreamWriter(destination);
        
        xml.writeStartDocument();
        xml.writeStartElement("html");
        xml.writeDefaultNamespace("http://www.w3.org/1999/xhtml");
        
        xml.writeStartElement("head");
        xml.writeStartElement("title");
        xml.writeCharacters("The title of the page");
        xml.writeEndElement();
        xml.writeEndElement();
        
        xml.writeEndElement();
        xml.writeEndDocument();
        

        【讨论】:

          【解决方案5】:

          一种面向对象的方法是使用名为ECS 的库。

          这是一个非常简单的库,并且多年来没有改变。再说一次,HTML 4.01 规范也没有改变;)我使用过 ECS,认为它比仅使用字符串或 StringBuffers/StringBuilders 生成大型 HTML 片段要好得多。

          小例子:

          Option optionElement = new Option();
          optionElement.setTagText("bar");
          optionElement.setValue("foo");
          optionElement.setSelected(false);   
          

          optionElement.toString() 现在会产生:

          <option value='foo'>bar</option>
          

          该库支持 HTML 4.0 和 XHTML。最初让我非常困扰的唯一一件事是与 XHTML 版本相关的类的名称以小写字母开头:optioninputatr 等等on,这违反了最基本的 Java 约定。但是,如果您想使用 XHTML,您可以习惯这一点。至少我做到了,速度出奇的快。

          【讨论】:

          • Tom 不能直接使用该库(尽管为什么有人会遇到 Apache 许可证问题对我来说是个谜),但他可以查看 api 的想法。
          • 嗯,我很确定“我不能求助于使用 JVM 附带的库以外的任何库”不在问题的原始版本中! :) 有了这个限制,JeeBee(像 TableBuilder 这样的实用程序类)和 Adam Paynter(XMLStreamWriter)的解决方案似乎是合理的。
          【解决方案6】:

          我会研究 JSP 是如何工作的 - 即,它们编译成一个 servlet,它基本上是一个巨大的 StringBuffer 附加集。这些标签还编译成 Java 代码 sn-ps。这很混乱,但非常非常快,除非您深入研究 Tomcat 的工作目录,否则您永远不会看到此代码。也许您想要的实际上是从一个以 HTML 为中心的视图(如 JSP)编写您的 HTML 生成代码,并为循环添加标签等,并在项目内部使用类似的代码生成引擎和编译器。

          或者,只需在具有“openTag”、“closeTag”、“openTagWithAttributes”、“startTable”等方法的实用程序类中自己处理 StringBuilder……它可以使用 Builder 模式,并且您的代码如下:

          public static void main(String[] args) {
              TableBuilder t = new TableBuilder();
              t.start().border(3).cellpadding(4).cellspacing(0).width("70%")
                .startHead().style("font-weight: bold;")
                  .newRow().style("border: 2px 0px solid grey;")
                    .newHeaderCell().content("Header 1")
                    .newHeaderCell().colspan(2).content("Header 2")
                .end()
                .startBody()
                  .newRow()
                    .newCell().content("One/One")
                    .newCell().rowspan(2).content("One/Two")
                    .newCell().content("One/Three")
                  .newRow()
                    .newCell().content("Two/One")
                    .newCell().content("Two/Three")
                .end()
              .end();
              System.out.println(t.toHTML());
          }
          

          【讨论】:

          • 我在这里使用了 TableBuilder,因为我有代码,因为我们需要将 HTML 表格嵌入到项目中的 HTML 电子邮件中。写起来并不难,但你需要跟踪打开的标签和你当前的状态。
          【解决方案7】:

          我认为通过 StringBuilder(或直接生成流)之类的方式手动生成 HTML 将是您的最佳选择,尤其是在您无法使用任何外部库的情况下。

          无法使用任何外部库,您将在开发速度而非性能方面遭受更多损失。

          【讨论】:

          • +1 它是最快的,并且根据我对这个问题的回复,可以将肮脏的方面隐藏在实用程序构建器类中。
          【解决方案8】:

          您可以使用任何像样的 xml 库,例如 JDom 或 Xom 或 XStream。 Html 只是 XML 的一个特例。

          或者,您可以使用现有的服务器端 java 模板引擎之一,例如 jsp 或 velocity。

          【讨论】:

          • 从技术上讲,HTML 不是 XML 的特例。 XHTML 是。
          • XHTML(强调 X)是 XML。 HTML 是 SGML。它们很相似,但实际上并不相同。大多数有效的 XHTML 也是有效的 HTML,但不是全部。
          • 因为它是在 JEditorPane 中使用的,所以它只需要是一种窗格可以读取的 HTML 形式。
          • 是的,这就是问题的症结,凯西 :)
          【解决方案9】:

          您可能希望使用 render() 方法构建一些 Element 对象,然后将它们组装成树形结构;使用访问算法,您可以继续设置值,然后渲染整个事物。

          PS:你考虑过像freemarker这样的模板引擎吗?

          【讨论】:

            猜你喜欢
            • 2023-03-20
            • 1970-01-01
            • 2010-12-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多