- 你所在位置:首页 〉VS.net〉XML〉XML经验〉合并 XML 文件、架构验证和更多功能
- 合并 XML 文件、架构验证和更多功能
- 作者:佚名 文章来源:http://msdn2.microsoft.com/zh-cn/default.aspx 发布日期:2007-07-07 浏览次数:551
-
- 打印这篇文章
-
下载本文的代码:XMLFiles0303.exe (174KB)
问: 如何将多个 XML 文件的内容合并到一个文件中?
答: 有多种用 Microsoft?.NET Framework 完成该任务的方法,每个方法都使用不同类型的 XML API。要用 DOM API 完成该任务,需要使用用于在文档之间复制 XmlNode 对象的 ImportNode 函数。由于 ImportNode 只在文档之间传输对象的控制,因此仍然需要调用 AppendChild(或 InsertBefore 等)以便将节点插入到树中。
图 1 显示了一个完整的 C# 示例,它将两个 XML 文档(product.xml 和 material.xml)合并到一个文档中。新文档具有一个根 Container 元素,它将存放其他两个文件的内容。使用 XmlReader 和 XmlWriter API。为此,您应该使用单个 XmlWriter 生成新的 XML 文档,并且使用多个 XmlReader 以便将其他文档合并到新的文档中。XmlWriter 提供了 WriteNode 方法,该方法可以一次性地读取所提供的 XmlReader 对象并写入它的所有节点(参见图 2)。
最后,您还可以使用 XSLT,通过 document 函数完成该任务。这可能是所有解决方案中最容易的一种:
〈xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
〈xsl:template match="/">
〈Container>
〈xsl:copy-of select="document('product.xml')"/>
〈xsl:copy-of select="document('material.xml')"/>
〈/Container>
〈/xsl:template>
〈/xsl:stylesheet>
请参见位于本文顶部链接处的代码下载。
问: 是否可以针对嵌入到 Web 服务描述语言 (WSDL) 文档中的 XML 架构定义验证 XML 文档?
答: 可以。XmlValidatingReader 是 .NET Framework 中提供 XML 架构验证的类。它提供一个类型为 XmlSchemaCollection 的 Schemas 属性,以便存放要用作验证依据的架构的缓存:
XmlTextReader r = new XmlTextReader("employee.xml");
XmlValidatingReader vr = new XmlValidatingReader(r);
// load schema into cache
vr.Schemas.Add("http://example.org/employee", "emp.xsd");
// read through XML stream - validates along the way
while (vr.Read()) ; // do nothing
该版本的 Add 需要指定命名空间以及文件名。要回避必须指定命名空间的需要,可以通过调用 XmlSchema.Read 生成一个 XmlSchema 对象并改而使用该对象:
XmlSchema schema = XmlSchema.Read("emp.xsd", null);
vr.Schemas.Add(schema);
针对嵌入到 WSDL 定义中的 XML 架构定义进行验证的过程非常类似。通过调用 ServiceDescription 将 WSDL 定义读取到 ServiceDescription 对象中。需要读取然后循环访问内部的 XmlSchema 对象,并且将它们加载到 XmlValidatingReader 所使用的 XmlSchemaCollection 中:
ServiceDescription sd = ServiceDescription.Read("emp.wsdl");
foreach(XmlSchema embeddedXsd in sd.Types.Schemas)
vr.Schemas.Add(embeddedXsd);
架构驻留在何处实际上没有任何关系,只要可以将其分析为 XmlSchema 对象即可。
问: 在客户端应用程序中管理 Web 服务引用的最佳技术是什么?
答: Web 开发的持续存在的难题之一是链接维护。以下是一个典型方案。站点 A 链接到站点 B 提供的资源。稍后某个时间,站点 B 决定重新组织它的站点,但是站点 A 不会发现已经发生了更改,因此它的链接在一段(可能很长)时间内处于断开状态。
图 3 具有硬编码地址的客户端
Web 服务面临相同的问题,因为客户端通常通过硬编码 URL 与它们的终结点紧密耦合,如图 3 所示。例如,请考虑下面的 .asmx 类,它包含一个简单的回显输入的 WebMethod:
[WebService(Namespace="http://example.org/echo")]
public class EchoClass : WebService
{
[WebMethod]
public string Echo(string input)
{
return
String.Format("Endpoint location: {0}\nInput: {1}",
HttpContext.Current.Request.Url,
input);
}
}
假设该类被绑定到一个名为 echo.asmx 且驻留在 URL http://localhost/echoservice/echo.asmx 的 .asmx 文件。使用 .NET Framework,可以通过 wsdl.exe 为该终结点生成一个代理类,如下所示:
wsdl.exe http://localhost/echoservice/echo.asmx?wsdl
当您这样做时,默认情况下 wsdl.exe 会通过将终结点的 URL 硬编码到构造函数中来生成代理类,如下所示:
...
public class EchoClass : SoapHttpClientProtocol {
public EchoClass() {
this.Url = "http://localhost/echoservice/echo.asmx";
}
...
}
这使您能够针对该代理编写代码,而无须在运行时指定终结点位置。当您调用该类中的方法时,它会自动生成正确的 SOAP 消息,并且将它们发送到被硬编码到构造函数中的 URL:
EchoClass e = new EchoClass();
// SOAP message for Echo automatically sent to
// http://localhost/echoservice/echo.asmx
Console.WriteLine(e.Echo());
但是,如果 Web 服务管理员在客户端应用程序交付之后决定将 endpoint1.asmx 移动到不同的位置,则他将中断 Web 服务链接,该链接只能通过重新编译针对原始路径硬编码的所有客户端应用程序才能修复。
要帮助缓解该问题,可以使用 wsdl.exe 从客户端应用程序的配置文件中的用户定义项中读取 URL。这是通过使用 /appsettingurlkey: 开关完成的,如下所示:
wsdl.exe /appsettingurlkey:EchoServiceLocation
http://localhost/echoservice/echo.asmx?wsdl
在这种情况下,所生成的代理的构造函数将包含额外的代码,以便在使用默认位置之前从应用程序配置文件中读取 URL 值:
public EchoClass() {
string urlSetting = ConfigurationSettings.AppSettings[
"EchoServiceLocation"];
if ((urlSetting != null)) {
this.Url = urlSetting;
}
else {
this.Url = "http://localhost/echoservice/echo.asmx";
}
}
现在,假定应用程序程序集称作 client.exe,则可以创建一个名为 client.exe.config 的含有以下 appSettings 项的配置文件,以便动态配置代理类:
〈configuration>
〈appSettings>
〈add key="EchoServiceLocation"
value="http://localhost/echoservice/echo.asmx" />
〈/appSettings>
〈/configuration>
在完成该工作以后,如果 Web 服务管理员决定移动文件,则至少无须重新编译客户端应用程序。他们可以简单地用新位置更新他们的本地配置文件,就可确保没有问题了。但是,这仍然不够理想,因为客户端必须查明正确的位置并手动进行更改。
统一描述、发现和集成规范 (UDDI) 可以通过 UDDI 调用模式对事情进行进一步简化。该模式定义了一系列步骤,以便在运行时确定 Web 服务的当前位置。简言之,它规定如果您调用服务并且找不到终结点,则应该查询一个著名的 UDDI 储存库(其地址不应当更改)并请求 Web 服务的当前位置。只要该 Web 服务向 UDDI 进行了注册并且已经使它的记录保持最新状态,则客户端就应当能够更新它的本地配置并重新尝试调用。在实现 UDDI 调用模式之后,您的代理就可以确定新位置并自动更新本地配置文件。
要使用 UDDI 调用模式,首先需要通过 UDDI 储存库(类似于 Microsoft 在 http://uddi.microsoft.com 提供的储存库)发布您的 Web 服务。您还可以承载您自己的企业级 UDDI 储存库,并且只在本地使用它。Windows?Server 2003 将随附 UDDI 服务以便简化该工作。您决定在何处发布您的 Web 服务实际没有任何关系,因为无论如何 UDDI API 都是相同的。
如果您尚未在决定使用的 UDDI 服务器中拥有帐户,则必须首先注册您自己。然后,只须完成相关步骤即可发布您的 Web 服务。在您发布 Web 服务之后,UDDI 服务器将立即向其分配您在将来用来查找该服务的绑定项(参见图 4)。通过 UDDI SDK 2.0,Microsoft 使开发人员可以容易地用面向 .NET Framework 的语言以编程方式访问 UDDI 储存库。图 5 中的 FindCurrentLocation 方法说明了如何实现 UDDI 调用模式部分。
图 4 向 UDDI 注册 Web 服务
该方法应查找 UDDI 服务器的 URL 以及客户端应用程序的配置文件中的 Web 服务绑定项,从而可以容易地在项目和 Web 服务中重用代码。仅当它确定 WebException 与无法查找宿主或终结点有关时,它才通过调用 NotFound 与 UDDI 服务器联系(参见图 6)。
如果您成功地通过调用 FindCurrentLocation 找到了 Web 服务的新位置,则您还将需要更新客户端的配置文件,以使其不必在 Web 服务每次被调用时执行查询。这可以使用 DOM 完成,如图 7 所示。我将 FindCurrentLocation 和 UpdateLocalConfiguration 放到一个名为 InvocationPattern 的类中,并且将它们标记为 public/static。您可以容易地在给定 Web 服务调用的错误处理代码的内部使用这些方法。
请考虑使用以下配置文件的客户端应用程序:
〈configuration>
〈appSettings>
〈add key="EchoServiceLocation"
value="http://staff.develop.com/aarons/dotnet/echo.asmx" />
