| NuttyCoder's profile初级程序员BlogLists | Help |
|
|
7/26/2006 ADO记录集向XML文档的转换(已批注)(NC:文章写于2003年秋天...XML刚刚开始嚣张的年代,看看,我在2004年秋天开始写Asp,2005年才知道XML这东西,现在居然也要这里那里的用它,这世界变化多快.) 1. 通用性:自从其诞生的那天起,便立志成为电子商务时代的世界语,所以它采用了一种结构化的ASCII文本文件,任何系统都可以方便的与之沟通。 2. 开放:XML为W3C所制定的标准语法,并已获得软件工业的认可。 3. 可扩展:无固定不变的标记,可根据需求创建新标记。 4. 自我描述能力:DTD将XML的每个部分做了声明与精确的格式定义。而SCHEMA是XML文档元素的规则组合,它指定文本中所允许的元素,及其可能的组合。 正因为此,通过ADO取得的数据记录,保存为XML文档,有着广泛的应用价值,下面详细讨论之。 目标现有一个ACCESS数据库PeiXun.mdb,一个kecheng数据表 我们将把其内容保存为如下格式的XML文档: -<xml> -<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),第三种是采用传统的字符串维护(NC:一直用第三种方式)。 所谓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的节点中去: ''''''''创建子元素 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 %> 这样写即简洁又通用,实际上写程序的过程就是不断精益求精的过程啊。 (NC:赞,单纯的程序员应该是一个有洁癖的完美主义者)
我们把记录集和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中去。 Sub Save([FileName As String], _ [PersistFormat As PersistFormatEnum = adPersistADTG]) Save 方法的两个参数都是可选的,但若是第一次调用,必须指定文件名Filename。 Save 不关闭 Recordset 或 FileName,从而可以继续使用 Recordset 并保存最新的更改。在 Recordset 关闭之前 FileName将保持打开,在这段时间其它应用程序可以读取但不能写入 FileName。 PersistFormatEnum 值,指定保存 Recordset 所使用的格式。可以是如下的某个常量
以上是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文档的格式。 下面我们就编写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转换。 <% 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保留字符时,转换将会失败,我们在上面的讨论中并没有注意这个问题。在实际开发中,要首先对这些字符进行过滤,然后才能进行转换。 使用ado2.1访问XML文件(已批注)MDAC 2.1有了许多新的特性,比如数据链结,三维数据分形和重定形数据(Data shaping and reshaping,实在不知道该怎么翻译),离线保持记录集,自动同步客户端游标,建立新记录集(自己加入数据,不从查询中得到),DDL和JRO等,其中的离线保持记录集就是采用XML来实现的。 这样,我们就可以象使用Recordset一样使用XML了,而且,也可以把Recordset保存为XML了,请看这一段Example Code: Dim objRS Const adCmdFile = 256 Const adPersistXML = 1 Set objRS = Server.CreateObject("ADODB.Recordset") ''''''''''''''''这里我新建一个记录集,当然从数据库中查询得到的也完全可以 objRS.Fields.Append "ID", adInteger objRS.Fields.Append "Content", adVarChar, 20 objRS.Open objRS.AddNew Array("ID", "Content"), Array(1, "test") ''''''''''''''''很简单,一个Save Method就可以转化为XML了 objRS.Save Server.MapPath("test.xml"), adPersistXML objRS.Close ''''''''''''''''要打开XML也非常的容易 objRS.Open Server.MapPath("test.xml"), , , , adCmdFile 不过呢,Recordset保存的XML比我们平常写的XML要复杂得多,因为它要记录字段的详细信息,让我们来看一下就知道了。 这是Recordset保存的: <xml 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''''''''''''''''> <s:Schema id=''''''''''''''''RowsetSchema''''''''''''''''> <s:ElementType name=''''''''''''''''row'''''''''''''''' content=''''''''''''''''eltOnly'''''''''''''''' rs:updatable=''''''''''''''''true''''''''''''''''> <s:attribute type=''''''''''''''''ID''''''''''''''''/> <s:attribute type=''''''''''''''''Content''''''''''''''''/> <s:extends type=''''''''''''''''rs:rowbase''''''''''''''''/> </s:ElementType> <s:AttributeType name=''''''''''''''''ID'''''''''''''''' rs:number=''''''''''''''''1'''''''''''''''' rs:write=''''''''''''''''true''''''''''''''''> <s:datatype dt:type=''''''''''''''''int'''''''''''''''' dt:maxLength=''''''''''''''''4'''''''''''''''' rs:precision=''''''''''''''''0'''''''''''''''' rs:fixedlength=''''''''''''''''true'''''''''''''''' rs:maybenull=''''''''''''''''false''''''''''''''''/> </s:AttributeType> <s:AttributeType name=''''''''''''''''Content'''''''''''''''' rs:number=''''''''''''''''2'''''''''''''''' rs:write=''''''''''''''''true''''''''''''''''> <s:datatype dt:type=''''''''''''''''string'''''''''''''''' dt:maxLength=''''''''''''''''20'''''''''''''''' rs:precision=''''''''''''''''0'''''''''''''''' rs:maybenull=''''''''''''''''false''''''''''''''''/> </s:AttributeType> </s:Schema> <rs:data> <rs:insert> <z:row ID=''''''''''''''''1'''''''''''''''' Content=''''''''''''''''test''''''''''''''''/> </rs:insert> </rs:data> </xml> (NC:汗) 我自己写的: <?xml version="1.0" encoding="gb2312" ?> <root> <z:row ID=''''''''''''''''1'''''''''''''''' Content=''''''''''''''''test''''''''''''''''/> </root> 用ADO访问XML并没有给我们带来什么方便,用XMLDOM也是比较简单的,但是它给我们提供了一种新的编程方式:用XML实现三层结构。 第一,如果数据库服务器上的一些数据将在一段时间内保持不变,比如一些对照表,而数据库服务器又不和Web Server在一起,那么就可以用XML在中间层放置这些数据,比用文本文件还是要来得方便和快捷的。 (NC:所见略同,解决目前NP的问题,终于为自己的想法找到依据了) 第二,比如我不想用数据库,又想放一些数据,比如我刚做的电子贺卡(实际上只是想用点新技术而已),那么也可以用XML来存放数据。 第三,比如某些数据不经常变动,比如一天变动一次,那么我不希望每次查询都去访问数据库,而是在有数据变动的时候保存到一个XML里面,而让客户端代码去读XML。 (按固定的时间刷新会影响用户体验,其实合理设置刷更新点是件很容易的且可行的事情) (NC:如果自己写一个将RecordSet转换成XML的东东,算法多加锤炼,相比效率怎样呢?) 以上内容部分来自PDC99资料DATA01:ADO体系结构和性能调整、WIN13:XML-实现3层Web应用程序。 由于本人水平有限,文中有谬误和遗漏之处,还望大家多指教。 |
|
|