http://dev2dev.bea.com.cn/techdoc/20060713845.html
XMLBEANS 2.0 —— 一位JAVA開發(fā)人員的視點
時間:2006-07-13
作者:Jacob
Danner, Raj Alagumalai
瀏覽次數(shù):
4546
本文關(guān)鍵字:XMLBeans, Apache, XmlCursor, XPath, XQuery, Open
Source, Dev
Toolbox, XML, Jacob
Danner, 開源 |
|
摘要
隨著面向服務(wù)架構(gòu)的出現(xiàn),大部分用戶不得不在應(yīng)用程序中使用XML。在開發(fā)過程中,用戶可能已經(jīng)注意到存在多種可以分析和處理XML的模型,包括開源和專有的。所有這些模型都存在一定的優(yōu)缺點。選擇不適合業(yè)務(wù)需求的模型可能會導(dǎo)致開發(fā)時間延長并浪費資源。Apache
XMLBeans是一個非常有價值的工具,它提供一種在Java中使用XML的簡便方法。在本文中,我們將介紹XMLBeans以及XMLBeans
2.0中的一些有用特性。
XMLBeans簡介
W3C XML Schema是一個XML文檔,該文檔定義一組其他XML文檔必須遵守才合法的規(guī)則。與早期XML模式語言如文檔類型定義(document
type definition,DTD)或簡單對象XML(simple object XML,SOX)相比,W3C XML
Schema具有許多優(yōu)點,它還提供了可供用戶以多種方式使用的豐富特性集。
XMLBeans是完全與模式兼容的XML-Java綁定工具,使用這個工具可以以對Java友好的方式訪問XML的全部特性。XMLBean解決方案是獨一無二的,因為它提供XML數(shù)據(jù)的雙重視圖。XMLBeans維護(hù)一個信息和結(jié)構(gòu)均未更改的原始XML文檔,并提供一個基于Java的XML數(shù)據(jù)視圖。
現(xiàn)在我們通過顯示一些代碼示例來演示XMLBeans
2.0中的一些特性。在每個示例中,我們都會提供模式以及一些操縱模式的XMLBean表示的Java代碼。模式和Java示例都可供下載。
下面我們來看下面的模式片斷:
1 <xs:element name="order">
2 <xs:complexType>
3 <xs:sequence>
4 <xs:element name="orderNo" type="xs:string"/>
5 <xs:element name="item" nillable="true"
6 maxOccurs="unbounded" type="tns:itemType"/>
7 <xs:element name="address" type="tns:addressType"/>
8 <xs:element name="quantity" type="tns:quantityType"/>
10 </xs:sequence>
11 </xs:complexType>
12 </xs:element>
要生成XMLBeans類,需要對模式進(jìn)行編譯。使用scomp實用工具可以很輕松地完成這個任務(wù),因為它可以為所有簡單和復(fù)雜的類型生成接口。所有類和接口的包名均派生自模式中指定的targetNamespace值。詳細(xì)情況請閱讀Hetal
Shah的Configuring
XMLBeans(中文版,Dev2Dev,2005年3月)。
現(xiàn)在我們看看如何生成實例文檔,如何針對模式檢查文檔的有效性,以及如何將實例保存到文件系統(tǒng)。
下面所生成的OrderDocument接口是一個XMLBeans為任意全局元素或類型創(chuàng)建的特殊“文檔”類型示例。
AddressType和ItemType是為全局復(fù)雜類型addressType和sizeType創(chuàng)建的接口:
1 OrderDocument orderDoc = OrderDocument.Factory.newInstance();
2 Order order = orderDoc.addNewOrder();
3 order.setOrderNo("ORD1234");
4 order.setQuantity(4);
5
6 AddressType aType = order.addNewAddress();
7 aType.setCity("Kirkland");
8
9 ItemType iType = order.addNewItem();
10 iType.setId("ITEM003");
11
12 boolean isValid = orderDoc.validate(xopt);
13
14 orderDoc.save(new File("sample.xml"),xopt);
運行此示例會導(dǎo)致構(gòu)建一個實例文檔,該文檔將被驗證并以“sample.
xml”為名保存在本地文件系統(tǒng)中。該程序還會將此實例文檔的內(nèi)容以及驗證測試的結(jié)果顯示到命令提示符或Unix shell中:
1 <sam:order xmlns:sam="http://temp.openuri.org/Sample">
2 <sam:orderNo>ORD1234</sam:orderNo>
3 <sam:item>
4 <sam:id>ITEM003</sam:id>
5 <sam:description>Latest Item</sam:description>
6 <sam:size>Large</sam:size>
7 </sam:item>
8 <sam:address>
9 <sam:Name>BEA Systems, Inc</sam:Name>
10 <sam:Street>10230 NE Points Drive, Ste 300</sam:Street>
11 <sam:City>Kirkland</sam:City>
12 <sam:Zip>98033</sam:Zip>
13 <sam:State>WA</sam:State>
14 <sam:Country>USA</sam:Country>
15 </sam:address>
16 <sam:quantity>4</sam:quantity>
17 </sam:order>
這是一個有效的實例文檔。在編譯一個模式時,從模式生成的API會與表示底層XML模式的XMLBeans類型系統(tǒng)相集成。對模型相關(guān)信息的訪問權(quán)限可通過使用模式類型系統(tǒng)API獲取。
在下一個示例中,我們將展示如何使用getEnumerationValues()方法編程式地訪問特定模式類型的多個枚舉值。我們使用的模式類型是sizeType,它是帶有三個可能值的枚舉類型。該模式片斷如下所示:
1 <xs:simpleType name="sizeType">
2 <xs:restriction base="xs:token">
3 <xs:enumeration value="Small"/>
4 <xs:enumeration value="Medium"/>
5 <xs:enumeration value="Large"/>
6 </xs:restriction>
7 </xs:simpleType>
SizeType是SchemaType類,它包含關(guān)于simpleType模式類型的信息:
SchemaType schType = null;
XmlAnySimpleType [] xmlarray = null;
SizeType sType = SizeType.Factory.newInstance();
schType = sType.schemaType();
xmlarray = schType.getEnumerationValues();
運行此代碼示例(EnumerationSample.java)將導(dǎo)致編程式地獲取枚舉值并將其重定向到System.out:
Enumeration values for ItemType :
Small
Medium
Large
XmlCursor是XMLBeans中的一個有趣特性;它們提供一種操作或?qū)Ш絏ML實例文檔的直觀方法。XmlCursor還提供了一種執(zhí)行XQuery表達(dá)式的方法。一旦加載了XML文檔,就可以創(chuàng)建一個游標(biāo)來表示XML中的特定位置。因為用戶可以使用具有或不具有對應(yīng)于XML的模式的游標(biāo),因此游標(biāo)是處理XML的理想方法。
下一個示例演示如何使用游標(biāo)操作XMLBean實例。此示例分析在第一個示例中創(chuàng)建的sample.xml。一旦將該文件保存到內(nèi)存中,就會使用XmlCursor
API導(dǎo)航到quantity元素并將值更改為104:
orderDoc = OrderDocument.Factory.parse(new File("sample.xml"));
XmlCursor xcursor = orderDoc.newCursor();
xcursor.toFirstChild();
xcursor.toChild(3);
xcursor.toEndToken();
xcursor.toPrevChar(1);
xcursor.insertChars("10");
xcursor.disp ose();
運行此示例會生成下面的輸出,它顯示修改后的XMLBean文檔為什么會無效:
Message: decimal
value (104) is greater than maxInclusive facet (5) for
quantityType in namespace http://temp.openuri.org/Sample
Location of invalid XML:
<xml-fragment xmlns:sam="http://temp.openuri.org/Sample"/>
到目前為止,我們已經(jīng)簡要介紹了XMLBeans,現(xiàn)在介紹一下2.0版本中的新特性。
XMLBeans 2.0中的新特性
通常,通過觀察產(chǎn)品的實際運行來了解其中的新特性是比較簡便的方法。我們將通過介紹一個利用了XMLBeans的某些重要特性的項目來介紹這些新特性。眾所周知,XMLBeans是一個Apache項目,所以它使用Atlassian的Jira問題跟蹤和項目管理應(yīng)用程序來跟蹤bug、特性和其他問題。BEA對XMLBeans項目進(jìn)行了投資,并擁有一個提供高質(zhì)量軟件的標(biāo)準(zhǔn)。這意味著BEA很關(guān)注XMLBeans之類項目的質(zhì)量。由于XMLBeans是開源項目,并且它使用Apache的常見工具如Jira,所以問題就在于BEA如何跟蹤XMLBeans的質(zhì)量指標(biāo)。
用于揭示XMLBeans 2.0中的一些新特性的計劃就是對這個問題的回答:如何方便地從Jira收集質(zhì)量指標(biāo)?
下面的屏幕快照顯示了XMLBeans的項目主頁面。請看圖片的右邊,在Project
Summary區(qū)域下可以看到一些與我們關(guān)心的質(zhì)量指標(biāo)問題相關(guān)的選項。

圖1:XMLBeans
Jira項目頁面(單擊圖像查看大圖)
Jira的一個好處就是它能提供問題數(shù)據(jù)的不同視圖。在下圖中,請看名為Current
View的標(biāo)題。在屏幕快照中,目前選擇的是Browser視圖,但還有其他選項,包括一個打印視圖、一個XML視圖,甚至還有一個Excel電子表格視圖:

圖2:XMLBeans
Jira Issue Navigator(單擊圖像查看大圖)
熟悉Jira以及XMLBeans跟蹤質(zhì)量指標(biāo)的方式后,我們可以通過多種方式收集質(zhì)量指標(biāo)。我們的選項包括屏幕抓取HTML、分析電子表格以及從URL獲取XML。我們認(rèn)為最合理的是從URL(通過從Issue
Navigator頁面單擊XML鏈接而提供)使用XML視圖。該URL的內(nèi)容看起來與下面的XML文檔類似:
<?xml version="1.0" encoding="utf-8" ?>
<!-- RSS generated by JIRA 98 at Sun Dec 04 18:08:34 CET 2005
-->
<rss version="0.92">
<channel>
<title>ASF JIRA</title>
<link>http://issues.apache.org/jira</link>
<description>This file is an XML representation of some
issues</description>
<language>en</language>
<item>
<title>[XMLBEANS-232] Fast Xml Infoset</title>
<link>http://issues.apache.org/jira/browse/x</link>
<description>
<!-- left out for brevity -->
</description>
<environment><![CDATA[]]></environment>
<key id="12326193">XMLBEANS-232</key>
<summary>Fast Xml Infoset</summary>
<type id="4">Improvement</type>
<priority id="3">Major</priority>
<status id="1">Open</status>
<resolution>Unresolved</resolution>
<assignee>Unassigned</assignee>
<reporter username="rrusin">Rafal
Rusin</reporter>
<created>Wed, 30 Nov 2005 13:29:44 +0100
(CET)</created>
<updated>Sat, 3 Dec 2005 18:15:10 +0100
(CET)</updated>
<version>unspecified</version>
<fixVersion>unspecified</fixVersion>
<component>XmlObject</component>
<due></due>
<votes>0</votes>
<comments>
<comment author="dandiep" created="Sat, 3 Dec 2005
18:15:10 +0100 (CET)" level="">
<!-- ... -->
</comment>
</comments>
<customfields>
</customfields>
</item>
<item>
<!-- left out for brevity -->
</item>
</channel>
</rss>
如果從上面的XML feed查看片斷,會發(fā)現(xiàn)它被定義為RSS feed。我們的第一步是找到一個RSS 0.92版本的XML
Schema模式,這樣就可以編譯模式,并通過使用XMLBeans的類似于JavaBean的簡單API來使用XMLBeans分析URL。我們無法找到官方模式,但可以找到規(guī)范,并可由此開始創(chuàng)建模式。隨后,我們發(fā)現(xiàn)根據(jù)規(guī)范創(chuàng)建的模式與從Jira獲取的RSS
feed不匹配。我們該怎么做呢?我們實際上惟一可以選擇的就是為此RSS
feed創(chuàng)建一個模式,但這費時且容易出錯。進(jìn)行了進(jìn)一步的調(diào)查后,我們偶然發(fā)現(xiàn)了新增的inst2xsd特性。
模式到實例再到模式的過程
inst2xsd工具可作為命令行實用工具使用,但用戶也可以編程式地使用API。其目的是采用一個XML實例并創(chuàng)建一個合法模式集。該工具也是可配置的,它提供了用于指定使用哪種設(shè)計模式的選項(包括Russian
Doll、Salami Slice、Venetian Blind;詳細(xì)信息請參見模式設(shè)計指導(dǎo)原則)。
該工具還能夠?qū)⒚杜e映射到重復(fù)值,并能夠根據(jù)數(shù)據(jù)類型的最小公分母創(chuàng)建類型。
我們使用lcd:val這個值作為創(chuàng)建最小公分母類型的示例。該文本可由多個內(nèi)置XML
Schema數(shù)據(jù)類型表示,例如字符串派生的類型(xsd:string、xsd:normalizedString、xsd:token,等等)以及QName類型。在本例中,inst2xsd特性確定類型的方式是查找前綴為lcd的命名空間聲明。如果找到該前綴,該類型將是QName,而不是某個可能基于字符串的類型。
現(xiàn)在看一下我們從Jira接收的RSS
feed的結(jié)果是什么。如果我們已經(jīng)將feed保存到名為jiraRssFeed.xml的實例中并已將XMLBEANS_HOME\bin放在我們的路徑中,工作流將如下:
/home/user>inst2xsd
Generates XMLSchema from instance xml documents.
Usage: inst2xsd [opts] [instance.xml]*
Options include:
-design [rd|ss|vb] - XMLSchema design type
rd - Russian Doll Design - local elements and local types
ss - Salami Slice Design - global elements and local
types
vb - Venetian Blind Design (default) - local elements and
global complex types
-simple-content-types [smart|string] - Simple content types
detection (leaf text). Smart is the default
-enumerations [never|NUMBER] - Use enumerations. Default
value is 10.
-outDir [dir] - Directory for output files. Default is '.'
-outPrefix [file_name_prefix] - Prefix for output file names.
Default is 'schema'
-validate - Validates input instances against generated
schemas.
-verbose - print more informational messages
-license - print license information
-help - help information
/home/user>inst2xsd jiraRssFeed.xml -enumerations never
-design rd -verbose -validate
# this generates a schema named schema0.xsd
這將生成名為schema0.xsd的(可配置)文件,并且模式將與下面的片斷類似:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
3 <xs:element name="rss">
4 <xs:annotation>
5 <xs:documentation>RSS generated by JIRA 98...
</xs:documentation>
6 </xs:annotation>
7 <xs:complexType>
8 <xs:sequence>
9 <xs:element name="channel">
10 <xs:complexType>
11 <xs:sequence>
12 <xs:element type="xs:string" name="title"/>
13 <xs:element type="xs:anyURI" name="link"/>
14 <xs:element type="xs:string" name="description"/>
15 <xs:element type="xs:string" name="language"/>
15 <xs:element name="item" maxOccurs="unbounded"
minOccurs="0">
從這個片斷中我們發(fā)現(xiàn)Jira RSS feed所需的所有元素均已定義。
如果用戶想要通過其他方式工作,例如從XML
Schema開始,XMLBeans的最新版本就提供了這種功能。xsd2inst工具就為用戶提供了從模式和全局元素創(chuàng)建示例文檔的方式;該實例將包含簡單類型的值。上述兩種工具的使用使得使用XML實例和模式變得非常簡單。
在項目的這個階段,我們就擁有了一個模式,使用這個模式可以通過scomp實用工具創(chuàng)建一個XMLBeans類型jar,并可開始處理業(yè)務(wù)邏輯以及先前嘗試收集的質(zhì)量指標(biāo)。
通過查看Jira RSS
feed實例,我們發(fā)現(xiàn)我們關(guān)注的bug詳細(xì)信息放在名為item的元素中,而且生成的模式將item元素作為數(shù)組。這意味著,如果我們想要獲得可能出現(xiàn)在所有項中的信息,就需要迭代所有項。現(xiàn)在我們看看如何通過一些代碼實現(xiàn)這個目標(biāo)。在下面的代碼中,我們會遇到名字被指定為方法參數(shù)的用戶導(dǎo)致的所有問題:
1 public Vector getItemsFromReporter(String reporter) {
2
3 // Get the Jira RSS feed instance from a URL
4 URL jiraFeedUrl; = new URL("");
5
6 // Get instance objects
7 RssDocument rssDoc = RssDocument.Factory.parse(jiraFeedUrl);
8 RssDocument.Rss rss = rssDoc.getRss();
9 RssDocument.Rss.Channel channel = rss.getChannel();
10
11 // We will use this object to get most of our data
12 RssDocument.Rss.Channel.Item[] items = channel.getItemArray();
13
14 //We will store all of the valid results in a vector
15 Vector results = new Vector();
16
17 for (int i = 0; i < items.length; i++) {
18 RssDocument.Rss.Channel.Item item = items[i];
19
20 //Add item to results vector when reporter == username
21 if(item.getReporter().getUsername().compareTo(reporter) == 0)
22 results.add(item);
23 }
24 }
25
26 return results;
27 }
可以看出,這是非常整潔的Java代碼。但是,當(dāng)項數(shù)變大時,使用此代碼也會影響性能。在最新的XMLBeans版本中,新增了兩個新特性來幫助解決這些問題。第一個特性是對JDK
5.0泛型的支持,第二個特性是對XPath和Xquery的支持。我們來看看如何將泛型用于XMLBeans。
將泛型用于XMLBeans
很明顯,JDK 5.0泛型可幫助創(chuàng)建參數(shù)化的類和方法。Collections API是XMLBeans中首批使用泛型的API之一。在XML
Schema中,當(dāng)元素包含的maxOccurs屬性的值大于1時,默認(rèn)情況下XMLBeans將針對這些類型創(chuàng)建一個Java數(shù)組。為了啟用泛型,需要將一個附加參數(shù)添加到scomp,并需要使用一個兼容JDK
5.0的虛擬機。
默認(rèn)情況下,用于從channel獲取item元素的API包含如下方法:
|
RssDocument.Rss.Channel.Item |
getItemArray(int i)
獲取item元素 |
RssDocument.Rss.Channel.Item[] |
getItemArray()
獲取所有item元素的數(shù)組 |
void |
setItemArray(int i,RssDocument.Rss.Channel.Item
item)
設(shè)置item元素 |
void |
setItemArray(RssDocument.Rss.Channel.Item[]
itemArray)
設(shè)置所有item元素的數(shù)組 |
但是,執(zhí)行了啟用泛型的編譯步驟后,API會有所變化:
/home/user>scomp
Compiles a schema into XML Bean classes and metadata.
Usage: scomp [opts] [dirs]* [schema.xsd]* [service.wsdl]*
[config.xsdconfig]*
Options include:
...
-javasource [version] - generate java source compatible for a
Java version (1.4 or 1.5)
...
#This is all it takes to enable Generics in your use of XMLBeans
/home/user>scomp -javasource 1.5 schema0.xsd
使用上面的示例,可用的新方法將如下所示:
java.util.List<RssDocument.Rss.Channel.Item> |
getItemList
獲取item元素的列表 |
現(xiàn)在我們來看看泛型的使用如何能夠簡化用于實現(xiàn)獲取單個用戶報告的所有項的方法的代碼:
1 public List- getItemsFromReporter(String reporter) {
2
3 // We already loaded the data as above
4 // ...
5 RssDocument.Rss.Channel channel = rss.getChannel();
6
7 // We will use this object to get most of our data
8 List<RssDocument.Rss.Channel.Item> items =
channel.getItemList();
9
10 for (int i = 0; i < items.size(); i++) {
11 RssDocument.Rss.Channel.Item item = items.get(i);
12
13 //Remove results from list
14 if (item.getReporter().getUsername().compareTo(reporter)
!= 0)
15 items.remove(i);
16 }
17 }
18
19 return items;
20 }
這種方法非常不錯,但還有一種更加簡單的獲取每個用戶的項信息的方法——當(dāng)您了解XPath和/或XQuery之后。
XQuery和XPath
XMLBeans與XQuery和XPath的集成在2.0版本中有了變化。版本1中使用了Jaxen(一種XPath實現(xiàn)),但與XMLBeans的集成不支持命名空間和前綴。最新版本構(gòu)建于Saxon
8.1.1版本所提供的XQuery實現(xiàn)的基礎(chǔ)之上。由于XQuery在Xpath之上構(gòu)建,所以Saxon還為XMLBeans提供了XPath實現(xiàn)。為了使用XQuery和XPath的特性,XmlObject類(所有XMLBeans類型都派生自它)提供了兩個執(zhí)行實例的查詢和語句的方法。XmlObject
API的execQuery()和selectPath()方法返回一個匹配組件的數(shù)組。這些方法在XmlCursor對象上也存在,但返回對象是使用匹配值列表填充的另一個XmlCursor對象:
1 String xq = "for $e in //employee
where $e/name='Bob' return $e ";
2
3 // Input is a valid xml instance
4 XmlObject o = XmlObject.Factory.parse(input);
5
6 XmlObject[] xObjres = o.execQuery(xq);
7 XmlCursor xCurres = o.newCursor.selectPath(xq);
從上面的代碼片斷中可以看出API相當(dāng)易用,而且您可以采取最方便的方式處理生成的數(shù)據(jù)。我們在第4行中構(gòu)建了自己的查詢語句,并在第6和第7行中使用不同的API運行該查詢。XQuery是一個強大的工具,從下面的代碼中可以看出獲取項數(shù)據(jù)變得多么簡單:
1 public XmlObject[] getItemsFromReporter(String reporter) {
2
3 //Load Jira RSS feed data
4 URL jiraFeedUrl; = new URL("");
5
6 //This is the only object we need
7 RssDocument rssDoc = RssDocument.Factory.parse(jiraFeedUrl);
8
9 //Build the statement for the xpath engine
10 String xpathStatement =
"http://item[reporter/@username='"+reporter+"']";
11
12 //Execute the statement on the instance
13 //We could cast this to an Item[] if we wanted
14 XmlObject[] queryResult = rssDoc.selectPath(xpathStatement);
15
16 return queryResult;
17 }
將XQuery與XMLBeans同時使用將使其如虎添翼,使對XML的處理變得簡單得多。如果要獲取更多有關(guān)XQuery的信息,有無數(shù)的資源可供參考。我們建議從Apache
XMLBeans Web站點上的XMLBeans示例開始。
到此時,由于XMLBeans提供的最新特性,XMLBeans的質(zhì)量指標(biāo)跟蹤問題解決方案實現(xiàn)起來已經(jīng)非常容易了。我們使用inst2xsd實用工具為實例創(chuàng)建模式,而不用從頭編寫,從而節(jié)省了時間。我們可以看到泛型的啟用如何通過使業(yè)務(wù)邏輯變得容易編寫而提高了生產(chǎn)力。最后,我們看到新增的XQuery集成如何提供操縱和查詢XML的豐富特性。
這些僅僅是最新版本的XMLBeans中的基本新特性。一些其他特性使得XMLBeans成為可滿足處理XML時的所有開發(fā)需要的理想工具。而下一個特性提供有關(guān)使用XML和XML
Schema時可能接收到的錯誤的更詳細(xì)信息,從而幫助開發(fā)人員提高生產(chǎn)力。
錯誤代碼
錯誤代碼是2.0版本中提供的另一個偉大特性。人們已創(chuàng)建了許多種方法,以便將這個新特性與scomp之類的工具集成,并允許編程式地訪問以便(比如說)在IDE中使用。XML
Schema規(guī)范的附錄C定義了一個錯誤代碼集,它定義了非法模式條款。在分析、驗證和編譯過程中,可使用錯誤監(jiān)聽程序編程式地訪問錯誤代碼。以前,錯誤消息的詳細(xì)信息和模式一致性是越小越好。此外,還添加了有關(guān)錯誤所在位置以及模式規(guī)范中的相關(guān)內(nèi)容的詳細(xì)信息。錯誤代碼本身以“cvc-complex-type.2.2”的形式定義,可參見http://www.w3c.org/TR/xmlschema-1/#cvc-complex-type條款2.2中的解釋。下面我們來看看它的工作方式。我們從一個XML
Schema開始,并針對它驗證一個實例。然后我們將查看舊的錯誤,并與接收到的最新版本進(jìn)行比較。
1 <!-- errorcode.xsd -->
2 <xs:schema
3 xmlns:xs="http://www.w3.org/2001/XMLSchema"
4 targetNamespace="http://xmlbeans.rocks.com/"
5 xmlns:tns="http://xmlbeans.rocks.com/" >
6 <xs:element name="address" type="tns:address"/>
7 <xs:complexType name="address">
8 <xs:sequence>
9 <xs:element name="number" type="xs:unsignedInt"/>
10 <xs:element name="street" type="xs:string"/>
11 <xs:choice>
12 <xs:sequence>
13 <xs:element name="city" type="xs:string"/>
14 <xs:element name="state" type="xs:string"/>
15 </xs:sequence>
16 <xs:element name="zipcode" type="xs:int"/>
17 </xs:choice>
18 <xs:element name="country" type="xs:string"/>
19 </xs:sequence>
20 </xs:complexType>
21 </xs:schema>
這個模式相當(dāng)簡單。注意xs:choice模型組的用法,因為下面的示例正是在對其進(jìn)行定義時出錯的。我們將要介紹一些錯誤代碼,您很快就可以發(fā)現(xiàn)問題所在:
1 <!-- errorcode.xml -->
2 <t:address
3 xmlns:t="http://xmlbeans.rocks.com/" >
4 <number>72</number>
5 <street>156th NE</street>
6 <country>USA</country>
7 </t:address>
除了可從命令行使用的scomp實用工具,還存在一個可針對模式驗證實例的實用工具。
/home/user>validate
Validates the specified instance against the specified schema.
Contrast with the svalidate tool, which validates using a stream.
Usage: validate [-dl] [-nopvr] [-noupa] [-license]
schema.xsd instance.xml
Options:
-dl - permit network downloads for imports and
includes (default is off)
-noupa - do not enforce the unique particle attribution rule
-nopvr - do not enforce the particle valid (restriction) rule
-partial - allow partial schema type system
-license - print license information
如果使用XMLBeans的1.0版本運行validate實用工具,結(jié)果將如下所示:
/home/user>validate errorcode.xsd errorcode.xml
errorcode.xml:0: error: Expected elements
city zipcode at the end of the content in element
address@http://xmlbeans.rocks.com/
上面的錯誤文本提到了實例的名稱,并告訴我們地址的末尾缺少一些應(yīng)有的元素。在這個小示例中,這是有點用處的,但沒有行號很難找到起點。現(xiàn)在我們將這個代碼文本與新版本中的新增錯誤代碼特性進(jìn)行比較:
/home/user>validate errorcode.xsd errorcode.xml
errorcode.xml:4: error: cvc-complex-type.2.4a: Expected elements
'city state' instead of 'country' here in element
address@http://xmlbeans.beaworld.com/
errorcode.xml:4: error: cvc-complex-type.2.4c: Expected elements
'zipcode' before the end of the content in element
address@http://xmlbeans.beaworld.com/
與XMLBeans的1.0版本中的錯誤文本相比,新的錯誤文本有很大的改進(jìn)。兩個錯誤文本都提到了實例,但新錯誤代碼還提供了行號、問題嚴(yán)重程度、附錄C模式參考以及更清楚的錯誤消息。而且,使用新的錯誤代碼,我們發(fā)現(xiàn)錯誤代碼cvc-complex-type.2.4a和cvc-complex-type.2.4c還提及更多造成故障的問題。同樣,這些錯誤代碼也分別對應(yīng)于模式規(guī)范中一個可使用URL訪問的位置。
剛剛我們介紹了如何通過命令行獲取詳細(xì)的錯誤文本,現(xiàn)在介紹如何以編程方式獲取錯誤信息:
1 // Create the error listener and XmlOptions
2 LinkedList list = new LinkedList();
3 XmlOptions opts = new XmlOptions().setErrorListener(list);
4
5 // Load the instance
6 File instance = new File("<SOME_PATH>\errorcodes.xml");
7 AddressDocument ad = AddressDocument.Factory.parse(instance);
8
9 // If there are errors, making a method call like this will
10 // populate the error listener
11 ad.validate(opts);
12
13 // Since we know there are errors, let's
14 // look at how to get at the data
15 for(int i=0; i < errors.size(); i++) {
16
17 // Cast list object to an XmlError
// type XmlError e = (XmlError)
18 errors.get(i);
19
20 // Now, let's get at all the information about the error
21 // This will be the location of the error in the instance
22 System.out.println("["+e.getLine()+","+e.getColumn()+"]-" +
e.getSeverity())
23 // Information about the error
24 System.out.println(e.getErrorCode() + ": " +e.getMessage());
25 }
請看此代碼片斷,以編程方式訪問錯誤信息并不比從命令行獲取類似信息困難多少。
性能提升
用戶可能不會注意到以前的特性,但一定會注意到它對開發(fā)工作的影響。如果新版本無法帶來性能提升,那它還有什么好處呢?
與在XMLBeans
1.0中一樣,性能對于2.0版本極為重要。在大多數(shù)情況下,與1.0相比,2.0版本性能有了10%到60%的提升。導(dǎo)致性能提升的原因有許多,其中最重要的是完全不同的存儲架構(gòu)。在1.0版本中,使用了一個名為splay
tree的數(shù)據(jù)結(jié)構(gòu)使所有存儲在XML Store中的內(nèi)容與影響XML數(shù)據(jù)的操作同步。對于不熟悉它的用戶,splay tree可以理解為支持O(log
N)次Find、Insert和Delete操作的平衡樹。這種數(shù)據(jù)結(jié)構(gòu)與其他此類樹的差別在于它不維持顯式的平衡條件。其詳細(xì)程度超出了用戶在大多數(shù)情況下的需要。2.0版本使用了一個較為簡單的架構(gòu),提供較少的復(fù)制和較少的對象。
在對XML數(shù)據(jù)執(zhí)行任何操作時,XMLBeans都會加載一個XML Store。XMLBeans總是加載一個XML
Store,然后在Store上提供一個綁定視圖。與直接解組到Java對象的其他Java/XML綁定框架相比,此綁定視圖與完整的XML
Infoset真實性通常導(dǎo)致額外的開銷。這使得XMLBeans的性能一直是一個障礙,從而消弱了額外的特性與信息所帶來的好處。對于運行時性能,人們主要關(guān)注的就是XML
Store方面,并盡可能地使Store的性能得到提高。
在對XML Store進(jìn)行改寫時,新增了一個特性,該特性使得使用XMLBeans進(jìn)行編程可以有更好的性能,并且更易于使用。此特性即DOM Level
II支持。DOM是Document Object Model(文檔對象模型)的簡寫,它提供了一個用于處理XML數(shù)據(jù)的接口。Level
II則指定哪些接口是可用的。它與SAX的區(qū)別在于XML信息保存在內(nèi)存中。
固有的DOM II支持
在1.0版本中,對DOM的訪問由Xerces處理,因此此類調(diào)用返回一個Xerces DOM Node。在2.0中,類似調(diào)用返回XMLBeans
DOM表示,因為DOM II現(xiàn)在是天然實現(xiàn)的。這意味著在XMLBeans內(nèi)無需協(xié)調(diào)兩種不同的數(shù)據(jù)存儲即可訪問DOM表示和XMLBeans表示。
這還意味著可以通過以下三種方式中的任何一種來處理XML。第一種方式是使用XmlObject
API中JavaBean風(fēng)格的方法。第二種方式是通過XMLCursor API使用基于令牌的模型。而第三種方式是使用對熟悉DOM
API的人來說非常熟悉的樹模型。它有一個特別的好處,就是用戶可以在這些方法之間來回切換,而不必?fù)?dān)心實例的同步問題。從開發(fā)人員的角度來看,這就意味著他們可以使用最順手的方式來處理XML。現(xiàn)在我們來了解一些可以在其中進(jìn)行切換以便獲得XML的底層視圖的API:
//To get the live DOM Node:
Node XmlObject.getDomNode()
Node XmlCursor.getDomNode()
//To get back:
XmlObject XmlBeans.nodeToObject(Node n)
XmlCursor XmlBeans.nodeToCursor(Node n)
//XMLBeans 1.0 API returns a copy:
Node XmlObject.newDomNode()
從上面的代碼中可以看出,在這些視圖之間進(jìn)行切換相當(dāng)容易。
結(jié)束語
本文介紹了XMLBeans
2.0中可用的一些新特性。我們了解到XMLBeans提供了一個健壯且完全保真的Java到XML的綁定框架。我們還介紹了如何使用XMLBeans
2.0的一些新特性更方便快捷地完成項目。這些新特性可以提高開發(fā)人員的生產(chǎn)力。性能提升也有助于提高生產(chǎn)力,但更重要的是,這意味著花在對應(yīng)用程序進(jìn)行調(diào)試和分析瓶頸上的時間將會減少。
我們介紹的特性只是XMLBeans的最新版本所提供的一部分增強。請了解一下XMLBeans,看它是如何幫助改進(jìn)開發(fā)人員的開發(fā)工作的。
參考資料
原文出處:http://dev2dev.bea.com/pub/a/2006/05/xmlbeans-2.html
作者簡介 |
|
Jacob Danner
是BEA的高級軟件工程師。他自2001年BEA的WebLogic
Workshop團(tuán)隊建立時起就一直在其中工作。他還曾參與BEA的多項開源工作。 |
|
Raj Alagumalai
是BEA Systems的WebLogic Workshop支持部門的一名高級開發(fā)人員關(guān)系工程師。 |