四种不同的 wsdl2java 应用程序无法导入 wsdl,但 SoapUI 可以

Four different wsdl2java apps fail to import wsdl, but SoapUI does fine

有一个public服务,据我所知,他们有几十或几百个客户。但是我无法从提供的 WSDL 生成 类。

http://api.kartoteka.ru/search/v3/soap/search.wsdl

我尝试了来自最新 jdk8 的 wsimport,以及来自 axis1、axis2、cxf 的 wsdl2java 所有应用程序都失败。最有趣的是 SoapUI 没有任何错误地处理了这个 WSDL。

我已经 "fixed" 通过下载 wsdl 和 "patching" 关于重复键的第一个错误,但下一个错误对我来说有点复杂:

[ERROR] undefined simple or complex type 'Error'
  line 15 of http://api.kartoteka.ru/core/v3/soap/core.wsdl

可能第一个问题也与命名空间有关,并没有真正重复的存在。警告相当冗长,但不清楚我应该进行哪些更改。

[WARNING] src-resolve.4.1: Error resolving component 'Error'. It was detected that 'Error' has no namespace, but components with no target namespace are not referenceable from schema document 'http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1'. If 'Error' is intended to have a namespace, perhaps a prefix needs to be provided. If it is intended that 'Error' has no namespace, then an 'import' without a "namespace" attribute should be added to 'http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1'.
  line 15 of http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1

[WARNING] src-resolve: Cannot resolve the name 'Error' to a(n) 'type definition' component.
  line 15 of http://api.kartoteka.ru/core/v3/soap/core.wsdl#types?schema1

[WARNING] src-resolve.4.1: Error resolving component 'Error'. It was detected that 'Error' has no namespace, but components with no target namespace are not referenceable from schema document 'file:/tmp/kart/search.wsdl#types?schema3'. If 'Error' is intended to have a namespace, perhaps a prefix needs to be provided. If it is intended that 'Error' has no namespace, then an 'import' without a "namespace" attribute should be added to 'file:/tmp/kart/search.wsdl#types?schema3'.
  line 26 of file:/tmp/kart/search.wsdl#types?schema3

我在 wsimport 中没有找到名称空间的选项,所以一般来说修改 wsdl 的方法似乎是错误的,也许我遗漏了一些简单的东西?

问题是 core.wsdl 和 search.wsdl 中的内联模式定义没有为目标命名空间(所有定义的元素都属于该命名空间)定义命名空间。 target命名空间表示这个inline schema中定义的词汇表(现在讲core.wsdl只是为了简单)属于一个命名空间"http://api.kartoteka.ru/core/v3/"。因此,当稍后在没有任何前缀的情况下引用已经定义的词汇表(在本例中为 complexType Error)时,这意味着它应该来自默认名称空间。默认命名空间在<xs:schema targetNamespace="http://api.kartoteka.ru/core/v3/">中没有定义,但应该取自:

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://api.kartoteka.ru/core/v3/" targetNamespace="http://api.kartoteka.ru/core/v3/">

因为如 XML 名称规范所述,section 6.2,它应该被继承:

The scope of a default namespace declaration extends from the beginning of the start-tag in which it appears to the end of the corresponding end-tag, excluding the scope of any inner default namespace declarations. In the case of an empty tag, the scope is the tag itself.

A default namespace declaration applies to all unprefixed element names within its scope. Default namespace declarations do not apply directly to attribute names; the interpretation of unprefixed attributes is determined by the element on which they appear.

If there is a default namespace declaration in scope, the expanded name corresponding to an unprefixed element name has the URI of the default namespace as its namespace name. If there is no default namespace declaration in scope, the namespace name has no value. The namespace name for an unprefixed attribute name always has no value. In all cases, the local name is local part (which is of course the same as the unprefixed name itself).

我认为 wsimport 的行为是错误的,因为它没有从父元素获取默认命名空间。添加默认命名空间就足以 "fix" 了。所以你只需要改变一行 core.wsdl (第 8 行):

<xs:schema xmlns="http://api.kartoteka.ru/core/v3/" targetNamespace="http://api.kartoteka.ru/core/v3/">

和 search.wsdl 一行(第 7 行):

<xs:schema xmlns="http://api.kartoteka.ru/search/v3/" targetNamespace="http://api.kartoteka.ru/search/v3/" elementFormDefault="qualified">

我将保留我之前写过的其他解决方法(如下),但它们更复杂(与此相比)并且实际上并不需要。


也许最简单的方法是进行必要的更改以在嵌入式架构定义中使用名称空间。

  1. 在 search.wsdl 中进行这些更改(第 7 行和第 26 行):

    <xs:schema xmlns:tns="http://api.kartoteka.ru/search/v3/" targetNamespace="http://api.kartoteka.ru/search/v3/" elementFormDefault="qualified">
    

    <xs:element name="error" type="tns:Error"/>
    
  2. 在core.wsdl中做类似的修改(第8行和第15-18行):

    <xs:schema xmlns:tns="http://api.kartoteka.ru/core/v3/" targetNamespace="http://api.kartoteka.ru/core/v3/">
    

    <xs:element name="systemError" type="tns:Error" /> 
    <xs:element name="serviceRestriction" type="tns:Error" /> 
    <xs:element name="authorizationRestriction" type="tns:Error" /> 
    

另一种方法是在 wsdl 文件之外定义 Error complexType 并将其导入您的 core.wsdlsearch.wsdl 个文件。

  1. 创建外部架构文件:common.xsd 内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns="http://mycustomschema/common/"
               targetNamespace="http://mycustomschema/common/">
        <xs:complexType name="Error">
            <xs:sequence>
                <xs:element name="code" type="xs:positiveInteger"/>
                <xs:element name="msg" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:schema>
    
  2. 在 search.wsdl 中引用您的自定义复杂类型:

    <xs:import namespace="http://mycustomschema/common/" schemaLocation="common.xsd"/>
    <xs:element name="sessionId" type="xs:string"/>
    <xs:element xmlns:common="http://mycustomschema/common/" name="error" type="common:Error"/>
    
  3. 在 core.wsdl 中引用您的自定义复杂类型:

    <xs:import namespace="http://mycustomschema/common/" schemaLocation="common.xsd"/>
    <xs:element xmlns:common="http://mycustomschema/common/" name="systemError" type="common:Error" /> 
    <xs:element xmlns:common="http://mycustomschema/common/" name="serviceRestriction" type="common:Error" /> 
    <xs:element xmlns:common="http://mycustomschema/common/" name="authorizationRestriction" type="common:Error" /> 
    

另一种方法是将 element="error" 更改为 type="Error":

  1. 从 search.wsdl 中删除此行:

    <xs:element name="error" type="Error"/>
    
  2. 更改 search.wsdl 中的这些行:

    <wsdl:message name="SearchError">
        <wsdl:part name="searchError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="CardError">
        <wsdl:part name="cardError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="ImportantFactsError">
        <wsdl:part name="importantFactsError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="PledgeError">
        <wsdl:part name="pledgeError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="VocabularyError">
        <wsdl:part name="vocabularyError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="BoYearsRequest">
        <wsdl:part name="request" type="bo:orgBoYearsRequest"/>
    </wsdl:message>
    <wsdl:message name="BoYearsResponse">
        <wsdl:part name="response" type="bo:orgBoYearsResponse"/>
    </wsdl:message>
    <wsdl:message name="BoError">
        <wsdl:part name="boError" type="Error"/>
    </wsdl:message>
    
  3. 从 search.wsdl 中删除这些行:

    <xs:element name="systemError" type="Error" /> 
    <xs:element name="serviceRestriction" type="Error" /> 
    <xs:element name="authorizationRestriction" type="Error" /> 
    
  4. 更改 search.wsdl 中的这些行:

    <wsdl:message name="SystemError">
        <wsdl:part name="systemError" type="Error"/>
    </wsdl:message>
    <wsdl:message name="ServiceRestriction">
        <wsdl:part name="serviceRestriction" type="Error"/>
    </wsdl:message>
    <wsdl:message name="AuthorizationRestriction">
        <wsdl:part name="authorizationRestriction" type="Error"/>
    </wsdl:message>
    

通过这种方式,您可以直接使用嵌入式模式定义中定义的类型,wsimport 似乎可以通过这种方式理解 wsdl 文件。