【发布时间】:2017-03-01 09:40:16
【问题描述】:
我目前正在尝试为 SoapClient 实现一个包装器,以通过 UPS Web 服务处理 Rate 服务请求。我看到的一件事是它们似乎使用与不同名称空间相关的单独模式,并且某些容器似乎在不同的名称空间中重复。 我不是 100% 确定当容器在从 wsdl 链接的两个不同模式文件中定义时,php 如何确定要使用的命名空间,但它似乎工作过一次,现在我收到错误,我看到的唯一的东西是它在返回错误的项目上定义了错误的命名空间。
据我所知,WSDL 和 Schema 提供了获得正确信息所需的信息。 WSDL 指向 UPS 包含的文件 RateWebServicesSchema.xsd 用于 UPS 定义为名称空间“rate”(php 自动生成“ns2”),并指向 common.xsd 用于名称空间“common”(php 自动生成“ns1”)
UPS 的 RateWebServicesSchema.xsd 和 common.xsd 都包含一个复杂类型“CodeDescriptionType”作为示例(该元素正在使用生成“缺少代码”错误的元素,因此我假设命名空间是问题)
<xsd:complexType name="CodeDescriptionType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
RateWebServicesSchema.xsd,似乎告诉任何解释它的东西来使用 PickupType 中子元素的 rate 命名空间:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" xmlns:rate="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" xmlns:ups="http://www.ups.com/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" version="201607">
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" schemaLocation="common.xsd"/>
<xsd:element name="RateRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Request"/>
<xsd:element minOccurs="0" name="PickupType" type="rate:CodeDescriptionType"/>
<xsd:element minOccurs="0" name="CustomerClassification" type="rate:CodeDescriptionType"/>
<xsd:element name="Shipment" type="rate:ShipmentType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
[.....]
如前所述,由 php 创建的信封将 common 定义为 ns1 并将 rate 定义为 ns2,但是当我通过 __soapCall 运行它并获得“缺少拾取类型代码”并查看请求时,我看到了:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0"
xmlns:ns2="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1"
xmlns:ns3="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0">
<SOAP-ENV:Body>
<ns2:RateRequest>
<ns1:Request>
<ns1:RequestOption>Shop</ns1:RequestOption>
<ns1:TransactionReference />
</ns1:Request>
<ns2:PickupType xsi:type="ns1:CodeDescriptionType">
<ns1:Code>01</ns1:Code>
<ns1:Description />
</ns2:PickupType> [......]
请求处于“常见”状态,因此正确显示为 ns1,但代码/描述由于某种原因被指向 ns1。
我无法追溯的一件奇怪的事情是,它在以前的某个时间点正确分配了它们,我不确定会/可能会发生什么变化以使其开始指向 common(ns1) 而不是rate(ns2) 命名空间。
所以这会产生几个问题。
首先(也是最重要的)是否有人知道为什么 php 可能分配了不正确的命名空间和/或我如何“指示” SoapClient 使用特定的命名空间来处理冗余命名的数据结构?
其次,为了便于调试和出于好奇,是否有预定义这些命名空间的键,这样我就不必经常翻译 ns1 与 common 或 ns2 与 rate 等?
第三,我使用 WSDLInterpreter v1.0 来生成模式的各种基于 php 的对象表示。它不是 100%,因此,例如,它没有构建一些“通用”命名空间对象,我必须为 common:Request 和 common:Response 手动构建这些对象。显然,我不能在同一目录中为 CodeDescriptionType 创建多个对象。有什么方法可以使用 php [例如 php 命名空间?] 来帮助区分什么是 soap 使用,什么是 soap 调用它们?也许是一个 phpdoc 标签之类的?例如通过分隔特定于 xml 命名空间的目录中的 php 类来创建多个 CodeDescription 类型。 (这里只是广泛推测)
更新: 我在另一篇文章中发现,如果您使用 SoapVar 创建传出 Soap 数据,则可以指定命名空间,因此我更改了代码以在添加给定分支时包装传出数据的每个子分支SoapVar 指定与该分支相关的命名空间。 虽然这似乎有点工作,但它以一种奇怪的方式有点不一致。一些元素被正确命名为 namespace:type 而其他元素被命名为 namespace:type xsi:type="namespace:type" 冗余。
例如,上面的代码现在具有正确的命名空间,但显示如下:
<SOAP-ENV:Body>
<ns2:RateRequest xsi:type="ns2:RateRequest">
<ns1:Request xsi:type="ns1:Request">
<ns1:RequestOption>Shop</ns1:RequestOption>
<ns1:TransactionReference xsi:type="ns1:TransactionReference">
<ns1:CustomerContext>Order Rate </ns1:CustomerContext>
</ns1:TransactionReference>
</ns1:Request>
<ns2:PickupType xsi:type="ns2:Pickup">
<ns1:Code>01</ns1:Code>
<ns1:Description/>
</ns2:PickupType>
【问题讨论】:
-
我的问题显然与 xsi:type="ns1:CodeDescriptionType" 相关,并且仍然没有运气弄清楚我是如何设置它的,或者我改变了什么,它在早期就起作用了。什么会导致 php/SoapClient 在那里插入该参数?
-
据我所知,PHP 无法在同一个soap 事务中处理多个命名空间中的相同元素名称。我尝试使用 SoapVar 为共享名称元素的实例显式命名命名空间,即使这样也坏了,只是更深一层。我最终不得不从头开始构建 XML,插入“ns2:”前缀,然后使用 XSD_ANYXML 创建没有指定 xmlns 的 soapvar,因为这就是将正确的命名空间附加到的结果。
标签: php soap xml-namespaces soap-client