在WSDL中,Type和Element有什么区别?

48

在WSDL文件中,一个函数可以返回类型(Type)或元素(Element)。到目前为止,我只使用自定义类型作为结果。但是,什么情况下应该使用元素而不是类型呢?它们之间有什么区别?

这两者有什么区别吗?

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" element="tns:Person"></wsdl:part>
</wsdl:message>

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" type="tns:Person"></wsdl:part>
</wsdl:message>

从客户端的角度来看(使用 Web 服务的应用程序)?

正如 skaffman 指出的那样,上述问题引出了另一个问题:两者之间有何区别?

<xs:element name="Person" ... >
 ...
</xs:element>

并且

<xs:complexType name="Person">
   ...
</xs:complexType>

你的问题对我来说比那14个投票更有价值。 - Farhan stands with Palestine
4个回答

17

这不仅仅只是如此。

标准中存在一些模糊不清的地方会导致互操作性问题。根据您使用基于文档的服务还是基于RPC的服务,您必须使用类型或元素。

还有一些歧义。如果您说

<wsdl:message name="message1" type="ns:type1"/>

你说过消息的内容必须符合类型“ns:type1”的验证。但是你没有提到包含内容的元素。它将在什么命名空间中?

请参考WS-I基本配置文件了解一些规则。


在评论中有关于“文档/面向对象”与“文档/面向对象/包装”的讨论。这是我的看法。

我刚刚创建了一个 Web 服务。以下是整个内容:

using System.Web.Services;

namespace WebService1
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class SimpleMathService : WebService
    {
        [WebMethod]
        public int Add(int a, int b)
        {
            return a + b;
        }

        [WebMethod]
        public int Multiply(int a, int b)
        {
            return a*b;
        }
    }
}

我不会发布整个 WSDL,但这里是“好的部分”:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" 
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
     targetNamespace="http://tempuri.org/" xmlns:tns="http://tempuri.org/" >
    <wsdl:types>
        <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
            <s:element name="Add">
                <s:complexType>
                    <s:sequence>
                        <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int"/>
                        <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int"/>
                    </s:sequence>
                </s:complexType>
            </s:element>
            <s:element name="AddResponse">
                <s:complexType>
                    <s:sequence>
                        <s:element minOccurs="1" maxOccurs="1" 
                           name="AddResult" type="s:int"/>
                    </s:sequence>
                </s:complexType>
            </s:element>
            <s:element name="int" type="s:int"/>
        </s:schema>
    </wsdl:types>
    <wsdl:message name="AddSoapIn">
        <wsdl:part name="parameters" element="tns:Add"/>
    </wsdl:message>
    <wsdl:message name="AddSoapOut">
        <wsdl:part name="parameters" element="tns:AddResponse"/>
    </wsdl:message>
    <wsdl:portType name="SimpleMathServiceSoap">
        <wsdl:operation name="Add">
            <wsdl:input message="tns:AddSoapIn"/>
            <wsdl:output message="tns:AddSoapOut"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="SimpleMathServiceSoap" type="tns:SimpleMathServiceSoap">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="Add">
            <soap:operation soapAction="http://tempuri.org/Add" style="document"/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="SimpleMathService">
        <wsdl:port name="SimpleMathServiceSoap" binding="tns:SimpleMathServiceSoap">
            <soap:address location="http://localhost:5305/SimpleMathService.asmx"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

注意单词“wrapped”未出现。IBM在其文档中所称的“document/literal/wrapped”实际上指的是“document/literal”,它恰好使用单个消息部分,该部分名称来自服务名称的派生名称,引用一个元素,并且包含操作的参数。

这里没有什么神奇的,也没有什么非标准的东西。

在许多标准组织中,公司会站在不同的立场上。对于SOAP而言,我们有“RPC方面”和“文档方面”。RPC对许多人来说更为熟悉-它将一对一地映射到函数调用。文档则较不熟悉,并要求您实际上以简单的XML格式思考。也许IBM站在了RPC方面,我不知道。


我现在已经完成了IBM文档,具体内容是关于哪种WSDL样式。总结如下:

总结

有四种绑定样式(实际上有五种,但document/encoded无意义)。虽然每种样式都有其用途,但在大多数情况下,最好的样式是document/literal wrapped。


我还想回应文档中讨论基于消息是否存在操作名称而难度分配的地方。这不是问题。如果你阅读文档,你会发现它从未讨论过<binding>部分的任何内容。“没有操作名称”问题的解决方案在那里。

<wsdl:binding name="SimpleMathServiceSoap" type="tns:SimpleMathServiceSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Add">
        <soap:operation soapAction="http://tempuri.org/Add" style="document"/>

soapAction 是发送在请求的 HTTP 头中的,可用于消息分发:

POST /SimpleMathService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Add"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Add xmlns="http://tempuri.org/">
      <a>int</a>
      <b>int</b>
    </Add>
  </soap:Body>
</soap:Envelope>

不可能。它们将被基于操作名称的元素包装。你是如何创建这些服务的?使用 ASMX 还是 WCF?无论哪种方式,我现在会尝试并向您展示。也许可以新开一个问题,这样我们就不需要在评论中进行了。 - John Saunders
刚试了一下,没有问题。<Envelope><Body><Add><a>1</a><b>2</b></Add></Body></Envelope>。(提示:用``来包围内联代码) - John Saunders
1
很奇怪。你确定你正在使用文档/字面量吗?根据这篇文章http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/中的第5个清单,这是一个rpc/字面量消息。 - czuk
1
我明白了。请继续阅读。微软使用他们所谓的“文档/字面包装”,好像这有什么问题。当他们说需要做出“有根据的猜测”时,他们几乎在说谎。这是无稽之谈。消息有一个元素部分,其类型在架构中定义。操作使用该消息。不需要猜测。 - John Saunders
好的,但“document/literal wrapped”不同于“document/literal”。我以为你在谈论第二个。你可以在本文中阅读到,“document/literal”的一个弱点是“SOAP消息中的操作名称丢失。没有名称,分派可能会很困难,有时甚至是不可能的。”。 - czuk
显示剩余7条评论

10

使用哪种取决于它所引用的模式。若在模式中定义了tns:Person,则:

<xs:element name="Person" ... >
 ...
</xs:element>

然后你使用

<wsdl:part name="parameters" element="tns:Person">
如果另一方面,模式定义如下

<xs:complexType name="Person">
   ...
</xs:complexType>

然后你使用

<wsdl:part name="parameters" type="tns:Person">

所以问题的关键在于 Schema 元素和 Schema 类型之间的区别。


1
是的,我想知道何时应该创建模式类型和何时应该创建模式元素。或者,在这种情况下可能没有区别吗? - czuk
1
在您更加了解这些知识之前,最好不要自行创建。同时,请依赖于自动生成的 WSDL 和模式文件。 - John Saunders

2
我无法评论关于WSDL的部分,但我会回答XML Schema的部分。 <xs:complexType>定义了一个类型,它描述了元素的内容,而不描述元素本身(即其名称)。<xs:element>描述了一个元素(特别是它的名称),但不描述其类型。然而,<xs:element>总是引用所描述元素的内容的类型。这可以是对模式中其他位置(包括但不限于<xs:complexType> - 例如还可以是<xs:simpleType>)定义的现有类型的引用,或者是内联<xs:complexType>定义:
<xs:element name="foo">
   <xs:complexType>
      ...
   </xs:complexType>
</xs:element>

由于上述结构非常普遍,您实际上可以完全省略<xs:complexType>,因为它将被暗示。

至于是应该总是单独定义类型,然后在元素声明中引用它们,还是应该优先在元素声明中内联定义元素类型,则取决于个人写作风格。


根据Skaffman的说法,complexType可以被命名。那么,给complexType命名和使用element包装类型有什么区别呢? - czuk
1
如果您命名它,可以将其应用于多个不同的元素声明,并/或从中派生其他类型。因此,您可以拥有complexType Person,通过扩展(添加更多子元素来描述属性)从中派生complexType Employee,并将这些类型分配给元素“Person”和“Employee”,例如。 - Pavel Minaev

0
<xs:element name="person" type="persontype"/>

<xs:complexType name="persontype">
  <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

type 属性的 <element> 指向 name 属性的 <complexType>


<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" element="tns:person"></wsdl:part>
</wsdl:message>

并且

<wsdl:message name="MyFunction">
    <wsdl:part name="parameters" type="tns:person"></wsdl:part>
</wsdl:message>
  • <part>参数与在<types>容器元素中定义的具体类型相关联。并且如上所示,<part>可以通过type属性引用<complexType>或通过元素属性引用<element>
  • 它可以是<complexType><portType>或任何其他被type属性引用的类型。

  • 网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接