VB和VB.NET中的XML操作

来源:岁月联盟 编辑:zhu 时间:2007-01-31
   

  概述:这篇文章为计划将他们的应用程序更新到Visual Basic.NET的微软Visual Basic 开发用户提供一些关于XML的建议。主要包括Visual Basic 6和Visual Basic.NET对XML操作的不同之处,以及Visual Basic.NET关于这方面新增工具的应用。 概述:这篇文章为计划将他们的应用程序更新到Visual Basic.NET的微软Visual Basic 开发用户提供一些关于XML的建议。主要包括Visual Basic 6和Visual Basic.NET对XML操作的不同之处,以及Visual Basic.NET关于这方面新增工具的应用。

  扩展标记语言XML是一种简单的数据存储语言,使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立。XML的简单使其易于在任何应用程序中读写数据,这使XML很快成为数据交换的唯一公共语言,可以说,“没有XML,就没有编程的未来”。

  XML主要应用在以下几个方面:

  1. 设计标记语言,如CML,MathML, WML等。

  2. 数据交换和数据整合,这是XML最激动人心的应用。

  3. 媒体无关的数据发布

  4. 智能代理和本地计算

  5. 精确搜索

  6. 文件保值

  XML的语法非常的简单,XML文档由节点组成,使用打开和关闭节点描述标记,在格式上与HTML标记非常相似,它们之间最大的不同是:XML中可以自由定义标记名。比如下面的标记就描述了一个主页地址:

  <web>http://tech.ddvip.com</web>

  注意,XML不用声明标记名就可以使用,而且,开始和结束标记必须相同,XML是识别大小写的,所以标记的大小写也必须相同。

  节点标记中可以包含属性,比如:

  <web type=”Homepage”>http://tech.ddvip.com</web>   

  代码中Web节点包含属性Type,其值为Homepage.

  如果不愿意在节点中包含一个值,那么可以不需要结束标记,可以用在开始标记的后面加一个斜线来结束节点,在下面的例子中,Web标记的属性就存储了一个电话号码,所以就不需要一个结束标记:

  <web type=”Homepage” url=”http://tech.ddvip.com” />  

  以上只是对XML文档的简单描述,如何使用文档中包含的信息,XML标准体系中有其他的配套标准。

  XSL(可扩展样式表语言)是对CSS的一种扩展,功能比CSS强大得多。XML链接是在HTML链接的功能之上加以扩展,可以支持更为复杂的链接,通过XML链接,不仅可以在XML文件之间建立链接,还可以建立其他类型数据之间的链接,其规范分为三个部分:XLink语言,XPointer语言和XML Base.

[责任编辑:editor]

   

  XML标准体系中还有其他很多技术,比如针对DTD的不足而提出的XML Schema,对XML文档进行结构话处理的DOM等,由于篇幅的关系,在这就不一一列举,不熟悉的请参考有关书籍。

  好了,现在让我们开始进入正题——对XML的操作。首先,请保证您的电脑中有最新版本的MSXML,微软XML核心服务(MSXML)版本4.0提供了从Visual Basic6.0加载和存储XML文档的工具。若没有,请到http://msdn.microsoft.com/xml/default.asp中下载最新版本的MSXML,并安装在计算机上。在Visual Basic 6.0中使用Microsoft XML V4.0对象引用其他对象一样,首先在工程菜单中选择引用菜单项,选择Microsoft V4.0,单击OK,一切完成后就现在就可以在VB应用程序中添加XML对象了。如图:

  万事俱备,我们先用VB和MSXML的COM接口的DOM实现的一个例子来对XML操作进行初步的了解吧。

  首先声明下面要用的几个对象的变量:

  Dim tempdoc As DOMDocument
Dim tempnode As IXMLDOMNode
Dim tempelement As IXMLDOMElement
Dim tempattribute As IXMLDOMElement
Dim root As IXMLDOMElement

  文档对象模型(DOM)使用了一系列相应的对象描述了XML文档的等级状态,DOMDocument类是一个描绘XML文档的DOM结构的MSXML类。DOMDocument类仅仅提供了很少的几个有用的属性和方法,例如:Load方法载入一个xml文件,loadxml方法将字符串作为xml数据添加到对象中。DOMDocument的xml属性返回文档的xml描述,可以显示这些返回值看看这些文档究竟是什么样子,也可以将它存储为一个文件,DOMDocument对象的documentElement属性表示文档数据的根结点,通常情况下操作XML文档都从这里开始。DOMDocument提供了几种创建新节点的方法。CreateElement方法为文档创建一个新的元素节点,其他创建节点的方法有createAttribute, createProcessingInstruction, 和 createTextNode,在这里就不一一介绍了。

[责任编辑:editor]

   

  IXMLDOMNode类描述了一个节点,该类提供了一系列用于搜索和操纵XML文档的属性和方法。selectSingleNode 方法用于搜索指定节点的后代,用于搜索指定节点路径的语言称为XPATH,XPATH非常棘手,本文就不详细说明其规范了。在IXMLDOMNode对象中,有许多有用的属性值:

  attributes.节点属性集合

  nodeName.节点的标记名

  nodeTypeString.节点的类型

  ownerDocument.返回DOMDocument对象包含的节点

  text.表示节点包含的文本内容。如果该节点包含其他节点,那么text代表了所有节点的文本内容的组合。

  xml.给出了节点的xml内容,例如:"<Email>hongwanfu@yahoo.com</Email>".

  ChildNodes集合包含了节点的子节点。要给节点增加一个子节点,首先必须给使用DOMDocument对象的节点创建方法,然后将这个新建的节点加入到父节点的childNodes集合中。 ChildNodes集合包含了节点的子节点。要给节点增加一个子节点,首先必须给使用DOMDocument对象的节点创建方法,然后将这个新建的节点加入到父节点的childNodes集合中。

  由于每个节点类型都有不同的访问方法和内容限制,有时候使用特定类型的节点要比使用通用 IXMLDOMNode 对象更容易。要做到这一点,需要使用 IXMLDOMElement 对象来处理 XML 数据元素和属性。正如元素可以包含 XML 数据文件中的子元素、文本、注释、处理说明、CDATA 部分和实体引用一样,IXMLDOMElement 对象也可以包含 IXMLDOMElement、IXMLDOMText、IXMLDOMComment、IXMLDOMProcessingInstruction、IXMLDOMCDATASection 和 IXMLDOMEntityReference 对象。可以通过使用 IXMLDOMElement 对象的 getAttribute 和 setAttribute 方法来访问属性;或者通过 IXMLDOMElement 对象的 attributes 属性,将属性作为 IXMLDOMNamedNodeMap 对象进行管理。有关使用这些方法和对象的详细信息,请参阅 MSXML 4.0 SDK Help。

  接下来我们要做的是生成一个XML DOMDocument 对象 :

  Set tempdoc = New DOMDocument

  生成根节点并把它设置为文件的根 :

  Set root = tempdoc.createElement("Personal")
Set tempdoc.documentElement = root

  生成孩子节点添加到根节点上去,并且为这个节点设置一个属性 :

  Set tempnode = tempdoc.createNode(NODE_ELEMENT, "Web", "")
tempnode.Text = " http://tech.ddvip.com "
root.appendChild tempnode

[责任编辑:editor]

   

  取得元素节点的接口,添加属性:

  Set tempelement = tempnode
tempelement.setAttribute "Type", "Homepage"

  最后,写XML文件:

  Open "CreateXMLFile.xml" for output as #1
Print #1, root.XML
Close #1

  下面就是上面程序生成的CreateXMLFile.xml文件的内容如图:

  熟悉了如何用Visual Basic 6创建XML文件,接下来,我们将编写一个程序,使得程序开始运行时,程序从XML文件中加载数据,在程序运行结束时,将程序中的现行值存入XML文件中。

  首先,建立一个名叫Personal.xml的文件:

  <?xml version="1.0" encoding="GB2312"?>
<个人信息>
<姓名>洪万福</姓名>
<性别>男</性别>
<出生日期>1983年x月x日</出生日期>
<地址>福建省厦门市集美大学水产学院新区270#</地址>
<邮编>361021</邮编>
<QQ>24948251</QQ>
<个人主页>http://tech.ddvip.com</个人主页>
</个人信息>

  其中,encoding="GB2312"是为了防止显示中文时出现乱码。

  接着,进入Visual Basic 6,建立7个Label和7个TextBox, 具体如图:

  随后,编写如下代码:

[责任编辑:editor]

   

  Option Explicit
Private p_AppPath As String
Private Sub Form_Load()
 ' 获得程序运行目录
 p_AppPath = App.Path
 If Right$(p_AppPath, 1) <> "/" Then p_AppPath = p_AppPath & "/"
 ' 加载值
 LoadValues
End Sub
Private Sub Form_Unload(Cancel As Integer)
 ' 保存现有的值
 SaveValues
End Sub
Private Sub LoadValues()
 Dim xml_document As DOMDocument
 Dim values_node As IXMLDOMNode
 ' 载入文件
 Set xml_document = New DOMDocument
 xml_document.Load p_AppPath & "Personal.xml"
 If xml_document.documentElement Is Nothing Then
  Exit Sub
 End If
 '寻找节点
 Set values_node = xml_document.selectSingleNode("个人信息")
 ' 读取各个节点的值
 txtName.Text = GetNodeValue(values_node, "姓名", "???")
 txtSex.Text = GetNodeValue(values_node, "性别", "???")
 txtBirthday.Text = GetNodeValue(values_node, "出生日期", "???")
 txtAddress.Text = GetNodeValue(values_node, "地址", "???")
 txtZip.Text = GetNodeValue(values_node, "邮编", "???")
 txtQQ.Text = GetNodeValue(values_node, "QQ", "???")
 txtHomepage.Text = GetNodeValue(values_node, "个人主页", "???")
End Sub
' 返回各个节点的值
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
' 保存现有的值
Private Sub SaveValues()
 Dim xml_document As DOMDocument
 Dim values_node As IXMLDOMNode
 ' 建立XML文件
 Set xml_document = New DOMDocument
 Set values_node = xml_document.createElement("个人信息")
 xml_document.appendChild values_node
 CreateNode values_node, "姓名", txtName.Text
 CreateNode values_node, "性别", txtSex.Text
 CreateNode values_node, "出生日期", txtBirthday.Text
 CreateNode values_node, "地址", txtAddress.Text
 CreateNode values_node, "邮编", txtZip.Text
 CreateNode values_node, "QQ", txtQQ.Text
 CreateNode values_node, "个人主页", txtHomepage.Text
 ' 保存XML文件
 xml_document.save p_AppPath & "Personal.xml"
 
End Sub
Private Sub CreateNode(ByVal parent As IXMLDOMNode, _
ByVal node_name As String, ByVal node_value As String)
 Dim new_node As IXMLDOMNode
 Set new_node = parent.ownerDocument.createElement(node_name)
 new_node.Text = node_value
 parent.appendChild new_node
End Sub

[责任编辑:editor]

   

  运行结果如下:

  虽然,MSXML提供了从Visual Basic6.0加载和存储XML文档的工具,但是,对其的应用要求程序员对VB和MSXML的COM接口有一定的认识,所以,并不是得到很广泛的应用。

  Visual Basic.NET的出现大大改变了这个状况,Visual Basic.NET提供了使用XML、XSL以及其他XML工具的完整工具,使用户很轻松就能实现XML的应用,甚至,在不用编写代码的情况下操作XML。

  ADO.NET是Microsoft新推出的.NET框架中用于数据访问的组件,其最大的优点就是使用XML作为传送数据的标准,只要有一个XML文本,就可以读入ADO.NET的组件中,然后ADO.NET再以XML格式传给数据库或者其他组件。

  可以使用DataSet对象的ReadXML方法将一个XML文件读入到DataSet中,这是一个重载的方法,有几种语法格式,经常用到的如下所示:

  ReadXML(FileName)

  其中,FileName为XML文档的名字,现在将前面创建的XML文本“Personal.xml”读入到DataSet中。新建一个项目,在窗体上创建一个Button和一个DataGrid控件,双击Button1输入以下代码:

  Dim ds As New DataSet()
'读入XML文档
ds.ReadXml("personal.xml")
Dim tb As DataTable
Dim dv As DataView
tb = ds.Tables(0)
dv = New DataView(tb)
Me.DataGrid1.DataSource = dv

  显示结果如图:

  怎么样?和刚才比起来,代码量是不是少了很多,很容易就实现了XML文件的读取呢?

[责任编辑:editor]

   

  .NET框架提供了操作XML文档和数据的一组完整的类。XmlReader和XmlWriter对象以及这两个对象的派生类提供了读取XML和可选验证XML的能力。XmlDocument和XMLSchema对象及其相关类代表了XML本身,而XslTransform和XMPathNavigator类分别支持XSL转换(XSLT)和应XML路径语言(XPath)查询。

  除了提供操作XML数据的外,XML标准还是.NET框 架中数据转换和序列化的基础。多数时候这些后台进行,不过我们已经看到ADO.NET类型化数据集是使用XML架构表示的。

  另外,ADO.NET数据集类对读写XML数据和架构提供直接支持,而且XmlDataDocument提供同步XML数据和关系ADO.NET数据集的能力,这样就可以用XML和关系工具对数据的单个集合进行操作。

  .NET框架公开了一个可用来直接对XML数据进行操作的类集。不过,如果需要使用关系操作(如排序、过滤或检索相关行),数据集则提供了一个更简便的机制。此外,XML类不支持数据绑定,所以如果要向用户显示数据,就必须使用数据集的XML方法。

  幸运的是,将任何一个给定的数据集合作为XML层次结构或关系数据集相互并不排斥。

  1.数据集支持的最直接的XML方法可能就是GetXml和GetXmlSchema了,这方法只将XML数据或XSD架构作为一个字符串值返回。可以用以下代码来实现:

  Dim xmlstr As String
xmlStr = Me.dsMasterl.GetXmlSchema()
Me.tbResult.Text = xmlStr

  和

  Dim xmlstr As String
xmlStr = Me.dsMasterl.GetXml
Me.tbResult.Text = xmlStr

  2. 数据集的ReadXmlSchema方法可从XSD架构定义或从XML加载数据集架构定义。

  ReadXmlSchema支持4个版本的方法。可以将流、识别文件名的字符串、TextReader或XmlReader对象传递给方法。

  ReadXmlSchema不加载任何数据,它只加载表、列和约束(键和关系)。如果数据集已经架构信息,新表、列和约束将在必要时添加到现有架构中。如果正读取的架构中定义的对象与现有数据集架构冲突,那么ReadXmlSchema方法将会引发一个异常。

  Dim newDS As New System.Data.DataSet()
newDS.ReadXmlSchema("masterSchema.xsd")
Me.daCategories.Fill(newDS.Tables("Categories"))
Me.daproducts.Fill(newDS.Tables("Products"))
SetBindings(newDS)

  3. 数据集的InferXmlSchema方法根据传递给它的XML数据的结构派生出数据集架构。

[责任编辑:editor]

   

  InferXmlSchema与上一节介绍的ReadXmlSchema方法的输入源相同。另外,InferXMLSchema方法接受表示命名空间的字符串数组,这个空间在生成数据集架构时应被忽略。

  Dim newDS As New System.Data.DataSet()
Dim nsStr()As string
newDS.InferXmlSchema("dataOnly.xml",nsStr))
Me.daCategories.Fill(newDS.Tables("Categories"))
Me.daProducts.Fill(newDS.Tables(Products"))
newDS.Relations.Add("CategoriesProducts", _
newDS.Tables("Categories").Columns("CategoryID"), _
newDS.Tables("Products").Columns("CategoryID"))

  前两行代码声明了数据集和String数组变量,第3行将结果传递到InferXmlSchema方法中。接下来的代码给新数据集添加并填充了新的数据关系,然后SetBindings函数将XML窗体控件绑定到数据集上。

  4.WriteXmlSchema方法将数据集架构(包括表、列和约束)写到指定输出中。这个方法和其他XML方法一样,都接受相同的输出参数。

  Me.dsMaster1.WriteXmlSchema("testSchema.xsd")
Messagebox.Show("Finished","WriteXmlSchema")

  5. 与ReadXml类似,数据集的WriteXml方法也可将XML数据或可选的数据集架构信息写到指定输出中。

  Me.daCategories.Fill(Me.dsMaster1.Categories)
Me.daProducts.Fill(Me.dsMaster1.Products)
Me.dsMaster1.WriteXml("newData.xml", XmlWriteMode.IgnoreSchema)
MessageBox.Show("Finished", “WriteXml")

  默认情况下,WriteXml方法生成XML,所生成的XML是一般结构来设置格式的,其中数据表的结构作为复杂类型,数据列的结构作为复杂类型中的元素。这并不一定是所需要的输出结果。例如,如果要将数据读回到数据集,只有存在架构时(而架构在很多情况下都是不很必要的开销)或者相关数据嵌套在XML层次结构中时,ADO.NET才会创建正确的关系。在其他情况下,也许需要控制列是否以元素、必性或简单文本方式写入,或者完全阻止某些列被写入。比如,在应用程序间互换数据就可能出会这种情况。

  Me.daCategories.Fill(Me.dsMaster1.Categories)
Me.daProducts.Fill(Me.dsMaster1.Products)
Me.dsMaster1.Relations("CategoriesProducts").Nested = True
Me.dsMaster1.WriteXml("nestedData.xml",XmlWriteMode.IgnoreSchema)
MessageBox.Show("Finished","WriteXml Nested")

[责任编辑:editor]

   

  数据列的ColumnMapping(列映射)属性控制着WriteXML方法写入列的方式。ColumnMapping属性的可能取值。 默认值Element将列作为表示数据表的复杂类型内的嵌套元素写入,同时,Attribute将列作为它的必性之一写入。这两个值可以在任何给定的数据表内混用。Hidden值可防止列写入。SimpleContent将列作为一个简单文本值写入,它不能与那些作为元素或属性写入的列混合,也不能在数据关系的Nested属性引用一个将Nested属性设置为True的表时使用。

  Me.daCategories.Fill(Me.dsMaster1.Categories)
with Me.dsMaster1.Categories
.Columns("CategoryID").ColumnMapping = MappingType.Attribute
.Columns("CategoryName").ColumnMapping = MappingType.Attribute
.Columns("dESCRIPTION").ColumnMapping = MappingType.Attribute
End with
Me.dsMaster1.WriteXml("attributes.xml", XmlWriteMode.IgnoreSchme)
MessageBox.Show("Finished", "Write Attributes")

  6. 虽然关系数据有效,但有些时候使用XML提供的工具(如XSL(可扩展样式表语言)、XSLT、和XPath)操作一组数据会更方便。

  .NET框架的Xml数据文档(XML DataDocument)使之成为可能。Xml数据文档允许将XML结构的数据作为数据集来操作。它不会创建一组新数据,但会创建一个引用所有或部分XML数据的数据集。因为只有一组数据,在一个视图中所作的更改将会自动反映在另一个视图中。当然存储资源会被保存,因为只维护了数据的一个副本。

  根据数据的初始源的不同,可以基于数据集的架构和内容创建一个Xml数据文档,或基于Xml数据文档的内容创建数据集。在任何一种情况下,对一个视图中存数据所作的更改将会映射到另一个视图中。

  要创建基于现有数据集的Xml数据文档,可将数据集传递给XMLDataDocument构造函数:

  myXDD = New XmlDataDocument(myDS)

  如果在创建Xml数据文档之前,数据集架构还未建立,那就必须手动建立这两个架构,因为对一个对象所作的架构更改不会被传播给另一个对象。反之,若要从XML文档开始并创建数据集,可以使用默认的XMLDataDocument构造函数,然后引用其数据集属性。

  myXdd = New XmlDataDocument()
myDS = myXDD.DataSet

  如果使用这个方法,就必须通过将对象添加到数据集的表数据表的列集合来手动创建数据集架构。为了能通过数据集使用Xml数据文档的数据,数据表和数据列的名称必须与Xml数据文档中的名称相匹配,名称匹区分大小写的。

[责任编辑:editor]

   

  第二种方法需要的代码稍微多一些,提供了一个创建XML数据部分关系视图的机制。在数据集中复制整个XML架构没有特殊要求。在数据集操作期间,所有不在数据集中的数据表和数据列都会被忽略。

  任何时候,同步前或同步后,都可将数据加载入两个文档中。对一个对象所作的数据更改(包括添加、删除或更改值)都会被自动映射到另一对象中。

  Dim mySDD As System.Xml.XmlDataDocument
myXDD = New System.Xml.XmlDataDocument(Me.dsMaster1)
myXDD.Load ("dataOnly.xml")
SetBindings(Me.dsMaster1)

  .NET框架对XML操作提供广泛支持,在System.XML名字空间中可以找到超过150个类,限于本人水平有限,只研究了XML和ADO.NET数据集之间的接口。

  总之,无论你喜欢与否,.NET框架都有一个令人难以拒绝的地方:这是个崭新的平台。在学习的过程中都要投如较多的精力。从现在开始,我们都是初学者,所以,请大家多多指点。

[责任编辑:editor]