一个使用Apache SDO处理XML数据的例子(2)
三、记录处理XML数据的变化
我们可以利用在SDO中定义的ChangeSummary机制来跟踪订购单的变化。为了实现我们的第二个目的,我们先来编辑一个这个XML的schema文件po_orginal.xsd。代码如下:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" <xsd:import namespace="commonj.sdo/xml" <xsd:complexType name="PurchaseOrderType"> |
这个被导入的sdo.xsd定义了ChangeSummaryType。我们在PurchaseOrderType中加一个ChangeSummaryType的元素。我们可以将这个元素命名为任何东西,当然,除了使用“changes”。
为了使用新的schema,我们需要使用Util类的definePOTypes()方法来装载它。我们将要保存被CreatePO.java产生的XML文件为po.xml。这个文件和po_original.xml比较得知,po.xml在<po:purchaseOrder>: <changes logging="false" />中有一个新的子元素。ProcessPO.java类处理订购单。当运行时,程序保存了这个处理过程,并在po_processed.xml中产生了一条变化记录。po_processed.xml的代码如下:
<?xml version="1.0" encoding="ASCII"?> <po:purchaseOrder xmlns:po="http://www.example.com/PO" orderDate="1999-10-20"> <shipTo country="US"> <name>Alice Smith</name> <street>123 Maple Street</street> <city>Mill Valley</city> <state>CA</state> <zip>90952</zip> </shipTo> <billTo country="US"> <name>Alice Smith</name> <street>8 Oak Avenue</street> <city>Mill Valley</city> <state>PA</state> <zip>95819</zip> </billTo> <po:comment>Hurry, my lawn is going wild!</po:comment> <items> <item partNum="872-AA"> <productName>Lawnmower</productName> <price>148.95</price> <quantity>1</quantity> <po:comment>Confirm this is electric</po:comment> </item> <item partNum="926-AA"> <productName>Baby Monitor</productName> <price>39.98</price> <quantity>2</quantity> <shipDate>2007-11-21</shipDate> </item> <item partNum="999-AA"> <productName>Armed Chair</productName> <price>299.95</price> <quantity>1</quantity> <po:comment>Make sure the cover is leather.</po:comment> </item> </items> <changes create=" ##//items/item[3]" delete=" ##//changes/items[1]/item[3]" logging="false" xmlns:sdo="commonj.sdo"> <billTo sdo:ref=" ##//billTo"> <name>Robert Smith</name> </billTo> <item sdo:ref=" ##//items/item[2]"> <quantity>1</quantity> </item> <items sdo:ref=" ##//items"> <item sdo:ref=" ##//items/item[1]" /> <item sdo:ref=" ##//items/item[2]" /> <item partNum="998-AA"><productName>Carpet</productName><price>439.98</price><quantity>1</quantity><shipDate>2007-12-01</shipDate></item> </items> </changes> </po:purchaseOrder> |
上面的代码显示了XML文件的变化记录,但是我们更感兴趣的是<changes>元素,这个元素现在变得更复杂了。这个元素捕捉了订购单的所有的变化。基本这些变化,应用程序可以恢复以前的未变化的数据。
现在让我我们看一下ProcessPO.java类,并分析一个SDO如何允许我们获得这样详细的变化数据。
1. 注释1中在运行时转载了po.xml。
2. 注释2建立了和purchaseOrder数据对象相关的ChangeSummary对象。
3. 为了跟踪变化,注释3打开了ChangeSummary对象的日志功能。
4. 在注释4中,日志是关闭的,purchaseOrder的所有变化和它的子数据对象在ChangeSummary对象中被捕捉。
5. 在注释5中输出了结果,我们可以看看Util类中的printChangeSummary方法,代码如下:
public static void printChangeSummary(ChangeSummary chngSum) { if (chngSum == null) { System.out.println("ChangeSummary is not in existence!"); return; } for (Iterator it = chngSum.getChangedDataObjects().iterator(); it.hasNext();) { DataObject changedObject = (DataObject) it.next(); System.out.println(); if (chngSum.isCreated(changedObject)) {//is the changed object newly created System.out.println("Created: " + changedObject); if (changedObject.getContainer()!=null){ System.out.println("\t--- to be contained in : " + changedObject.getContainer().getType().getName() + " ---"); }else{ System.out.println("\t--- created object has no container --- "); } printAnnotatedDataObject("newly created",changedObject, 2); } else if (chngSum.isDeleted(changedObject)) { System.out.println("Deleted: " + changedObject); if (chngSum.getOldContainer(changedObject) != null){ System.out.println("\t--- originally contained in : " + chngSum.getOldContainer(changedObject).getType().getName() + " ---"); }else{ System.out.println("\t--- deleted object has no container ---"); } // a potential bug in Tuscany SDO, this shows nothing in ProcessPO.java printAnnotatedDataObject("deleted",changedObject, 2); // drill down to deleted property System.out.println("\t--- deleted property information --- "); // a potential bug in Tuscany SDO, this section shows nothing in ReviewPO.java for (Iterator settingIt = chngSum.getOldValues(changedObject).iterator(); settingIt.hasNext();) { printDeletedProperty((ChangeSummary.Setting) settingIt.next()); } System.out.println("\t--- deleted property information --- "); } else if (chngSum.isModified(changedObject)) { System.out.println("Updated: " + changedObject); // print out the updated object printAnnotatedDataObject("after update", changedObject, 2); // drill down to changed property System.out.println("\t--- property update information --- "); for (Iterator settingIt = chngSum.getOldValues(changedObject).iterator(); settingIt.hasNext();) { ChangeSummary.Setting changeSetting = (ChangeSummary.Setting) settingIt.next(); printUpdatedProperty(changeSetting, changedObject,chngSum); } System.out.println("\t--- property update information --- "); } else System.out.println("Should never come here!"); } } |
在这个方法中,我们首先使用了getChangedDataObjects()来获得所有变化了的数据对象,然后按着他们的种类处理,即建立、删除或编辑。如果数据对象是新建的,我们会打印对象的信息和所有的属性。
在下一部分,我们来浏览被编辑的订购单。
四、通过一个不同的实体浏览数据的变化
XML数据处理的第三部分需要完成两个任务:
1. 程序需要按着编辑顺序打印出主要的信息。
2. 显示处理阶段所有的修改记录。
当我们可以更进一步根据着一个记录变化阶段编辑订购单时,这部分显示了如何使用ReviewPO.java调用所有的编辑记录。ReviewPO.java的代码如下:
package com.company.sdo.po; import java.io.FileInputStream; import java.util.List; import commonj.sdo.ChangeSummary; import commonj.sdo.DataObject; import commonj.sdo.helper.XMLDocument; import commonj.sdo.helper.XMLHelper; public class ReviewPO { public static void main(String[] args) throws Exception { Util.definePOTypes(); FileInputStream fis = new FileInputStream(Constants.PO_PROCESSED_XML); //1. 装载要处理的订购单 XMLDocument xmlDoc = XMLHelper.INSTANCE.load(fis); DataObject purchaseOrder = xmlDoc.getRootObject(); //2. 显示被编辑的订购单的信息 System.out.println(); System.out.println("---received purchase order information---"); System.out.println("Order date: " + purchaseOrder.get("orderDate")); System.out.println("Order comment: " + purchaseOrder.get("comment")); DataObject shipTo = purchaseOrder.getDataObject("shipTo"); System.out.println("Ship to name: "); Util.printDataObject(shipTo,1); DataObject billTo = purchaseOrder.getDataObject("billTo"); System.out.println("Bill to name: "); Util.printDataObject(billTo,1); DataObject items = purchaseOrder.getDataObject("items"); List itemList = items.getList("item"); System.out.println("Ordered items: "); for (int i = 0; i < itemList.size(); i++) { DataObject item = (DataObject) itemList.get(i); System.out.println("\tItem " + (i+1) + " :" ); Util.printDataObject(item,2); } //3. 显示了第二阶段的数据变化 System.out.println(); System.out.println("---review changes in purchase order ---"); ChangeSummary chngSum = purchaseOrder.getChangeSummary(); Util.printChangeSummary(chngSum); //4. 取消第二阶段的所有变化 System.out.println(); System.out.println("---action taken after reviewing the changes---"); System.out.println("\t###undo all changes###"); chngSum.undoChanges(); //5. 编辑订购单的原始版本 System.out.println(); System.out.println("---changes made in purchase order review---"); chngSum.beginLogging(); billTo.set("name", "Alice Smith"); chngSum.endLogging(); //6. 将新的变化输出到系统控制台 Util.printChangeSummary(chngSum); //7. 将改变记录保存到一个XML文件中 Util.storeXML(purchaseOrder,"purchaseOrder", Constants.PO_REVIEWED_XML); } } |
要注意的是第二个任务不同于在前一部分打印ChangeSummary,在这里printout是直接基于ChangeSummary的。变化细节在运行时被重新装载。我们可以通过比较这两个printout来分辨它们的不同。在上一部分,printDataObject()在删除项时什么都没产生,而是调用了printDeletedProperty()来列出它们的属性和它们的值。在当前的printout中,恰恰相反。
在程序的其他部分,注释4通过调用undoChanges方法取消了在第二阶段的所有的变化,注释5对订购单做了一些小的变化。我们可以看看保存变化记录的文件(po_reviewed.xml)来验证这些操作结果。