 |
<noscript>&lt;tr valign=&quot;top&quot;&gt;&lt;td width=&quot;8&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;8&quot; src=&quot;//www.ibm.com/i/c.gif&quot;/&gt;&lt;/td&gt;&lt;td width=&quot;16&quot;&gt;&lt;img alt=&quot;&quot; width=&quot;16&quot; height=&quot;16&quot; src=&quot;//www.ibm.com/i/c.gif&quot;/&gt;&lt;/td&gt;&lt;td class=&quot;small&quot; width=&quot;122&quot;&gt;&lt;p&gt;&lt;span class=&quot;ast&quot;&gt;未显示需要 JavaScript 的文档选项&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;</noscript> |
|
级别: 初级 Amit Tuli (tamit@in.ibm.com ), Software Engineer, IBM India Research Lab 2004 年 7 月 22 日
Jakarta Element Construction Set(ECS)是一个使用 Java 语言和面向对象方法创建标记语言文档的开放源代码项目。Java 开发人员 Amit Tuli 介绍了 ECS 并展示了如何用它一步一步地在日志文件中生成格式良好的状态报告。我们将创建一个示例应用程序来帮助您更好地理解 ECS 及其用法。还将介绍这个 API 的一些其他用法。
在本文中,您将学到如何使用 Jakarta Element Construction Set (ECS),这是一组可以用来开发生成格式良好标记文档的 Java 类。我将带您完成下载并使用 ECS 库开发一个示例应用程序的过程,这个应用程序可以读取不同的日志文件,并用它们生成 HTML 格式的状态报告。我不会深入生成日志文件的应用程序的细节,相反,我只是假定应用程序使用标准格式的日志文件。(当然,可以使用其他 ECS 库,其日志文件格式可能与我们这里使用的不一样,那样的话,您需要相应地修改解析算法以便从日志文件中提取所需要的信息。)可以编写类似的代码或者插件程 序,将您自己流化的或者复杂的日志转换为格式良好的 HTML 文件,从而获得更好的可读性和易用性。 大型企业应用程序 ——像应用服务器、测试应用程序或者带有事务性日志的在线系统——生成大量日志文件。阅读全部日志并提取有用数据的汇总会是一项困难和费时的工作。一个具 有 HTML 格式的汇总报告可以以更具可读性的方式表示数据。但是在 Java 应用程序中生成大型 HTML 文件是另一项艰巨的任务。我们将共同分析的这个例子提供了用 Jakarta ECS API 生成 HTML 文档的一个简单和可管理的方法。我们将使用的技术可以扩展到任何需要生成标记文档的应用程序。 开始使用 ECS ECS 是一组类,它们可用于生成以 HTML、XML、VioceXML 和其他标记语言编写的文档。目前,ECS 支持 HTML 和 XML,但是它可以扩展为支持其他不同的标记语言。有了 ECS,就可以创建一个使用面向对象方法生成这种文档的应用程序,这简化了应用程序的开发和维护。ECS 提供了用 Java 对象生成标记语言的更易管理的技术。 创建 HTML 文档的传统方式 在典型情况下,开发人员如何编写创建 HTML 文档的 Java 代码呢?一般来说, servlet 将会向客户端写回一个响应。清单 1 中的代码展示了这种应用程序的常见方法。 清单 1. 生成 Java 应用程序中 HTML 的代码
out.println("<HTML>");
out.println("<HEAD><TITLE>Log Report</TITLE></HEAD>");
out.println("<BODY>");
out.println("<H1>Logs for application A</H1>");
out.println("<H3>Generated on Mar 03rd, 2004</H3>");
out.println("Following table lists down status of all testcases.");
out.println("</BODY>");
out.println("</HTML>");
|
这种代码难于调试和管理。而且,必须在这里处理输出的标记格式。HTML 文档不一定需要是格式良好的,但是如果试图创建 XML 文档,像清单 1 中这样的代码就会让程序人员感到头痛:代码处理 String 并且不使用标记文档的任何特性。编程人员必须保证标签是正确关闭和嵌套的。如您所见,ECS 聪明地为您做所有这些事情。 使用 ECS 现在让我们分析一下使用 ECS API 的替代方式。清单 2 中的代码创建清单 1 中的代码创建的同样 HTML 文档。如果您仔细观察它,您会发现它不需要您为输出特殊的字符而编写大量代码,如 < 和 > 。 清单 2. 在 Java 应用程序中使用 ECS 生成 HTML 的代码
Html html = new Html()
Head head = new Head();
head.addElement(new Title("Log Report")));
html.addElement(head);
Body body = new Body();
body.addElement(new H1("Logs for application A"));
body.addElement(new H3("Generated on Mar 03rd, 2004"));
body.addElement("Following table lists down status of all testcases.")));
html.addElement(body);
out.println(html.toString());
|
编 程人员能够体会到生成清单 2 所示 HTML 的干净和面向对象方法的好处。在这里,最终文档中每个 HTML 元素都是一个 Java 对象。在其他对象中嵌套对象以构成嵌套的 HTML 代码。您处理的是 Java 对象而不是原始字符串,以便形成 HTML 文档。ECS 接受添加元素的名字——这个概念类似于 java.util.Hashtable 中的键。可以在以后利用这个键来访问元素,甚至可以删除元素。用以前的方法修改或者删除 HTML 元素几乎不可能,因为缺少任何结构。 对于复杂的文档,ECS 非常方便,因为它有定义为管理颜色、文档等的类。
ECS API:进一步考察 ECS 提供了一种编程方式来生成以不同标记语言编写的文档。它设计为通过面向对象的抽象来生成所有标签。 ECS 结构的定义方式使得创建文档容器的 Document 类成为了 Html 、 Head 、 Title 和 Body 元素的包装器。事实上,ECS 对每个 HTML 标签有一个对应的 Java 类。例如,Html.class 对应于 <html> 标签,Head.class 对应于 <head> 标签等等。可以用相应的 Java 对象创建和添加标签。图 1 表示了对象布局,显示了 ECS 类的容器关系。 图 1. 元素结构

ECS 定义了一组类和接口,如图 2 所示。 图 2. 类结构

一些重要的 ECS 类 在介绍示例应用程序之前,我将讨论一些常用的 ECS 类。这有助于更好地理解示例代码。 org.apache.ecs.html.Html 这个类表示 HTML 中的 <html> 元素。这种类型的对象用于容纳所有其他的元素。所有其他元素对象都包含在它或者它的一个子对象中。 org.apache.ecs.html.Head 这个类表示 HTML 中的 <head> 元素。 org.apache.ecs.html.Table 这个类表示 HTML 中的 <table> 元素。这个 HTML 元素的属性 (像 border 、 bgcolor 、 cellspacing 等) 可以用这个类的 getter/setter 方法设置。 org.apache.ecs.html.Form 这个类表示 HTML 中的 <form> 元素。这个 HTML 元素的属性 (像 action 、 name 、 method 等) 可以用这个类的 getter/setter 方法设置。 org.apache.ecs.html.Body 这个类表示 HTML 中的 <body> 元素。这个 HTML 元素的属性 (如 background 、 alink 、 bgcolor 等) 和事件 (如 onClick 、 onDblClick 、 onKeyPress 等) 可以用这个类的 getter/setter 方法设置。
一个示例日志生成应用程序 在本节,我将回顾这个示例应用程序代码的重要内容并解释它是如何工作的。如果希望看到完整的应用程序代码以及这个应用程序将要解析的示例日志文件,可以单击本文顶部或者底部的 Code 图标。回顾完代码后,我将引导您完成下载示例代码和 ECS 库的过程,这样如果愿意,您就可以在自己的计算机上执行这个示例应用程序。 为 了设置这一过程的场景,想像使用一个执行不同测试用例并为每一用例生成单独日志文件的应用程序。(这个应用程序的特性对于我们的目的来说并不重要。) 测试用例有一个共同点:日志文件的格式。清单 3 显示了一个示例日志文件。这个文件相对简单,但是长的日志文件会非常复杂并难于阅读和分析。 清单 3. 日志文件
Testlog for Tc1
***************
Variation 1 : Passed
Variation 2 : Passed
Variation 3 : Passed
SUMMARY ->
Total variations : 3
Total variations ran : 3
Total Passed : 3
Total Failed : 0
Testcase Result : PASSED |
第一行表明这个测试日志是针对名为 Tc1 的测试用例的。后三行显示测试用例的变种:共有三类变种,它们都通过了。运行这个测试用例的总结出现在 SUMMARY -> 一行之后。 看了要处理的日志文件之后,我们将编写一个 Java 应用程序,它解析这些文件并生成一个综合报告。第一步是创建根元素 <html> ,如清单 4 所示: 清单 4. 创建 <html> 元素
Html html = new Html();
Head head = new Head();
Title title = new Title("Logging in HTML format");
head.addElement(title);
html.addElement(head);
|
在这段代码中, Html 是封装整个文档的对象。下一个子元素是 <HEAD> ,在这里它是由 Head 类表示的。 <TITLE> 元素是由 Title 类表示的。开始和结束 <TITLE> 标签之间的值作为参数传递给 Title 类的构造函数。这个 Title 元素添加到 Head ,而 Head 添加到 Html 。 下一步是读取并解析日志文件以收集所需要的信息。代码提取测试用例的名字、要运行的所有变种、通过的变种数量、未通过的变种数量以及日志文件的路径,并将所有这些信息存储到 Log 对象中。在解析一系列的日志文件时,代码创建 Log 对象的 Vector ,每个日志文件都有一个 Log 对象。如果对所有这些逻辑感兴趣,可以分析 ecs.jar 中的代码,它对于整体把握实际上并不重要,因为这个逻辑是特定于这个日志文件格式的。 这样,现在有了 Log 对象的 Vector ,每个 Log 表示一个日志文件。 Log 类的结构如清单 5 所示。 清单 5. Log 类
public class Log
{
private String testcaseName = null; // Name of the testcase
private int totalVariations = 0; // total number of variations in it
private int totalRan = 0; // total variations ran
private int totalPassed = 0; // total variations passed
private int totalFailed = 0; // total variations failed
private String result = null; // result of the testcase
private String logFile = null; // path of the log file
public String getResult() {}
public String getTestcaseName() {}
public int getTotalFailed() {}
public int getTotalPassed() {}
public int getTotalRan() {}
public int getTotalVariations() {}
public String getLogFile(){}
public void setResult(String string) {}
public void setTestcaseName(String string) {}
public void setTotalFailed(int i) {}
public void setTotalPassed(int i) {}
public void setTotalRan(int i) {}
public void setTotalVariations(int i) {}
public void setLogFile(String string) {}
}
|
现在已经解析了日志文件,并且有了生成报告所需要的所有数据,以前很复杂并且易混淆的打印格式良好的报告这一任务,就可以用 ECS 轻松地完成。在清单 6 中,我将展示如何创建一个表结构,其中每一列表示 Log 类的一个相应属性。在表中,每个测试用例占一行。 清单 6. 表头
Table table = new Table();
table.setBorder(1);
TH th = null;
String[] tableHeaders =
{
"Serial Number",
"Testcase Name",
"Total variations",
"Total variations ran",
"Total Passed",
"Total Failed",
"Result",
"Log File" };
for (int j = 0; j < tableHeaders.length; j++) {
th = new TH(tableHeaders[j]);
table.addElement(th);
}
|
创建了表并填充了表头后,就要生表数据了。为此,迭代 Vector 并生成 <TR> 标签,每个日志文件一个。在清单 7 中, logs 是包含 Log 对象的 Vector 。 清单 7. 生成表行
TR tr = null;
TD td = null;
Font font = null;
Iterator it = logs.iterator();
int count = 1;
while (it.hasNext()) {
Log log = (Log) it.next();
String testcaseName = log.getTestcaseName();
int totalVariations = log.getTotalVariations();
int totalPassed = log.getTotalPassed();
int totalFailed = log.getTotalFailed();
int totalRan = log.getTotalRan();
String result = log.getResult();
String logFile = log.getLogFile();
tr = new TR();
tr =
createTR(
count++,
testcaseName,
totalVariations,
totalRan,
totalPassed,
totalFailed,
result,
logFile);
table.addElement(tr);
}
|
注意,在完整的源代码中定义了 createTR() 方法,但是为了节省空间而没有在这里展示,请查看完整代码以了解它的工作过程。 这一步完成了所需要的 <TABLE> 结构,它现在可以包含在 <BODY> 元素中了。现在最后一项任务是将这个 <TABLE> 元素加入到 <BODY> 对象中,并将所有 HTML 代码保存到一个文件中,这是在清单 8 中完成的。 清单 8. 将 HTML 保存到一个文件中
body.addElement(table);
html.addElement(body);
DataOutputStream output = null;
try {
output =
new DataOutputStream(new BufferedOutputStream(new FileOutputStream("./result.html")));
output.write(html.toString().getBytes());
} catch (Exception e) {
e.printStackTrace();
}
|
清单 8 中的代码将应用程序中生成的 HTML 代码保存到当前目录中一个名为 result.html 的文件中。
运行示例应用程序 在运行这个示例应用程序之前,必须下载所需要的 ECS 库并设置环境以容纳它们。执行以下步骤:
- 下载 最新版本的 ECS 。 (在本文发表时当前版本是 ecs-1.4.2.zip。)
- 将文件保存到本地 (比如保存在 C:\ecsapi\ecs-1.4.2.zip)。
- 设置 classpath 以包括 C:\ecsapi\ecs-1.4.2.zip。
注意如果是在一个 IDE 中工作,那么您还需要设置它的路径。一些 IDE 只使用它们内部设置的 classpath。 现在可以安装示例应用程序本身了:
- 如果还没下载本文的源代码 ecs.jar 的话,请单击本文顶部或者底部的 Code 图标下载它。
- 将 ecs.jar 解压缩到一个文件夹中。比如使用 C:\ecs,解压缩这个 JAR 会将类文件释放到 C:\ecs 中,并日志文件释放到 C:\ecs\com\ecs\log 中。
- 设置 classpath 以包括 C:\ecs。
- 像这样运行这个应用程序:
java com.ecs.log.GenerateReport C:\ecs ,它会在当前目录中生成 result.html。
图 3 展示了生成的 HTML。 图 3. 程序输出

结束语 在本文中,您学习了 Jakarta ECS 的结构组件,以及如何利用它和 Java 对象根据日志文件生成格式良好的 HTML 状态报告。不过,这个库的用途不止于此。ECS 还有许多其他潜在的用途:
- 考虑一个能够生成 XML 格式数据的数据库系统。这种数据库可以用 ECS 增加能够生成的数据标记类型。
- 想像一个场景,其中 DBA 收到改变远程数据库的请求。他或者她可以用一个 PDA 访问并修改数据库。可以利用 ECS 生成 DBA 可以使用的 WML 界面。
- 假定您有一个可以用浏览器、Web 服务、PDA 或者电话作为客户端的应用程序。在这种情况下,应用程序工厂可以为每种客户类型 (分别是 HTML、XML、WML 或者 VoiceXML) 选择适当的标记并用 ECS 生成它。
如您所见,ECS 在任何需要以编程方式生成标记的场合非常有用。我希望本文为您提供了这种有用技术的一些启发。 |