什么是XML
擴展標(biāo)記語言XML是一種簡單的數(shù)據(jù)存儲語言,,使用一系列簡單的標(biāo)記描述數(shù)據(jù),而這些標(biāo)記可以用方便的方式建立,,雖然XML占用的空間比二進(jìn)制數(shù)據(jù)要占用更多的空間,,但XML極其簡單易于掌握和使用。
XML與Access,Oracle和SQL Server等數(shù)據(jù)庫不同,,數(shù)據(jù)庫提供了更強有力的數(shù)據(jù)存儲和分析能力,,例如:數(shù)據(jù)索引、排序,、查找,、相關(guān)一致性等,XML僅僅是展示數(shù)據(jù),。事實上XML與其他數(shù)據(jù)表現(xiàn)形式最大的不同是:他極其簡單,。這是一個看上去有點瑣細(xì)的優(yōu)點,但正是這點使XML與眾不同,。
XML的簡單使其易于在任何應(yīng)用程序中讀寫數(shù)據(jù),,這使XML很快成為數(shù)據(jù)交換的唯一公共語言,雖然不同的應(yīng)用軟件也支持其它的數(shù)據(jù)交換格式,,但不久之后他們都將支持XML,,那就意味著程序可以更容易的與Windows、Mac OS, Linux以及其他平臺下產(chǎn)生的信息結(jié)合,,然后可以很容易加載XML數(shù)據(jù)到程序中并分析他,,并以XML格式輸出結(jié)果,。
XML的優(yōu)點
我們談到XML長于在不同的應(yīng)用程序之間交換數(shù)據(jù),XML文件也便于構(gòu)建小的數(shù)據(jù)庫,,不久以前,軟件都使用INI文件存儲配置信息,、用戶參數(shù)以及其他信息,,后來微軟引入了系統(tǒng)注冊表,接作微軟告訴我們不應(yīng)該再使用INI文件了,,從那時起Visual Basic對INI文件的支持被削弱了,。但不幸的是注冊表有幾個致命的缺點:不是簡單的文本文件,難于讀寫,、可能會變得龐大和緩慢,、如果注冊表不知何故出現(xiàn)問題,將有可能造成系統(tǒng)死機,。
將配置信息放在XML文件中可以避免這些問題,,甚至可以將XML文件設(shè)置為一個共享文件,這樣在不同的計算機上的用戶就可以共享數(shù)據(jù),,這是注冊表所不能比擬的,。
在被稱為下一代ASP的ASP.NET中可以在WEB頁中直接使用XML,你可以使用數(shù)據(jù)綁定控件直接綁定數(shù)據(jù)并自動顯示,。
當(dāng)然也可以不選擇XML,,使用文本文件、注冊表,、數(shù)據(jù)庫都可以完成XML所能完成的任務(wù),,XML只是你在數(shù)據(jù)存儲和恢復(fù)的另一種工具而已。
XML語法簡介
XML的語法非常的簡單,,XML文檔由節(jié)點組成,,使用打開和關(guān)閉節(jié)點描述標(biāo)記,在格式上與HTML標(biāo)記非常相似,,它們之間最大的不同是:XML中可以自由定義標(biāo)記名,。比如下面的標(biāo)記就描述了一個電話號碼:
<Phone>987-654-3210</Phone> |
而且不用聲明標(biāo)記名就可以使用。
開始和結(jié)束標(biāo)記必須相同,,XML是識別大小寫的,,所以標(biāo)記的大小寫也必須相同。比如上面的例子中以<Phone>標(biāo)記開始就必須以</Phone>標(biāo)記結(jié)束,,而不能是</phone>或</PHONE>
節(jié)點標(biāo)記中可以包含屬性,,比如下面的代碼中Phone節(jié)點包含屬性Type,其值為WorkFax:
<Phone Type="WorkFax">987-654-3210<Phone> |
如果不愿意在節(jié)點中包含一個值,,那么可以不需要結(jié)束標(biāo)記,,可以用在開始標(biāo)記的后面加一個斜線來結(jié)束節(jié)點,,在下面的例子中,Phone標(biāo)記的Number屬性就存儲了一個電話號碼,,所以就不需要一個結(jié)束標(biāo)記:
<Phone Type="WorkFax" Number="987-654-3210" /> |
XML文檔的結(jié)構(gòu)是一個樹形等級結(jié)構(gòu),。文檔必須有一個唯一的根結(jié)點,根節(jié)點包含所有其它節(jié)點,。下面我們舉一個較為完整的例子:
<Addresses> ?。糆ntry Type="Personal"> <FirstName>Andy</FirstName> ?。糒astName>Fickle</LastName> ?。糞treet>1234 Programmer Place</Street> <City>Bugsville</City> ?。糞tate>CO</State> ?。糧ip>82379</Zip> <Phone Type="Home">354-493-9489</Phone> ?。?Entry> ?。糆ntry Type="Work"> <FirstName>Betty</FirstName> ?。糒astName>Masterson</LastName> ?。糚hone Type="Work">937-878-4958</Phone> <Phone Type="WorkFax">937-878-4900</Phone> ?。?Entry> ... </Addresses> |
注意相似的節(jié)點不需要包含相同的信息,,例如第一個Entry節(jié)點包含了地址信息和家庭電話號碼,第二個Entry節(jié)點包含了Work和WorkFax電話號碼,,而沒有包含第一個Entry節(jié)點包含的信息,。
XML工具
如前面的例子顯示,XML語法是如此的簡單以至于你可以在很短的時間作一個XML解析器,,幸運的是你不必這樣做,,因為XML工具可以運行在各種平臺上,包括可以安裝了Visual Basic的Windows,。
正是這些L工具而不是XML本身使XML變得更強大和復(fù)雜,。不同的解析器使你可以某一時刻加載整個XML文檔或只加載某個節(jié)點,與此相反,,XML Writer 可以同時創(chuàng)建一個XML文檔和節(jié)點,。
DOM解析器使我們能夠很方便的加載、復(fù)制,、排序,、修改和存儲XML文件,遍歷節(jié)點獲得名稱或?qū)傩?,并給結(jié)果排序,。雖然他們的功能沒有真正的關(guān)系數(shù)據(jù)庫強大,,但DOM的這些特點依然非常有用。
XSD可以定義XML文檔的格式,,XSL擴展樣式單定義了怎樣將XML文檔轉(zhuǎn)換成其他可以在WEB瀏覽器中瀏覽的文件格式,,比如HTML文件。
這些工具實際上比XML本身更復(fù)雜,,所以所有講解XML的書籍都花了很大的篇幅解釋這些XML工具,。但這超出了本文的范圍,有興趣的讀者可以參考有關(guān)資料,。
Visual Basic.Net提供了使用XML、XSL以及其他XML工具的完整工具,。但不用等待VB.NET,,微軟XML核心服務(wù)(MSXML)版本4.0提供了從Visual Basic6.0加載和存儲XML文檔的工具。
在msdn.microsoft.com/xml/default.asp中下載最新版本的MSXML,,并安裝在計算機上,。在Visual Basic 6.0中使用Microsoft XML V4.0象引用其他對象一樣,首先在工程菜單中選擇引用菜單項,,選擇Microsoft V4.0,單擊OK,一切完成后就現(xiàn)在就可以在VB應(yīng)用程序中添加XML對象了,。
DOMDocument 類
文檔對象模型(DOM)使用了一系列相應(yīng)的對象描述了XML文檔的等級狀態(tài),DOMDocument類是一個描繪XML文檔的DOM結(jié)構(gòu)的MSXML類,。
DOMDocument類僅僅提供了很少的幾個有用的屬性和方法,。Load方法載入一個xml文件,loadxml方法將字符串作為xml數(shù)據(jù)添加到對象中,。例如,,下面的代碼就將一個小的xml文件添加到名為xml_document的文檔中。
Dim xml_document As New DOMDocument
xml_document.loadXML _ "<Person>" & vbCrLf & _ " <FirstName>Rod</FirstName>" & vbCrLf & _ " <LastName>Stephens</LastName>" & vbCrLf & _ "</Person>" |
DOMDocument的xml屬性返回文檔的xml描述,,可以顯示這些返回值看看這些文檔究竟是什么樣子,,也可以將它存儲為一個文件,但這完全不必要,,因為DOMDocument對象的save方法已經(jīng)自動將他們存儲了,。
DOMDocument對象的documentElement屬性表示文檔數(shù)據(jù)的根結(jié)點,通常情況下操作XML文檔都從這里開始,。
DOMDocument提供了幾種創(chuàng)建新節(jié)點的方法,。CreateElement方法為文檔創(chuàng)建一個新的元素節(jié)點,其他創(chuàng)建節(jié)點的方法有createAttribute, createProcessingInstruction, 和 createTextNode,,在這里就不一一介紹了,。
IXMLDOMNode類
IXMLDOMNode類描述了一個節(jié)點,該類提供了一系列用于搜索和操縱XML文檔的屬性和方法,。 selectSingleNode 方法用于搜索指定節(jié)點的后代,,用于搜索指定節(jié)點路徑的語言稱為XPATH,,XPATH非常棘手,本文就不詳細(xì)說明其規(guī)范了,。下面我們將介紹兩個對搜索子節(jié)點有特別有用并且簡單的方法,。
在給selectsingleNode方法中輸入子節(jié)點的名字,該方法將在節(jié)點的子節(jié)點進(jìn)行精確匹配搜索,。如果在輸入的字符串前面加上".//",,那么將搜索節(jié)點的全部后代。
‘ Search for a child node named "LastName." Set last_name_node = address_node.selectSingleNode("LastName")
‘ Search for any descendant named "LastName." Set last_name_node = address_node.selectSingleNode(".//LastName") |
下面列出了IXMLDOMNode對象的部分非常有用的屬性:
attributes.節(jié)點屬性集合
nodeName.節(jié)點的標(biāo)記名
nodeTypeString.節(jié)點的類型
ownerDocument.返回DOMDocument對象包含的節(jié)點
text.表示節(jié)點包含的文本內(nèi)容,。如果該節(jié)點包含其他節(jié)點,,那么text代表了所有節(jié)點的文本內(nèi)容的組合。
xml.給出了節(jié)點的xml內(nèi)容,,例如:"<FirstName>Rod</FirstName>".
ChildNodes集合包含了節(jié)點的子節(jié)點,。要給節(jié)點增加一個子節(jié)點,首先必須給使用DOMDocument對象的節(jié)點創(chuàng)建方法,,然后將這個新建的節(jié)點加入到父節(jié)點的childNodes集合中,。下面的代碼展示了創(chuàng)建一個新的子節(jié)點的子程序,并使用父節(jié)點的appendChild方法將其加入到父節(jié)點中:
‘ Add a new node to the indicated parent node. Private Sub CreateNode(ByVal indent As Integer, _ ByVal parent As IXMLDOMNode, ByVal node_name As String, _ ByVal node_value As String) Dim new_node As IXMLDOMNode
‘ Create the new node. Set new_node = parent.ownerDocument.createElement(node_name)
‘ Set the node‘s text value. new_node.Text = node_value
‘ Add the node to the parent. parent.appendChild new_node End Sub |
SaveValues 程序
現(xiàn)在我們可以使用XML創(chuàng)建一個簡單的程序(如圖1),,其值存儲到XML文件中,,在程序開始運行時,程序從VALUE.XML文件中加載數(shù)據(jù),,在程序運行結(jié)束時,,將程序中的現(xiàn)行值存入VALUE.XML文件中。 下面的代碼是顯示了VALUE.XML文件的結(jié)構(gòu):
<Values> ?。糉irstName>Rod</FirstName> ?。糒astName>Stephens</LastName> <Street>1234 Programmer Place</Street> ?。糃ity>Bugsville</City> ?。糞tate>CO</State> <Zip>80276</Zip> </Values> |
List1顯示了怎樣編寫SaveValues,,當(dāng)載入表單時,,form_load事件觸發(fā)LoadValues子程序。
LoadValues創(chuàng)建了一個名為xml_document的DOMDocument對象,,然后載入xml文件,,使用selectSingleNode方法查找名為values的節(jié)點,然后使用GetNodeValue方法獲得從value節(jié)點后代中得到的值,。
GetNodeValue使用value節(jié)點的selectSingleNode方法尋找目標(biāo)節(jié)點,,如果節(jié)點不存在函數(shù)將返回一個缺省值,如果找到這個節(jié)點GetNodeValue將返回該節(jié)點的text值。對于value.xml文件中的數(shù)據(jù)節(jié)點,,text僅僅是包含在節(jié)點中的文本內(nèi)容,。
當(dāng)窗體卸載時觸發(fā)form_unload事件,unload事件調(diào)用SaveValues子程序,。程序創(chuàng)建一個新的DOMDocument對象,,該對象創(chuàng)建一個新的名為value的節(jié)點,然后用文檔的appendChild方法將節(jié)點添加到文檔中,。
在創(chuàng)建所有新的節(jié)點后,,SaveValues調(diào)用DOMDocument‘s save方法存儲新的xml文件。
注意這個新的文件已經(jīng)覆蓋了舊文件,,使用DOMDocument對象無法部分改變XML文件,,可以加載XML文件,然后修改其中一部分,,然后保存文件,,但原文件將被完全覆蓋。這是一個小的缺陷,,但在這時可以使用其它程序進(jìn)行修改。
List1的最后一部分是CreateNode子程序,,CreateNode 為父節(jié)點創(chuàng)建一個新節(jié)點并同時給這個節(jié)點賦值,。在這個子程序中首先引用一個DOMDocument對象,然后使用該對象的createElement方法創(chuàng)建一個新的節(jié)點,。
createNode方法設(shè)置節(jié)點的text屬性,,然后將節(jié)點作為子節(jié)點添加到父節(jié)點中。
List1:
Option Explicit
Private m_AppPath As String
Private Sub Form_Load() ‘ Get the application‘s startup path. m_AppPath = App.Path If Right$(m_AppPath, 1) <> "" Then m_AppPath = m_AppPath & ""
‘ Load the values. LoadValues End Sub
Private Sub Form_Unload(Cancel As Integer) ‘ Save the current values. SaveValues End Sub
‘ Load saved values from XML. Private Sub LoadValues() Dim xml_document As DOMDocument Dim values_node As IXMLDOMNode
‘ Load the document. Set xml_document = New DOMDocument xml_document.Load m_AppPath & "Values.xml"
‘ If the file doesn‘t exist, then ‘ xml_document.documentElement is Nothing. If xml_document.documentElement Is Nothing Then ‘ The file doesn‘t exist. Do nothing. Exit Sub End If
‘ Find the Values section. Set values_node = xml_document.selectSingleNode("Values")
‘ Read the saved values. txtFirstName.Text = GetNodeValue(values_node, "FirstName", "???") txtLastName.Text = GetNodeValue(values_node, "LastName", "???") txtStreet.Text = GetNodeValue(values_node, "Street", "???") txtCity.Text = GetNodeValue(values_node, "City", "???") txtState.Text = GetNodeValue(values_node, "State", "???") txtZip.Text = GetNodeValue(values_node, "Zip", "???") End Sub
‘ Return the node‘s value. Private Function GetNodeValue(ByVal start_at_node As IXMLDOMNode, _ ByVal node_name As String, _ Optional ByVal default_value As String = "") As String Dim value_node As IXMLDOMNode
Set value_node = start_at_node.selectSingleNode(".//" & node_name) If value_node Is Nothing Then GetNodeValue = default_value Else GetNodeValue = value_node.Text End If End Function
‘ Save the current values. Private Sub SaveValues() Dim xml_document As DOMDocument Dim values_node As IXMLDOMNode
‘ Create the XML document. Set xml_document = New DOMDocument
‘ Create the Values section node. Set values_node = xml_document.createElement("Values")
‘ Add the Values section node to the document. xml_document.appendChild values_node
‘ Create nodes for the values inside the ‘ Values section node. CreateNode values_node, "FirstName", txtFirstName.Text CreateNode values_node, "LastName", txtLastName.Text CreateNode values_node, "Street", txtStreet.Text CreateNode values_node, "City", txtCity.Text CreateNode values_node, "State", txtState.Text CreateNode values_node, "Zip", txtZip.Text
‘ Save the XML document. xml_document.save m_AppPath & "Values.xml" End Sub
‘ Add a new node to the indicated parent node. Private Sub CreateNode(ByVal parent As IXMLDOMNode, _ ByVal node_name As String, ByVal node_value As String) Dim new_node As IXMLDOMNode
‘ Create the new node. Set new_node = parent.ownerDocument.createElement(node_name)
‘ Set the node‘s text value. new_node.Text = node_value
‘ Add the node to the parent. parent.appendChild new_node End Sub |
SaveValuesIndented 程序
雖然每個人都化了很大的精力去處理xml文檔,,使他們看上更容易些,,但xml工具一般都忽略了那些使xml文檔結(jié)構(gòu)明顯的空白和縮進(jìn),xml解析器也同樣忽略縮進(jìn)和空白,。
不幸的是我們例子也同樣忽略了這些縮進(jìn)和空白,,SaveValues創(chuàng)建了一個象下面那樣的xml文件,所有的代碼都在同一行中,。
<Values><FirstName>Rod</FirstName><LastName>Stephens</LastNa me><Street>1234 Programmer Place</Street><City>Bugsville</Ci ty><State>CO</State><Zip>80276</Zip></Values> |
VB.NET中包括了文本寫入類,,可以XML文檔規(guī)定格式。但MSXML重沒有這種功能,,所以如果需要以一種清晰的格式保存XML文件,,只能另行添加它的格式。
List2列出了程序SaveValuesIndented使用的代碼,,SaveValues子程序與上面例子中講的幾乎完全相同,,但他在創(chuàng)建value節(jié)點后同時給XML文檔創(chuàng)建了一個<value>標(biāo)記的新行。
然后SaveValues 調(diào)用CreateNode創(chuàng)建一個新的數(shù)據(jù)節(jié)點,但在這里它傳遞給CreateNode一個新的參數(shù),,這個參數(shù)表示這個新節(jié)點的縮進(jìn)方式,。
CreateNode
‘ Save the current values. Private Sub SaveValues() Dim xml_document As DOMDocument Dim values_node As IXMLDOMNode
‘ Create the XML document. Set xml_document = New DOMDocument
‘ Create the Values section node. Set values_node = xml_document.createElement("Values")
‘ Add a new line. values_node.appendChild xml_document.createTextNode(vbCrLf)
‘ Add the Values section node to the document. xml_document.appendChild values_node
‘ Create nodes for the values inside the ‘ Values section node. CreateNode 4, values_node, "FirstName", txtFirstName.Text CreateNode 4, values_node, "LastName", txtLastName.Text CreateNode 4, values_node, "Street", txtStreet.Text CreateNode 4, values_node, "City", txtCity.Text CreateNode 4, values_node, "State", txtState.Text CreateNode 4, values_node, "Zip", txtZip.Text
‘ Save the XML document. xml_document.save m_AppPath & "Values.xml" End Sub
‘ Add a new node to the indicated parent node. Private Sub CreateNode(ByVal indent As Integer, _ ByVal parent As IXMLDOMNode, ByVal node_name As String, _ ByVal node_value As String) Dim new_node As IXMLDOMNode
‘ Indent. parent.appendChild parent.ownerDocument.createTextNode(Space$(indent))
‘ Create the new node. Set new_node = parent.ownerDocument.createElement(node_name)
‘ Set the node‘s text value. new_node.Text = node_value
‘ Add the node to the parent. parent.appendChild new_node
‘ Add a new line. parent.appendChild parent.ownerDocument.createTextNode(vbCrLf) End Sub |
結(jié)論
本文僅僅揭示XML編程的表面,本文的例子中的涉及只是非常簡單的XML文件,,但你可以使用使用本文揭示的技術(shù)做更多的事情,,比如配置設(shè)置、表單位置,、以及其他信息,。XML已經(jīng)向前更進(jìn)一步的發(fā)展了,有了更復(fù)雜的數(shù)據(jù)層次,。對于更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),,在運行時可以更容易的使用MSXML對象來存取XML文件
|