Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 5 additions & 14 deletions src/zeep/xsd/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,11 @@ def visit_import(self, node, parent):
sourceline=node.sourceline,
)

# We found an empty <import/> statement, this needs to trigger 4.1.2
# from https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#src-resolve
# for QName resolving.
# In essence this means we will resolve QNames without a namespace to no
# namespace instead of the target namespace.
# The following code snippet works because imports have to occur before we
# visit elements.
if not namespace and not location:
# Per W3C XSD 4.1.2 (https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#src-resolve):
# an import without a namespace attribute provides access to the no-namespace
# components. In that case unqualified QNames should resolve to no namespace
# instead of the target namespace.
if not namespace:
self.document._has_empty_import = True

# Check if the schema is already imported before based on the
Expand Down Expand Up @@ -252,12 +249,6 @@ def visit_import(self, node, parent):
sourceline=node.sourceline,
)

# If the imported schema doesn't define a target namespace and the
# node doesn't specify it either then inherit the existing target
# namespace.
elif not schema_tns and not namespace:
namespace = self.document._target_namespace

schema = self.schema.create_new_document(
schema_node, location, target_namespace=namespace
)
Expand Down
72 changes: 72 additions & 0 deletions tests/test_wsdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,78 @@ def test_import_cyclic():
)


def test_import_schema_without_namespace_and_header():
"""An xsd:import with schemaLocation but no namespace attribute that
points to a schema without targetNamespace should not inherit the
parent schema's targetNamespace. When the imported element is used
in a soap:header binding, the unqualified QName must still resolve.
"""
xsd_content = (
b'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">'
b'<xs:element name="Header" type="xs:string"/>'
b"</xs:schema>"
)

wsdl_main = StringIO(
"""\
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns" name="TestService">
<wsdl:types>
<xsd:schema targetNamespace="http://tests.python-zeep.org/tns">
<xsd:import schemaLocation="http://tests.python-zeep.org/header.xsd"/>
<xsd:element name="Request" type="xsd:string"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="InputMsg">
<wsdl:part name="body" element="tns:Request"/>
</wsdl:message>
<wsdl:message name="HeaderMsg">
<wsdl:part name="h" element="Header"/>
</wsdl:message>
<wsdl:portType name="TestPort">
<wsdl:operation name="Op">
<wsdl:input message="tns:InputMsg"/>
<wsdl:output message="tns:InputMsg"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TestBinding" type="tns:TestPort">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Op">
<soap:operation soapAction="Op"/>
<wsdl:input>
<soap:body use="literal"/>
<soap:header message="tns:HeaderMsg" part="h" use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestService">
<wsdl:port name="TestPort" binding="tns:TestBinding">
<soap:address location="http://tests.python-zeep.org/endpoint"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
"""
)

transport = DummyTransport()
transport.bind("http://tests.python-zeep.org/header.xsd", xsd_content)

document = wsdl.Document(
wsdl_main, transport, "http://tests.python-zeep.org/test.wsdl"
)

service = document.services.get("TestService")
assert service is not None
port = service.ports.get("TestPort")
assert port is not None


def test_import_no_location():
node_a = etree.fromstring(
"""
Expand Down