xslt 特殊字符处理
在Web服务领域,Web服务描述语言(WSDL)文档描述了Web服务提供的接口-并指出了可以在网络上找到这些Web服务实例的位置。 通常,借助于各种开发工具来编写和使用WSDL文档。 与几乎所有与Web服务相关的信息一样,WSDL文档被表示为标准XML文档。
XML的优势之一就是可以使用功能越来越强大的工具来处理数据。 一种这样的工具XSLT可用于对XML数据进行复杂的转换。 由于WSDL文档以XML表示,因此可以使用XSLT自动执行各种WSDL转换任务。 本文介绍了一些已证明在使用XSLT处理WSDL文档中有用的方法(有些还没有),并列出了一些可用于简化WSDL文档自动处理的常规技术。
本文档假定您对WSDL和XSLT都有一定的了解。 IBM developerWorks上的以下链接提供了有用的背景信息:
- 有关WSDL之类的Web服务标准的背景知识,请访问Standards and Web services 。
- 有关WSDL的更多信息,请参阅文章SOA和Web服务的新手 。
- 有关XSLT的更多信息,请参阅XML新手 。
SAX和DOM与XSL
修改WSDL文档有两种基本方法。 第一种使用诸如Java或C之类的语言以及诸如SAX或DOM之类的XML解析API。 读取原始WSDL文档,通过算法解析和修改其内容,并构建经过修改的WSDL文档-通过手动将文档组装成字符串或使用特定于语言的XML库。 第二种方法利用XSL转换,该转换指定应如何处理输入WSDL文档以产生输出WSDL文档。 尽管此处介绍的许多技术都适用于第一种方法,但XML方法具有以下优点:
- 通用语言没有用于处理XML文档的特殊构造。 虽然可以将它们用于此类任务,但要获得同等的结果还需要付出更多的努力。
- 使用通用语言,转换背后的概念会迷失在实现转换所需的大量代码中。 XSL转换的相对简洁性使基础概念更加明显,因此更易于调试和维护。
- XSL转换可以通过许多不同的工具进行处理,其中许多工具已经广泛使用。 例如,ant构建工具,大多数Linux发行版上可用的libxslt软件包,Java运行时环境和许多Web浏览器都可以执行XSL转换。
为了完整起见,应该注意的是,XSL在表达与输入XML文档的结构不直接相关的算法方面的能力有些弱。 如果所需的转换大量使用了此类算法,那么通用语言可能是比XSL更好的选择。
WSDL的挑战
使用XSL从WSDL文档中提取结构会带来一些有趣的挑战。 为了允许使用尽可能广泛的XSL转换引擎集,请将样式表限制为XSL 1.1版中定义的功能。 XSL 2.0版中添加的某些功能将简化此处显示的某些XSL,但在一段时间内在许多环境中将不普遍。
使用XSL处理WSDL文档的最大障碍是在WSDL文档的属性值中广泛使用命名空间前缀。 这些名称空间前缀用于关联消息,端口类型,绑定和端口。 尽管XSL擅长处理输入文档中元素和属性上的名称空间,但它在属性值和字符数据内部处理它们的构造有些薄弱。
WSDL文档中的关系
尽管这里不可能完全描述WSDL文档的结构,但是值得描述WSDL文档元素之间的一些显着关系。 正确处理WSDL文档取决于了解和保留这些关系。
图1. WSDL文档元素之间的关系
每个<wsdl:message>
, <wsdl:portType>
和<wsdl:binding>
元素都包含必需的ncname类型的“ name”属性,但是使用qname从WSDL文档的其他地方引用了该属性。 与qnames关联的URI从<wsdl:definitions>
元素上的targetNamespace
属性继承。 如果<wsdl:definitions>
元素未指定targetNamespace,则qname继承一个空的名称空间URI。 图1中的虚线灰色箭头显示了这种隐式命名空间限定。
WSDL文档中的元素之间还存在以下其他“有趣”关系。 在图1中,每个箭头都用实心黑色箭头显示。
- 在
<wsdl:portType>
定义的<wsdl:operation>
中,每个<wsdl:input>
,<wsdl:output>
和<wsdl:fault>
元素均通过其message
属性引用<wsdl:message>
。是:wsdl:portType/wsdl:operation/wsdl:input/@message -> wsdl:message wsdl:portType/wsdl:operation/wsdl:output/@message -> wsdl:message wsdl:portType/wsdl:operation/wsdl:fault/@message -> wsdl:message
-
<wsdl:binding>
元素上的“ type”属性引用<wsdl:portType>
元素。 那是:wsdl:binding/@type -> wsdl:portType
- 在
<wsdl:binding>
元素内,每个<wsdl:operation>
都具有一个“名称”属性,该属性等于关联的<wsdl:portType>
<wsdl:operation>
上的“ name”属性。wsdl:binding/wsdl:operation/@name = wsdl:portType/wsdl:operation/@name
- 在
<wsdl:binding>
定义的<wsdl:operation>
中,每个<wsdl:input>
,<wsdl:output>
和<wsdl:fault>
元素都可以包含一个name
属性,其值与对应的name
属性相匹配。<wsdl:portType>
中的元素。 那是:wsdl:binding/wsdl:operation/wsdl:input/@name = wsdl:portType/wsdl:operation/wsdl:input/@name wsdl:binding/wsdl:operation/wsdl:output/@name = wsdl:portType/wsdl:operation/wsdl:output/@name wsdl:binding/wsdl:operation/wsdl:fault/@name = wsdl:portType/wsdl:operation/wsdl:fault/@name
技巧
以下是一些已证明对处理WSDL文档有用的技术和XSL代码段。 这些方法中的许多方法也可以推广到与非WSDL XML文档一起使用。
除了XSL代码段之外,下面描述的每种技术还包括一个简单的示例样式表,该样式表显示了如何将该技术用于处理WSDL文档。 对于每个示例样式表,还显示了将样式表应用于以下人为设计的WSDL文档的输出:
清单1.示例中使用的test.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file contains an imaginary WSDL used to illustrate how various
types of XSL transformations can be applied to it.
-->
<wsdl:definitions name="test"
targetNamespace="http://tempuri.org/test/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:test="http://tempuri.org/test/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
>
<wsdl:message name="inputmsg1">
<wsdl:part name="inputmsg1-part" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="inputmsg2">
<wsdl:part name="inputmsg2-part" type="xsd:decimal"/>
</wsdl:message>
<wsdl:message name="inputmsg3">
<wsdl:part name="inputmsg3-part" type="xsd:integer"/>
</wsdl:message>
<wsdl:message name="outputmsg">
<wsdl:part name="outputmsg-part" type="xsd:base64Binary"/>
</wsdl:message>
<wsdl:message name="faultmsg"/>
<wsdl:portType name="porttype">
<!-- one-way operation -->
<wsdl:operation name="porttype-op1">
<wsdl:input message="test:inputmsg1" name="porttype-op1-input"/>
</wsdl:operation>
<!-- request-response operation -->
<wsdl:operation name="porttype-op2">
<wsdl:input message="test:inputmsg2" name="porttype-op2-input"/>
<wsdl:output message="test:outputmsg" name="porttype-op2-output"/>
<wsdl:fault message="test:faultmsg" name="porttype-op2-fault"/>
</wsdl:operation>
<!-- solicit-response operation -->
<wsdl:operation name="porttype-op3">
<wsdl:output message="test:outputmsg" name="porttype-op3-output"/>
<wsdl:input message="test:inputmsg3" name="porttype-op3-input"/>
<wsdl:fault message="test:faultmsg" name="porttype-op3-fault"/>
</wsdl:operation>
<!-- notification operation -->
<wsdl:operation name="porttype-op4">
<wsdl:output message="test:outputmsg" name="porttype-op4-output"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="binding" type="test:porttype">
<soap:binding style="document"
trans