XML應用與XGen實戰

來源:互聯網
上載者:User
xml 如今似乎任何的軟體開發都離不開XML支援人員,在圖形映像、資料庫、加密安全、軟體工程、網路教育、電子商務、語音技術上都有XML施展拳腳的地方,XML應用大潮已經來臨。 

XML工作小組創始會員C.M. Sperberg-McQueen認為:“XML最大的影響在於XML軟體大量興起:XML剖析器、XML程式語言庫、XSLT處理器、XSL FO處理器、資料庫接受XML—不只如此,還有網路瀏覽器也接受XML。”也正因為如此,IBM、微軟、SUN、惠普、Oracle等大公司紛紛進入這個市場。

在學會了XGen等對象綁定工具後,相信大家已經是躍躍欲試,希望立刻用XGen來實戰一下,體驗一下XML對象綁定的優勢。下面就介紹一下我經常用到的XML應用。

1. XML設定檔
每個系統可能都需要或大或小的設定檔,通過設定檔來初始化系統的參數,好處不用詳細介紹了。一般設定檔的格式有以下種:

1. window系統中ini格式檔案和Java語言中使用的Properties檔案

2. XML格式的檔案

3. 其他格式檔案

第一種類型的設定檔是純文字檔案,基本採用“key = value”的格式來記錄各種參數,便於手工書寫和閱讀。

基於XML Schema的XML檔案易於閱讀,並且能非常好的顯示各個元素之間的層次關係和約束關係。相對於ini檔案格式使用xml格式的設定檔有以下優點:

1.1. 配置具有層次性

1.2. 取值有效性檢查

1.3. 支援鏈表,枚舉,複雜資料類型

1.4. 設定檔可以嵌套

1.5. 結合XML Spy 等XML編輯工具編輯設定檔十分便捷

1.6. 存在大量第三方的XML對象綁定工具,並且功能強大、開發便捷。如Java語言版的XGen、JAXB,C++版工具 XBind

現在就使開始實踐使用XML作為程式使用的設定檔吧。

1.1. 設計XSD檔案(XML Schema)
XGen需要編譯的是XSD檔案,XSD檔案是用來描述指定類型的XML檔案的大綱檔案,是個純文字檔案。通過本文編輯工具就可以手工建立、編輯XSD檔案,但是通過一些XML編輯工具可以事半功倍的完成XSD編寫工作。我也用過一些XML編輯工具,但是只有XML SPY的功能最強大,並且使用非常方便。

XML Spy 的一些特性:

l 在編輯XML、XSD等檔案時具有提示輸入功能,可以非常方便的選擇。

l 同時具有XML檔案合法性校正功能,可以判斷Element值的取值是否符合schema的定義。

l 支援DTD和XSD互轉

l 提供XSD的範例XML執行個體檔案功能

l 同樣支援java,c++,c#的xml綁定,可以產生Java,c++和C#代碼,不要太強大哦!

通過XML Spy編寫AlertServer.xsd 檔案

<?xml version="1.0"?>

<xsd:schema targetNamespace="urn:com:lianchuang:smartsecurer:alert:config:configfile.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:com:lianchuang:smartsecurer:alert:config:configfile.xsd" elementFormDefault="qualified" attributeFormDefault="unqualified" >

<xsd:element name="Config" type="ConifgType"/>

<xsd:complexType name="ConifgType">

<xsd:sequence>

<xsd:element ref="Globe"/>

</xsd:sequence>

</xsd:complexType>

<xsd:element name="Globe" type="GlobeType"/>

<xsd:complexType name="GlobeType">

<xsd:sequence>

<xsd:element ref="AlertServer"/>

<xsd:element ref="VOManager" maxOccurs="unbounded"/>

</xsd:sequence>

</xsd:complexType>

<xsd:element name="AlertServer" type="AlertServerType"/>

<xsd:complexType name="AlertServerType">

<xsd:sequence>

<xsd:element name="ID" type="xsd:int"/>

<xsd:element name="Address" type="xsd:string" default="127.0.0.1" minOccurs="0"/>

<xsd:element name="Port" type="xsd:int" default="1099" minOccurs="0"/>

<xsd:element name="AlertServerName" type="xsd:string" minOccurs="0"/>

<xsd:element name="RegisterInterval" type="xsd:int" default="1000" minOccurs="0"/>

<xsd:element name="CacheSize" type="xsd:int" default="10000" minOccurs="0"/>

<xsd:element name="DeliverThreadNum" type="xsd:int" default="2" minOccurs="0"/>

<xsd:element ref="DBOperMode" default="Default" minOccurs="0"/>

<xsd:element name="BatchDBInsertSize" type="xsd:int" default="1000" minOccurs="0"/>

<xsd:element name="StatisticsInterval" type="xsd:int" default="1000" minOccurs="0"/>

</xsd:sequence>

</xsd:complexType>

<xsd:element name="VOManager" type="VOManagerType"/>

<xsd:complexType name="VOManagerType">

<xsd:sequence>

<xsd:element name="Address" type="xsd:string"/>

<xsd:element name="Port" type="xsd:int" default="1099" minOccurs="0"/>

</xsd:sequence>

</xsd:complexType>

<xsd:element name="DBOperMode">

<xsd:simpleType>

<xsd:restriction base="xsd:string">

<xsd:enumeration value="Default"/>

<xsd:enumeration value="Native"/>

</xsd:restriction>

</xsd:simpleType>

</xsd:element>

</xsd:schema>



注意 <xsd:schema> 設定

elementFormDefault="qualified" attributeFormDefault="unqualified" 屬性

,否則在unmarshal(InputStream ,valid)方法調用中會有異常。這樣設定表示限制局部元素和屬性,即對每個局部的元素都要設定首碼。

當將 elementFormDefault 設定為 qualified 時,它表示在該文法的執行個體中,必須使用首碼或通過設定 {預設命名空間} 來顯式限定所有元素。unqualified 設定意味著只有全域聲明的元素才必須被顯式限定,而局部聲明的元素不得被限定。在此情形下,限定一個局部聲明是錯誤的。同樣,將 attributeFormDefault 設定為 qualified 時,必須使用首碼顯式限定執行個體文檔中的所有屬性。

1.2. 建立Java對象
進入xgen安裝目錄,為了省事將AlertServer.xsd檔案拷貝到該目錄下。執行以下指令碼:

xgen AlertServer.xsd

在目前的目錄下,會按照urn 路徑產生 com\lianchuang\smartsecurer\alert\config\configfile_xsd 目錄,並且新建立的class檔案就儲存在該目錄下。若在XSD中定義了自訂複雜類型資料,則會在 configfile_xsd

目錄下建立 \type 目錄,並把相關的Java Class 放在該目錄下。

1.3. 編寫代碼
對於定義XSD文檔,每個複雜類型的ElementA,會有ElementA和ElementATypeComplexType類來作為該Java類的映射,通過getElementATypeComplexType()方法直接可以擷取擷取ElementA的複雜物件類型的引用。

如在XSD檔案中的Globe,可以通過XXX.getConifgTypeComplexType().getGlobe()來擷取該Java對象,通過config.getConifgTypeComplexType().getGlobe().getGlobeTypeComplexType()來擷取實際的該類型的對象。

對於一些基本類型Element。XGen定義了一些X開頭的類與之對應,如int,用XInt表示。可以通過new XInt(int i)來構造XInt對象。

// 下面是讀取指定的設定檔,返回 Java 對象的代碼

public static synchronized Config getConfig(String fileName) throws

FileNotFoundException

{

// 建立InputStream對象

File file = new File(fileName);

FileInputStream ins = new FileInputStream(file);



ChainedEntityResolver er = new ChainedEntityResolver();

Unmarshaller un = new Unmarshaller(er);

GlobalElement ge = null;

try

{

ge = un.unmarshal(ins, false); // 注意,由於本人對XML和XSD也是一知半解,unmarshal的方法嘗試了一遍,只有使用這個方法,才可以正常轉化xml檔案的對象。不知道為什麼…



if (ge != null && ge instanceof Config)

configInstance = (Config) ge;

}

catch (ValidationException ex)

{

m_log.error(ex);

}

catch (MarshalException ex)

{

m_log.error(ex);

}

catch (IOException ex)

{

m_log.error(ex);

}

return configInstance;

}

// 下面是列印對象各個屬性參數的範例代碼

public static void printConfig(Config config)

{

if (config == null)

return;

m_log.debug("================ AlertServer Parameters ==================");

m_log.debug("ID = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().getAlertServer().

getAlertServerTypeComplexType().getID());

m_log.debug("Address = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().

getAlertServer().getAlertServerTypeComplexType().getAddress());

m_log.debug("Port = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().

getAlertServer().getAlertServerTypeComplexType().getPort());



m_log.debug("AlertServerName = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().getAlertServer().

getAlertServerTypeComplexType().getAlertServerName());

m_log.debug("RegisterInterval = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().getAlertServer().

getAlertServerTypeComplexType().getRegisterInterval());

m_log.debug("DeliverThreadNum = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().

getAlertServer().getAlertServerTypeComplexType().

getDeliverThreadNum());

m_log.debug("CacheSize = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().getAlertServer().

getAlertServerTypeComplexType().getCacheSize());

m_log.debug("BatchDBInsertSize = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().getAlertServer().

getAlertServerTypeComplexType().getBatchDBInsertSize());



m_log.debug("================= VOManager Parameters ==================");

for (int i = 0;

i <

config.getConifgTypeComplexType().getGlobe().getGlobeTypeComplexType().

getVOManagerCount();

++i)

{

m_log.debug("VOManger Address = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().getVOManager()[i].

getVOManagerTypeComplexType().getAddress());

m_log.debug("VOManger Port = " +

config.getConifgTypeComplexType().getGlobe().

getGlobeTypeComplexType().getVOManager()[i].

getVOManagerTypeComplexType().getPort());

}

}

2. 利用XML格式的訊息通訊
編寫自訂Socket通訊程式時,都需要自己定義一套通訊協定的規範,尤其是異構的系統。我們可以使用xml文檔作為通訊協定,結合XML相關的對象綁定工具來將XML格式的報文轉換為Java、C++等語言的對象。

下面以Java語言結合XGen使用範例描述通訊的流程。

2.1. 通訊流程
l 發送XML對象

通過程式建立相關的對象,並賦值。通過unmarshal方法轉化為StringWriter對象,使用StringWriter的getBuffer().toString()方法返迴轉化好的字串。最後,利用socket發送該String。

l 接收XML對象

接收到XML文檔後,marshal到Java對象即可。

2.2. 具體技術
l 通訊中加密

由於通過XML文檔進行通訊,資料包是明文的文本,對於一些敏感性資料需要進行適當的加密。如直接對XMLw文檔上進行DES然後傳遞,或者根據情況採用更安全的加密方式。

l 發送XML文檔

// UDP Socket

DatagramSocket discoverySocket = null;

// 發送的資料包

DatagramPacket dgp = null;

// 將XML對象轉化StringWriter對象,即轉化為字串對象

StringWriter sw = new StringWriter();

// XML綁定對象

request req = null;

// 需要發送的字元數組

byte[] sendBytes = null;

……

……

try

{

// 建立XML文檔對象

req = XMLObjAnalysis.makeRequset(m_agentDisc.m_configFileName,

getDiscoverRespSeqNo(),

XMLObjAnalysis.DISCOVERY_REQUEST);



sw.getBuffer().setLength(0);

// 將請求對象序列化為xml字串

req.getRequestTypeComplexType().setRequestAgentIp(new XString(

agentKey.getRequestIp()));

req.marshal(sw);

// 將XML文檔通過DES加密

sendBytes = getDESBytes(sw.getBuffer().toString().

getBytes(), true);

if (sendBytes != null)

{

dgp = new DatagramPacket(sendBytes, sendBytes.length);

dgp.setAddress(ia);

dgp.setPort(agentKey.getPort());

m_log.debug("Send discovery pdu :" + agentKey.getRequestIp() +

":" +

agentKey.getPort() + ",size =" +

sendBytes.length);

// m_log.debug(new String(sw.getBuffer()));

discoverySocket.send(dgp);

}

}

catch (Exception ex4)

{

m_log.error(ex4);

}



l 接收XML文檔



inGram =

new DatagramPacket

(inBuffer, inBuffer.length);

try

{

for (; ; )

{

try

{



inSock.receive(inGram);

}

catch (IOException ex)

{

m_log.error

("ERROR reading input socket:"

+ ex.getMessage());

// break;

}

catch (Exception ex)

{

ex.printStackTrace();

try

{

Thread.sleep(100);

}

catch (InterruptedException ex2)

{

}

// return;

continue;

}

recvBytes = new byte[inGram.getLength()];

System.arraycopy(inGram.getData(), 0, recvBytes, 0, inGram.getLength());

dealAgentMessage(recvBytes, hostName);



}

}

finally

{

if (inSock != null)

inSock.close();

}



private void dealAgentMessage(final byte[] origRecvBytes)

{

BasicInfo resp = null;

// 解密XML文檔

byte[] recvBytes = m_agentDisc.getDESBytes(origRecvBytes, false);

// 將 encoding 標籤改為gb2312,這樣可以分析出元素中的中文,否則,無法正確轉化為中文

String orig = new String(recvBytes);

orig = orig.replaceAll("encoding=\"UTF-8\"", "encoding=\"gb2312\"");

// 將字串轉化為 ByteArrayInputStream

ByteArrayInputStream bais = new ByteArrayInputStream(orig.trim().

getBytes());

try

{

// 將XML文檔轉換為對象

resp = XMLObjAnalysis.getResponseFromXMLStream(bais);

}

catch (Exception ex1)

{

m_log.error(ex1);

}



String requestAgentIp = resp.getBasicInfoTypeComplexType().

getRequestAgentIp().get();

if (resp == null)

{

m_log.error("Decode reponse error.Ip = " + requestAgentIp);

return;

}



// 判斷是否是代理自動探索的響應資料

if (resp.getBasicInfoTypeComplexType().getResponse().

getResponseChoiceComplexType().getAutoDiscoveryAsChoice() != null)

{

……

}

else if (resp.getBasicInfoTypeComplexType().getResponse().

getResponseChoiceComplexType().getHealthCheckAsChoice() != null)

{

……

}

}





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.