可能的解决方案
将记录集打包
虽然下面的每个解决方案都为我的问题提供了解决方案,但每个方案都各有其优缺点,我将在下面对此进行详细说明。
我们已经用 SOAP Toolkit Wizard 创建了源文件。现在我们将看一看它所生成的 ASP 接口文件(因为我们选择了使用 ASP 监听程序解决方案)。之所以选择使用 ASP 解决方案,是因为它具有这样的灵活性,即它允许在 COM 对象完成的处理之前和之后添加其它代码。
注:相比之下,ISAPI 监听程序解决方案最适合调用不需要其它代码处理的 COM 对象的情况,而我们现在需要进行这种处理。虽然 ISAPI 监听程序不像 ASP 监听程序那样灵活,但它能够提供比 ASP 监听程序更好的性能。另外,如果我们能够修改现有的 COM 对象来返回 XML,或者编写另一个 COM 对象来包装现有对象的功能,并使该包装对象返回 XML,则 ISAPI 解决方案可能会是更好的选择。
向导生成的函数如下所示:
Public Function GetAllArtists ()
Dim objGetAllArtists
Set objGetAllArtists = Server.CreateObject("RadioWeb.clsSongs")
GetAllArtists = objGetAllArtists.GetAllArtists()
'在此处插入其它代码
Set objGetAllArtists = NOTHING
End Function
请记住,虽然 GetAllArtists 将返回一个 ADO 记录集,但是因为这并不是一种符合 SOAP 的数据类型,所以 SOAP Toolkit Wizard 会指定缺省的返回数据类型 "string"。因此,为了返回我们的数据,该字符串返回值将必须是记录集的一种 XML 表示。
现在我将概要介绍两种不同的解决方案。解决方案 1 实现了一个单独的函数,将记录集转换为一种 XML 表示。解决方案 2 则使用 ADO 记录集的 Save 方法,通过 ADO Stream 对象将数据保持为 XML 格式。
本文的后半部分会说明每种解决方案的优缺点。
解决方案 1 打包
对于第一种解决方案,我们将实现“粘合代码”,以方便从记录集到 XML 字符串的转换,如下所示:
Public Function GetAllArtists ()
Dim objGetAllArtists
Set objGetAllArtists = Server.CreateObject("Radioweb.clsSongs")
GetAllArtists = GetXMLFromADORS(objGetAllArtists.GetAllArtists())
'在此处插入其它代码
Set objGetAllArtists = NOTHING
End Function
其中 GetXMLFromADORS 如下所示:
Public Function GetXMLFromADORS(ByVal objADORS)
Dim objField
Dim strXMLString
Dim strFieldName
Dim strFieldValue
strXMLString = "" & VBCrLf
Do while not objADORS.EOF
strXMLString = strXMLString & vbTab & "" & vbCrLf
For each objField in objADORS.Fields
strFieldName = objField.name
strFieldValue = objADORS(strFieldName)
If instr(1, strFieldValue, "/") Or _
instr(1, strFieldValue, ">") Or _
instr(1, strFieldValue, "<") Then
strFieldValue = CDATAit(strFieldValue)
End If
strXMLString = strXMLString & vbTab & vbTab & _
"<" & strFieldName & ">" & strFieldValue & "strFieldName & ">" & vbCrLf
Next
objADORS.MoveNext
strXMLString = strXMLString & vbTab & "" & vbCrLf
Loop
strXMLString = strXMLString & "</RECORDSET>" & vbCrLf
GetXMLFromADORS = strXMLString
End Function
GetXMLFromADORS 函数将不会像 ADO Save 方法那样强健,但它不要求在客户机上安装 Microsoft Data Access Components (MDAC)。其原因是,客户机只须分析简单的 XML 结构,而不必将 XML 转换为 ADO 记录集。
我还实现了 CDATAit 函数,它将防止插入可能形成畸形 XML 的字符串。在调用过程内部可根据需要使用此逻辑,GetXMLFromADORS 函数的情况也是这样。在上面的示例中,我只对 ">"、"<" 和 "/" 进行了检查。
Private Function CDATAit(ByVal strData)
CDATAit = ""
End Function
GetAllArtists 函数现在将返回类似下面的结果:
GetAllArtists 函数现在返回了形式良好的 XML 记录集。请注意,我们的 XML 中不存在任何 CDATA 区域。如果任何艺术家的名字包含了我们所查找的字符("/"、"<" 或 ">"),CDATAit 函数就会将它们包装在 CDATA 区域,以确保形成形式良好的 XML。
我们必须进行的唯一额外更改就在向导所生成的“服务描述语言”(SDL) 文件中。该文件是用来描述我们正在引出的 Web Service 的 XML 文件。它将位于您指示向导将您的文件保存在其下的同一文件夹中。必须修改向导为我们的返回数据生成的数据类型 — 以便“远程对象代理引擎”(ROPE)能够按 XML 正确分析数据,需要指明数据类型是一种 XML 方案。请注意,客户机代码仍将把返回数据视为由某种 XML 结构表示的字符串变量。
在这种情况下,将生成如下所示的 SDL 文件:
将需要修改描述数据返回值的部分。您将注意到,这在我们的 SDL 文件中是这样描述的:
<ELEMENT name="GetAllArtistsResponse">
<ELEMENT type="dt:string" name="return" />
</ELEMENT>
我们的返回值不再是由 SDL 所描述的字符串,而是表示记录集的一个结构。因此,对此文件的修改需要将此返回值表示为一个结构,而不是一个字符串。可以通过将该文件更改为以下形式来完成这一工作:
现在请注意,我们是将 'return' 元素作为一种 'MyReturnStruct' 类型返回,而不是作为一个字符串返回。
'MyReturnStruct' 是我们将要定义的一种结构元素。它将是我们返回的结构的父结构。请记住,该结构必须具有如下的形式:
<RECORD>
Some artist
</RECORD>
..
..
..
因此,'MyReturnStruct' 是一种定义如下的元素:
<ELEMENT name="MyReturnStruct">
>ELEMENT type="ArtistStruct" name="RECORD" />
</ELEMENT>
请注意,'MyReturnStruct' 具有一个名为 'RECORD' 的元素,其类型进一步定义为 'ArtistStruct'。这是必需的,因为子元素 实际上是 的一个子代,而后者又是 的一个子代。
然后将 'ArtistStruct' 定义为如下形式:
<ELEMENT name="ArtistStruct">
<ELEMENT type="dt:string" name="artist" />
</ELEMENT>
其中,数据类型为 'string' 的元素 'artist' 代表结构中的单个艺术家。
在研究用来分析这些数据的方法之前,让我们考察一下能够获得相同结果的另一种方法。