为什么
面对漫天飞舞的XML曾经迷惑,不就是一种带格式的文本文件吗,为什么会惹得众多软件巨头竞相追捧,以致成为网络时代的通用表达语言?仔细研究下来,XML的以下特点使之成为互联网上的新宠:
1. 通用性:自从其诞生的那天起,便立志成为电子商务时代的世界语,所以它采用了一种结构化的ASCII文本文件,任何系统都可以方便的与之沟通。
2. 开放:XML为W3C所制定的标准语法,并已获得软件工业的认可。
3. 可扩展:无固定不变的标记,可根据需求创建新标记。
4. 自我描述能力:DTD将XML的每个部分做了声明与精确的格式定义。而SCHEMA是XML文档元素的规则组合,它指定文本中所允许的元素,及其可能的组合。
正因为此,通过ADO取得的数据记录,保存为XML文档,有着广泛的应用价值,下面详细讨论之。
目标
现有一个ACCESS数据库PeiXun.mdb,一个kecheng数据表,其结构如下图所示:
我们将把其内容保存为如下格式的XML文档:
- <xml>
- <row>
<id>3</id>
<classid>1 </classid>
<date>2003年5月24日</date>
<curriculum_name>MBA考前辅导第一期基础班</curriculum_name>
</row>
</xml>
正如我们所熟悉的用ASP操作数据库模式,先创建一个conn..asp文件,用于打开数据库,在后面的代码中都会用到:
<%
on error resume next
dim conn,connstr
dim dbpath
connstr="DBQ="+server.mappath("DataBase/peixun.mdb")+";DefaultDir=;DRIVER={Microsoft Access Driver (*.mdb)};"
set conn=server.createobject("adodb.connection")
conn.Open connstr
%>
方案一
基本上,维护XML文档的技术有三种,第一种是使用DOM(Document Object Modal)接口,第二种是通过SAX(Simple API for XML),第三种是采用传统的字符串维护。
所谓DOM就是把整个XML文档加载到一个树状结构的节点中,然后再通过维护树状结构的方式来改变XML文档,使用DOM时,整个XML文档必须先加载到内存中。
实际上,很多家公司都实现了DOM,包括IBM,Apache,Microsoft等,而Microsoft公司是把DOM的实现放在MSXML SDK内,而MS IE 也使用DOM 。下面我们就使用MSXML对象实现从ADO RecordSet 到XML文档的转化。
1. 取得ADO数据记录集
<!--#include file ="conn.asp"-->
<%
Dim strsql
Dim objRecordset
Dim fileObj
strsql=" select id,class_id,date, curriculum_name from kecheng "
set objRecordset=conn.execute (strsql)
%>
2. 创建XMLDOM对象
<%
Set objXMLDOM = Server.CreateObject("MSXML2.DOMDocument.3.0")
'创建根节点<xml>
Set objRootNode = objXMLDOM.createElement("xml")
objXMLDOM.documentElement = objRootNode
‘用createProcessingInstruction方法处理指令
objXMLDOM.appendChild(objXML.createProcessingInstruction("xml","version=""1.0"""))
%>
3. 循环把数据集中的每条记录写到DOM的节点中去:
<%
Do While NOT objRecordset.EOF
'创建子元素 row
Set objRowNode = objXMLDOM.createElement("row")
'创建子元素 id
Set objNode = objXMLDOM.createElement("id")
objNode.text = _
objRecordset.Fields.Item("id").Value
'id 作为row 的子节点 添加到row下
objRowNode.appendChild(objNode)
'创建 classid节点,并使之为row的子节点
Set objNode = objXMLDOM.createElement("classid")
objNode.text = _
objRecordset.Fields.Item("classid").Value
objRowNode.appendChild(objNode)
'创建 date节点,并使之为row的子节点
Set objNode = objXMLDOM.createElement("date")
objNode.text = _
objRecordset.Fields.Item("date").Value
objRowNode.appendChild(objNode)
'创建 curriculum_name节点,并使之为row的子节点
Set objNode = objXMLDOM.createElement("curriculum_name")
objNode.text = _
objRecordset.Fields.Item("curriculum_name").Value
objRowNode.appendChild(objNode)
'row 作为xml的子节点添加
objRootNode.appendChild(objRowNode)
'移到下一条记录
objRecordset.MoveNext
Loop
%>
4. 调用save方法 保存XML文件
<%
objXMLDOM.save(server.MapPath("kecheng.xml"))
%>
5. 释放资源
<%
Set objNode = Nothing
Set objRowNode = Nothing
Set objRootNode = Nothing
Set objRecordset = Nothing
%>
您肯定发现了,第3步写得好罗嗦啊,完全可以用RecordSet得Fields属性,循环取出所有的字段,如下所示:
<%
Do While NOT objRecordset.EOF
'创建子元素 row
Set objRowNode = objXMLDOM.createElement("row")
For Each varItem In objRecordset.Fields
Set objNode = objXMLDOM.createElement(varItem.name)
objNode.text =varItem.value
objRowNode.appendChild(objNode)
Next
' row 作为xml的子节点添加
objRootNode.appendChild(objRowNode)
objRecordset.MoveNext
Loop
%>
这样写即简洁又通用,实际上写程序的过程就是不断精益求精的过程啊。
方案二
我们把记录集和XML格式串放到字符串中,生成目标中所示的格式,然后把字符串写到一个文本文件中。
1. 同方案一中第一步取得ADO数据记录集。
2. 定义XML格式初始化字符串:
<%
Dim strXML
strXML = "<?XML version="&""""&"1.0"&""""&" encoding="&""""&"gb2312"&""""&"?>"
strXML = strXML & "<xml>"
%>
注意我们在这里把XML文档的encoding属性定义为gb23312,以防止中文字符在XML解析器中(如IE)解析时出现错误。
3. 循环把数据集中的每条记录附加到所定义的字符串中:
<%
objRecordset.MoveFirst
Do While NOT objRecordset.EOF
For Each varItem In objRecordset.Fields
strXML = strXML _
&"<"_
&varItem.name_
&">"_
&varItem.value_
&"</"_
&varItem.name_
&">"
Next
Loop
strXML = strXML & "</xml>"
Set objRecordset = Nothing
%>
4. 把字符串保存到文件中去:
<%
Dim FileObject,OutFile
‘调用系统文件对象
SET FileObject=Server.CreateObject("Scripting.FileSystemObject")
‘创建文本文件
Set OutFile=FileObject.CreateTextFile(server.MapPath("kc1.xml"),TRUE,FALSE)
‘把字符串写到文件中去。
OutFile.WriteLine(strXML)
OutFile.Close
Set OutFile=Nothing
Set FileObject=Nothing
%>
方案三
实际上ADO的RecordSet对象中有一个Save方法,可以直接把数据保存为XML格式。下面我们看看是如何使用的:
1. 同方案一中第一步取得ADO数据记录集。
2.创建DOMDocument对象,并调用RecordSet的Save方法,把数据保存到DOMDocument中去。Save方法在ADODB 的RecordSet 的对象中是这样声明的:
Sub Save([FileName As String], _
[PersistFormat As PersistFormatEnum = adPersistADTG])
Save 方法的两个参数都是可选的,但若是第一次调用,必须指定文件名Filename。
Save 不关闭 Recordset 或 FileName,从而可以继续使用 Recordset 并保存最新的更改。在 Recordset 关闭之前 FileName 将保持打开,在这段时间其它应用程序可以读取但不能写入 FileName。
PersistFormatEnum 值,指定保存 Recordset 所使用的格式。可以是如下的某个常量
AdPersistADTG |
(默认)使用专用的“Advanced Data Tablegram”格式保存。 |
AdPersistXML |
使用 XML 格式保存。 |
以上是MSDN中对该方法的描述,据此,可以利用Save把RecordSet保存为XML文件:
objRecordset.save server.MapPath("ceshi.xml"), adPersistXML
需要注意的是,Filename并不一定是磁盘文件,也可以是内存流对象,比如DOMDocument。
下面把第二步中的代码列于此:
<%
Const adPersistXML = 1
Dim objXMLDOM
Set objXMLDOM = Server.CreateObject("MSXML2.DOMDocument.3.0")
objRecordset.save objXMLDOM, adPersistXML
%>
这样,数据记录就保存到了objXMLDOM对象中了,为什么不直接保存成XML文件呢?这是因为通过该方法保存成的XML文件附加了一些我们目标中不需要的信息:
这些信息是XML文档的架构(Schema)信息。它包含了RecordSet中记录的描述,其中<s:Schema> 定义了各字段的名称,类型及其它一些属性; <rs:data> 是RecordSet中的所有数据记录 <z:row>则具体到每一条记录的信息。我们的任务下一步就是利用XSLT把该文档转化为目标中XML文档的格式。
3.利用XSLT对XML文档进行转换。那么什么是XSLT呢?它是Extensible Stylesheet Language Transformations 的缩写,是一种专为XML设计的样式表语言,负责将XML源代码转化为另一种格式。XSLT转换必须由特定的软件来担任,这样的软件称为XSL处理器。XSL处理器在工作之前,得先借助XML解析器替它把XSLT样式表和待转换的XML文档中的节点和属性分离出来,分离的结果我们程之为源树,指的是转换前的XML结构。然后,XSL处理器根据XSL中的命令对XML文档的源树进行操作,得到转换的成品,我们称之为结果树。下图就是利用XSLT对XML进行转换的原理图。
.
下面我们就编写XSLT文件 RecordsetCleaner.xsl
<%
<?xml version="1.0"?>
<!-- RecordsetCleaner.xsl -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:element name="xml">
<xsl:for-each select="/xml/rs:data/z:row">
<xsl:element name="row">
<xsl:for-each select="@*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
%>
4.调用XSLT转换。现在XSLT文件已经准备好了,开始让它与XML文档发生作用吧。记住,我们在第二步的时候已经把RecordSet保存在了objXMLDOM中。
<%
Dim strCleanXML, objXMLDOM_XSLT
Set objXMLDOM_XSLT = CreateObject("MSXML2.DOMDocument.3.0")
objXMLDOM_XSLT.load(Server.MapPath("RecordsetCleaner.xsl"))
strCleanXML = objXMLDOM.transformNode(objXMLDOM_XSLT)
%>
现在,strCleanXML字符串中就保存着我们目标中所要求的XML文档。下一步就是要把它保存在磁盘文件中去。
5.保存为文件。
<%
objXMLDOM.loadXML(strCleanXML)
objXMLDOM.save(server.MapPath("test1.xml"))
Set objXMLDOM = Nothing
Set objXMLDOM_XSLT = Nothing
Set objRecordset = Nothing
%>
在这里,我们复用了objXMLDOM对象,通过调用loadXML方法,其内容已经变为已经减肥过的XML文档内容了。
遗留问题
当数据集中的数据包含 “,’,<,,>等XML保留字符时,转换将会失败,我们在上面的讨论中并没有注意这个问题。在实际开发中,要首先对这些字符进行过滤,然后才能进行转换。
|