本文給出了一個使用apache sdo處理xml數據的例子。由于sdo現在還不是處理xml的標準的解決方案,因此,本文還討論了sdo中的基本的操作xml數據的方法。
跟蹤數據的變化在很多軟件、應用程序和商業場景中是一個基本的要求。如果要嚴格地實現這個需求是非常困難的,這主要是因為對文件的不同變化建模,并監視這些變化一般很難做到。從另一方面講,在所有的程序中反復地實現這種功能要比將一個單獨的模塊應用到不同的應用程序中更經濟實用。而服務數據對象(sdo),這個由bea和ibm定義的異構數據訪問解決方案,為開發人員提供了更容易實現的機制來從系統層跟蹤數據的變化。
一、處理xml數據的三個階段
在本文給出的處理xml的例子分為三個不同的階段,這些階段如下:
1. 建立
2. 處理
3. 瀏覽
xml數據可以通過一個文件系統在這三個階段之間進行傳輸。在本例的中心場景如下:第二步需要記錄xml文件在第一階段被建立的記錄,當第三步瀏覽xml數據時,人們總希望知道這個文件有哪些變化。如果我們使用word的跟蹤特性,我們將會立即獲得這些變化的值。
許多應用程序都有這些需求,包括實現并發控制、離線應用程序的同步,商業進程管理(bpm)系統。這部分將演示sdo如何幫助我們更容易地實現這些需求。
本文提供的xml數據是一個訂購數據,代碼如下:
<?xml version="1.0" encoding="utf-8"?> <xsd:import namespace="commonj.sdo/xml" schemalocation="sdo.xsd"/> <xsd:complextype name="purchaseordertype"> <xsd:complextype name="usaddress"> <xsd:simpletype name="sku"> |
createpo.java類完成了建立xml的工作。代碼如下
package com.company.sdo.po; import commonj.sdo.dataobject; import commonj.sdo.helper.datafactory; public class createpo { public static void main(string[] args) throws exception { //1. 使用xsd定義類型和屬性 util.definepotypes(); //2. 建立根dataobject dataobject purchaseorder = datafactory.instance.create(constants.po_namespace, "purchaseordertype"); //3. 設置根dataobject的數據類型屬性 purchaseorder.setstring("orderdate", "1999-10-20"); //4. 建立子dataobject dataobject shipto = purchaseorder.createdataobject("shipto"); //5. 設置子dataobject的數據類型屬性 shipto.set("country", "us"); shipto.set("name", "alice smith"); shipto.set("street", "123 maple street"); shipto.set("city", "mill valley"); shipto.set("state", "ca"); shipto.setstring("zip", "90952"); dataobject billto = purchaseorder.createdataobject("billto"); billto.set("country", "us"); billto.set("name", "robert smith"); billto.set("street", "8 oak avenue"); billto.set("city", "mill valley"); billto.set("state", "pa"); billto.setstring("zip", "95819"); purchaseorder.set("comment", "hurry, my lawn is going wild!"); dataobject items = purchaseorder.createdataobject("items"); //6. 為子dataobject “item”建立一個子dataobject dataobject item1 = items.createdataobject("item"); item1.set("partnum", "872-aa"); item1.set("productname", "lawnmower"); item1.setint("quantity", 1); item1.setstring("price", "148.95"); item1.set("comment", "confirm this is electric"); dataobject item2 = items.createdataobject("item"); item2.set("partnum", "926-aa"); item2.set("productname", "baby monitor"); item2.setint("quantity", 1); item2.setstring("price", "39.98"); item2.setstring("shipdate", "2007-11-21"); dataobject item3 = items.createdataobject("item"); item3.set("partnum", "998-aa"); item3.set("productname", "carpet"); item3.setint("quantity", 1); item3.setstring("price", "439.98"); item3.setstring("shipdate", "2007-12-01"); //7. 將xml數據保存在一個xml文件中 util.storexml(purchaseorder,"purchaseorder", constants.po_xml); } } |
1. 使用xsd定義類型和屬性;由于我們的數據是基于xml格式的,因此,我們首先需要在運行時定義sdo類型的屬性。這個功能由util類的definepotypes()方法完成。在definepotypes方法內部調用了xsdhelper類。definepotypes()方法的代碼如下:
public static void definepotypes() throws exception { fileinputstream fis = new fileinputstream(po_model_original); xsdhelper.instance.define(fis, null); fis.close(); } |
2. 建立根數據對象:sdo的動態api可以通過數據對象的層次和屬性或是一個datagraph(包含了數據對象元數據的一個圖)來描述結構化數據。sdo提供了用于建立一個未連接的數據對象的datafactory接口。
3. 設置根數據對象的數據類型屬性:訂購單在sdo中是一個類型,并且根據schema,它有一個叫orderdate的數據類型屬性,這是一個日期類型。
4. 建立子數據對象:數據對象訂購單有一些子數據對象。例如,上面代碼中的注釋4在purchaseorder中建立shipto子結點。除了這種方法,我們還可以使用datafactory來建立一個未連接的shipto數據對象,并使用setdataobject方法將他設置成purchaseorder的一個子結點。代碼如下:
dataobject shipto = datafactory.instance.create(constants.po_namespace, "usaddress");
......
purchaseorder.setdataobject("shipto", shipto);
5. 設置子對象結點的數據類型屬性:基于usaddress類型的定義,shipto數據對象有不同的數據類型屬性。上面注釋5建立了這些屬性。
6. 為子數據對象“item”建立一個子數據對象:這部分顯示了建立xml時sdo數據模型。
在下一部分將討論如何使用sdo的動態api,我們可以編輯訂購單,并且在同時跟蹤他們的變化。
|||
三、記錄處理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)來驗證這些操作結果。
新聞熱點
疑難解答