处理 XML 文档
在本节中,您将了解如何在运行时运行 JiBX 绑定编译器和使用 JiBX,从而处理 XML 文档。
运行 JiBX 绑定编译器
要在处理 XML 文档时使用生成的绑定定义,首先需要运行 JiBX 绑定编译器工具。按照绑定定义的指定,绑定编译器将把字节码添加到编译后的类文件,这些文件实际实现了与 XML 之间的来回转换。每次重新编译 Java 类或修改绑定定义时,都必须运行绑定编译器,因此一般最好把绑定编译器步骤添加到项目的标准构建流程中。
jibx-bind.jar 中的 JiBX 发行版附带了绑定编译器。JiBX 文档将提供通过各种方法运行绑定编译器的完整信息,包括如何在运行时而非在构建时运行绑定编译器。JiBX 还提供了 Eclipse 和 IntelliJ IDEA 的插件,这样在使用这些 IDE 时将自动运行绑定编译器。
根据本教程的目的,您将把一切简单化并且只通过 Ant 使用 build.xml 的 bind 目标运行绑定编译器。假定您已经运行了 compile 和 bindgen 目标,图 2 将显示运行此目标时应当会看到的输出(您还可以通过在命令行中按顺序列出这些目标来运行全部三个目标:ant compile bindgen bind)。
图 2. Ant 构建 bind 任务
在运行时使用 JiBX
清单 3 显示了匹配生成模式的简单测试文档,包含在教程的代码下载中,名为 data.xml:
清单 3. 默认绑定测试文档
<order orderNumber="12345678" orderDate="2008-10-18" shipDate="2008-10-22"
xmlns="http://jibx.org/starter">
<customer customerNumber="5678">
<firstName>John</firstName>
<lastName>Smith</lastName>
</customer>
<billTo>
<street1>12345 Happy Lane</street1>
<city>Plunk</city>
<state>WA</state>
<postCode>98059</postCode>
<country>USA</country>
</billTo>
<shipping>PRIORITY_MAIL</shipping>
<shipTo>
<street1>333 River Avenue</street1>
<city>Kirkland</city>
<state>WA</state>
<postCode>98034</postCode>
<country>USA</country>
</shipTo>
<item quantity="1" price="5.99">
<id>AC4983498512</id>
<description>Left-handed widget</description>
</item>
<item quantity="2" price="9.50">
<id>IW2349050499</id>
<description>Right-handed widget</description>
</item>
<item quantity="1" price="8.95">
<id>RC3000488209</id>
<description>High-speed MP3 rewinder</description>
</item>
</order> |
下载包还包括一个简单测试程序,它在本文中显示为 清单 4,用于演示如何使用 JiBX 解组 及编组 文档(编组是在内存中生成对象的 XML 表示的过程,可能包括从初始对象链接的对象;解组是编组的反向过程,它将通过 XML 表示在内存中构建一个对象(还有可能是一些链接的对象)。Ant run 目标将执行此测试程序,使用 清单 3 文档作为输入并把编组后的文档副本写到名为 out.xml 的文件中。
清单 4. 测试程序
public class Test
{
/**
* Unmarshal the sample document from a file, compute and set order total, then
* marshal it back out to another file.
*
* @param args
*/
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: java -cp ... " +
"org.jibx.starter.Test in-file out-file");
System.exit(0);
}
try {
// unmarshal customer information from file
IBindingFactory bfact = BindingDirectory.getFactory(Order.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
FileInputStream in = new FileInputStream(args[0]);
Order order = (Order)uctx.unmarshalDocument(in, null);
// compute the total amount of the order
float total = 0.0f;
for (Iterator<Item> iter = order.getItems().iterator(); iter.hasNext();) {
Item item = iter.next();
total += item.getPrice() * item.getQuantity();
}
order.setTotal(new Float(total));
// marshal object back out to file (with nice indentation, as UTF-8)
IMarshallingContext mctx = bfact.createMarshallingContext();
mctx.setIndent(2);
FileOutputStream out = new FileOutputStream(args[1]);
mctx.setOutput(out, null);
mctx.marshalDocument(order);
System.out.println("Processed order with " + order.getItems().size() +
" items and total value " + total);
} catch (FileNotFoundException e) {
e.printStackTrace();
System.exit(1);
} catch (JiBXException e) {
e.printStackTrace();
System.exit(1);
}
}
} |
图 3 显示了运行 run 目标时应当会看到的输出:
图 3. Ant 构建 run 任务
您可以检查生成的 out.xml 文件,查看它与 清单 3 所示的初始输入之间的匹配程度。除了名称空间声明和属性顺序以及输出中添加的 total 属性(由测试程序计算和设置)之外,两个文档应当完全相同。情况不会永远是这样!像大多数形式的数据绑定一样,JiBX 只处理文档中的 “重要” 数据(意味着应用程序所使用的那些值)。在解组文档时,文档的不重要部分(例如开始或结束标记内的空白,元素之间的文本及注释)将丢失。在本例中,输入文档和输出文档之所以如此相似,部分原因是 清单 4 中的代码把输出格式设为在每个元素嵌套级别使用两个空格的缩进,这与输入文档相匹配。
细心的读者会注意到,在输出文档的项目清单部分(如清单 5 所示)中,输入与输出之间似乎 存在一个很大的差异:
清单 5. 输出文档的项目清单
<item quantity="1" price="5.99">
<id>AC4983498512</id>
<description>Left-handed widget</description>
</item>
<item quantity="2" price="9.5">
<id>IW2349050499</id>
<description>Right-handed widget</description>
</item>
<item quantity="1" price="8.95">
<id>RC3000488209</id>
<description>High-speed MP3 rewinder</description>
</item>
|
如果将 清单 5 中用粗体显示的行与 清单 3 初始文档中的对应行相比较,您可以看到价格已经从 9.50 变为 9.5,小数点最后位的零被去掉了。可是,这并不是错误。价格值使用的表示是 float,并且根据 Java 和 XML 模式,小数点前面的零和后面的零对于 float 来说并不重要。
|