Reputation: 450
I have a wsdl that defines a schema with:
<xsd:schema elementFormDefault="unqualified"
targetNamespace="http://www.xpto.com/xpto">
and the element:
<xsd:element name="insertResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="sys_id"
type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="1" name="table"
type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="1" name="display_name"
type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="1" name="display_value"
type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="1" name="status"
type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="status_message"
type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="error_message"
type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
but when i execute the operation and get the response, SoapUI says its invalid:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<insertResponse xmlns="http://www.xpto.com/xpto">
<sys_id>something</sys_id>
<table>something</table>
<display_name>number</display_name>
<display_value>something</display_value>
<status>something</status>
</insertResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The SoapUI message (with lines wrapped for legibility):
line 4: Expected element 'sys_id' instead of
'sys_id@http://www.xpto.com/xpto' here in element
insertResponse@http://www.xpto.com/xpto
If i change the WSDL to include elementFormDefault="qualified"
, in the schema, the same response is valid.
Why is this response invalid without elementFormDefault="qualified"
and what is the correct way to do it?
Also the code generated against this WSDL doesn't like the response either, failing with:
Unmarshalling Error: unexpected element
(uri:\\"http://www.xpto.com/xpto\\", local:\\"sys_id\\"). Expected
elements are <{}table>,<{}display_value>,<{}display_name>,
<{}error_message>,<{}sys_id>,<{}status_message>,<{}status>
(Again, lines wrapped for legibility.)
Using apache-cxf.
Upvotes: 0
Views: 6339
Reputation: 25054
Before your question can be answered clearly, some background information appears to be needed.
In XSD, elements declared within a complex type definition are said to be local to that type. (The alternative is to declare them independently, as top-level elements; then they are global or top-level. Not coincidentally, the top-level elements are those whose declarations are at the top level of the schema document, i.e. those which are children of xsd:schema.)
Every element declared in an XSD schema has a name consisting of a namespace name and a local name. As with XML names generally, the namespace name may be null. When the element's name has a non-null namespace name, it is said to be namespace-qualified; when the namespace name is null, by contrast, the element's name is unqualified.
Top-level element declarations take their namespace from the targetNamespace attribute on the enclosing xsd:schema element. Local element declarations, on the other hand, pose a design question: do they go into the target namespace (i.e. should their names be namespace-qualified)? Or should they have unqualified names?
There are two schools of thought on this in the XSD user community, and there were two schools of thought in the responsible WG. Some feel that any element declared in a schema document for namespace foo should be in namespace foo -- after all, one of the functions of a namespace is to tell you where the element comes from, which is a first step toward finding documentation. Others feel that local elements depend on their containing type in just the same way that attributes do -- and local attributes have unqualified names. The one thing both sides agree on is that the other guys are crazy and that no one with two brain cells to rub together could ever actually believe that things should be that way.
The form attribute on local element declarations is used to control whether the local element in question has a qualified name or an unqualified name; unsurprisingly, the two values it can take are qualified
and unqualified
. The elementFormDefault attribute on the xsd:schema element is used to specify which of those values should be the default value in the current schema document; its value defaults to unqualified
, but it is almost always good practice to specify it explicitly, since otherwise some readers will be confused.
With that background information, it's now possible to answer your question: Why is this response invalid without elementFormDefault="qualified"
and what is the correct way to do it?
The insertResponse element declared in the schema, being top-level, has the expanded name (http://www.xpto.com/xpto, insertResponse) -- sometimes expanded names are written in the form {http://www.xpto.com/xpto}insertResponse, and apparently sometimes (as illustrated by your error message) in the form insertResponse@http://www.xpto.com/xpto.
When the schema document does not specify elementFormDefault = "qualified"
, the form of local element names defaults to unqualified
. That means the expanded names of the 'sys_id', 'table', 'display_name', and the other local elements all have a null namespace part, so their expanded names are {}sys_id, {}table, {}display_name, etc. But the document you show has the form
<insertResponse xmlns="http://www.xpto.com/xpto">
<sys_id>something</sys_id>
<table>something</table>
<display_name>number</display_name>
...
The default namespace declaration on insertResponse ensures that the name given as 'sys_id' in the first child element is expanded to {http://www.xpto.com/xpto}sys_id, and similarly for the other children. The basic rule of matching for expanded names in pretty much all XML technologies is that an explicit namespace name like {http://www.xpto.com/xpto} does not match the null namespace name {}. So the element name {http://www.xpto.com/xpto}sys_id does not match the element declaration for an element named {}sys_id. An element required by the schema is not found in the instance, and an element is found in the instance which matches nothing in the declaration. So the insertResponse element is invalid.
When the schema document specified elementFormDefault="qualified"
, the local elements sys_id etc. are namespace qualified. So the expanded name found in the instance document and the expanded name associated with the declaration in the schema are both the same, namely {http://www.xpto.com/xpto}sys_id. All is well, the document is valid, and life is good, or at least as good as it gets when you are working with SOAP.
Bottom line: the creator of the response message and the creator of the schema are not currently in agreement on what the response is supposed to look like. The correct way to do it is for both of them to understand how namespace qualification works in XML and in XSD, and to agree on what form the response should take.
Good luck.
Upvotes: 6