VB读写XML文件还是比较简单的,因为有自带的类库,不需要下载,或者引用别人的。
XML文件目前就我所知有两种写法:
一种是下面这种,节点和数据融合在一起,数据作为节点的属性存在。
<?xml version="1.0" encoding="gb2312" ?> <root> <order name="订单数据" 测试使用="ceshisdfd"> <row 订单编号="62" 下单时间="2008-10-3 上午 12:28:30" 产品名称="金维" 产品价格="169" 当前状态="3" 广告编号="45" /> <row 订单编号="65" 下单时间="2008-10-4 上午 13:28:30" 产品名称="系列" 产品价格="166" 当前状态="5" 广告编号="41" /> <row 订单编号="63" 下单时间="2009-11-4 上午 11:08:57" 产品名称="系列" 产品价格="133" 当前状态="1" 广告编号="39" /> </order> </root>
还有一种就是下面这种写法,数据与节点分开,<Node></Node>之间的是数据,<>内的则是节点名称。
<Values> <FirstName>wang</FirstName> <LastName>wei</LastName> <Street>huanquanroad</Street> <City>fengdu</City> <State>jiangsu</State> <Zip>00000</Zip> </Values>
针对这两种不同的写法的的XML文件的读取代码也是不一样的。如果用错了会出现程序报错或崩溃的情况。
Private Sub Command1_Click() CommonDialog1.ShowOpen Label1.Caption = CommonDialog1.FileName Dim xmldoc As DOMDocument Dim nodes As IXMLDOMNode Dim cnodes As IXMLDOMNode Set xmldoc = New DOMDocument 'xmldoc.Load App.Path + "\test.xml" xmldoc.Load Label1.Caption '打开输出文件 Open App.Path + "\outPut.txt" For Output As #1 If xmldoc.documentElement Is Nothing Then Exit Sub End If Print #1,xmldoc.childNodes.Item(1).baseName For j = 0 To xmldoc.documentElement.childNodes.length - 1 Set nodes = xmldoc.documentElement.childNodes(j) '第一层节点 Print #1,nodes.baseName For i = 0 To nodes.childNodes.length - 1 ''第一个节点的下一层节点 (2层) Set cnodes = nodes.childNodes.Item(i) If cnodes.childNodes.length > 1 Then Call ChildNode(cnodes) Else Print #1,cnodes.baseName,cnodes.Text End If Next Print #1,nodes.baseName Next '将数据输入至指定文件 Print #1,xmldoc.childNodes.Item(1).baseName '关闭输出文件 Close #1 End Sub
'防止多层嵌套 Public Function ChildNode(Node As IXMLDOMNode) Dim cNode As IXMLDOMNode Print #1,Node.baseName For i = 0 To Node.childNodes.length - 1 Set cNode = Node.childNodes.Item(i) If cNode.childNodes.length > 1 Then Call ChildNode(cNode) Else Print #1,cNode.baseName,cNode.Text End If Next Print #1,Node.baseName End Function
引用,我是引用的Microsoft XML,V4.0。
程序的功能就是读取XML文件各个节点和数据,并将它们写入到一个TXT文件。
读取的目标文件是用CommonDialog实现的。
需要注意的就是:
1、IXMLDOMNode.baseName 和IXMLDOMNode.Text两个的应用。这也是第二种文件的读取不同于第一种文件的所在。
baseName就是节点的值,Text则是节点内容。如果节点是<name>Joe</name>,那么baseName = name ;Text = Joe。
这个也是可以读取到XML文件中的注释部分的:如果注释是<!--modify-->,那么 baseName = ; Text = modify;baseName为空。
网上有人回答说无法读取到注释的内容,这个是不正确的,是可以读取的。
2、关于第二种写法的格式问题
常见的以第二种格式为模板的写法,基本就是这么些的,<Node>Text</Node>完整的作为一行来写,然后缩进什么的。但是实际中按代码的理解的正确写法却不是这样的。
因为当读取到<Node>Text</Node>这类的节点的时候,用.childnodes.length去看值,会发现值并不为0,按道理说,这就是个完整的节点,怎么可能还有子节点?所以代码的理解的正确的写法应该是下面这样的:
<Transaction_Header> <Code> 404 </Code> <Name> Joe </Name> </Transcation_Header>节点之间的值,应该还有一层缩进。
For i = 0 To nodes.childNodes.length - 1 ''第一个节点的下一层节点 (2层) Set cnodes = nodes.childNodes.Item(i) For Each pp In cnodes.childNodes '3层 If LCase(pp.Attributes.getNamedItem("name").nodeValue) = "name" Then '节点名为name Text1.Text = Text1.Text + CStr(pp.Text) + "," End If If LCase(pp.Attributes.getNamedItem("name").nodeValue) = "fullname" Then Text1.Text = Text1.Text + CStr(pp.Text) + "," End If If LCase(pp.Attributes.getNamedItem("name").nodeValue) = "description" Then Text1.Text = Text1.Text + CStr(pp.Text) + vbCrLf End If Text1.Refresh Next Next
与第一种的区别在于没有用IXMLDOMNode.baseName 和IXMLDOMNode.Text,用的是IXMLDOMNode.Attributes,因为他的值被视为节点的属性的一部分写在了一起,所以自然也就用IXMLDOMNode.Attributes了。
但是如果用IXMLDOMNode.Attributes去读取第二种写法的文件,则会出现IXMLDOMNode.Attributes为空导致的莫名其妙的错误,那么后面的属性和方法自然也就没法使用了。