PDA

View Full Version : XML Schema: complexContent/extension



res1st
Jun 7th, 2006, 09:45 AM
Hi!
i want to define a base type (CasDataType) and then "subclass" it.
I found the XML Schema element complexContent+extension which seems to fit for my needs.
Please look at my XML Schema snippet.


<complexType name="CasDataType">
<sequence>
<element name="key" type="long" nillable="false minOccurs="1" maxOccurs="1"/>
</sequence>
</complexType>

<complexType name="AddressDataType">
<complexContent>
<extension base="tns:CasDataType">
<sequence>
<element name="FirstName" nillable="true" minOccurs="0" type="string"/>
<element name="LastName" nillable="true" minOccurs="0" type="string"/>
</sequence>
</extension>
</complexContent>
</complexType>

<complexType name="ArrayOfCasDataTypes">
<sequence>
<element name="casDataTypes" type="tns:CasDataType" nillable="false" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
</complexType>

<element name="createDataTypesRequest" type="tns:ArrayOfCasDataTypes"/>

<element name="createDataTypesResponse" type="tns:ArrayOfCasDataTypes"/>
I'm creating AddressDataType objects in my endpoint method invokeInternal(...) and want to returm this objects. But i get an validation error ant my soap message looks like this:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<createDataTypesResponse xmlns="http://springws.cas.de">
<casDataTypes>
<key>123</key>
<FirstName>Ingo</FirstName>
<LastName>Siebert</LastName>
</casDataTypes>
<casDataTypes>
<key>456</key>
<FirstName>Ingo</FirstName>
<LastName>Siebert</LastName>
</casDataTypes>
</createDataTypesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
As we can see, i get casDataTypes and not AddressDataType. Why? I thought that "casDataTypes" is only the name of the array. Instead this is the element name of array elements.
Has anyone an idea, how i can provide one method for several "subclassed" (with complexContent/extension) XML schema elements?

Cheers,

Ingo

Arjen Poutsma
Jun 9th, 2006, 06:21 AM
But i get an validation error ant my soap message looks like this:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<createDataTypesResponse xmlns="http://springws.cas.de">
<casDataTypes>
<key>123</key>
<FirstName>Ingo</FirstName>
<LastName>Siebert</LastName>
</casDataTypes>
<casDataTypes>
<key>456</key>
<FirstName>Ingo</FirstName>
<LastName>Siebert</LastName>
</casDataTypes>
</createDataTypesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
As we can see, i get casDataTypes and not AddressDataType. Why?

You get a validation error because the XML is not valid according to your schema ;). Don't you just love that PayloadValidatingInterceptor?

What I would expect to see in the payload is this:



<createDataTypesResponse xmlns="http://springws.cas.de" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<casDataTypes xsi:type="AddressDataType" >
<key>123</key>
<FirstName>Ingo</FirstName>
<LastName>Siebert</LastName>
</casDataTypes>
</createDataTypesResponse>


Note the xsi:type attribute. That tells the XML parser that the type is actually an address data type. If this attribute is added, the XML is valid.



I thought that "casDataTypes" is only the name of the array. Instead this is the element name of array elements.


Try and look at this from an XML perspective, and let's forget about Java for a while. In ArrayOfCasDataTypes, you are defining a sequence (=list) of elements. Each element is called casDataType. It's that simple.



Has anyone an idea, how i can provide one method for several "subclassed" (with complexContent/extension) XML schema elements?


The trick seems to be to add the xsi:type attribute I mentioned above, which is more a JAXB thing than anything else. This thread (http://forums.java.net/jive/thread.jspa?threadID=14017&tstart=225) seems to be related to your problem, and you might also want to check out the type-substitution sample that comes with JWDSP 2.0's JAXB implementation.

Cheers,

fgt
Jun 9th, 2006, 07:22 AM
The trick seems to be to add the xsi:type attribute I mentioned above, which is more a JAXB thing than anything else.

So this means this is not interoperable with other clients than JAXB clients?

Perhaps the xsi:type approach works with .NET or other Java Bindings, I have not tried yet..., but can we use this in the future?

Currennlty I think there is no other way than to wrap the whole thing:
e.g.

<complexType name="CasDataTypeWrapper">
<choice>
<element name="AddressDataType" type="tns:AddressDataType" />
<element name="OtherExtendedCasDataType" type="tns:OtherExtendedCasDataType" />
</choice>
</complexType>

<complexType name="ArrayOfCasDataTypes">
<sequence>
<element name="casDataTypes" type="tns:CasDataTypeWrapper" nillable="false" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
</complexType>

and then take the right out..., well seems not to look nice.

Knows somebody another approach to be interoperable with Java and .NET or whatever clients. Have nothing found in the WS-I. What are your solutions to this?

Cheers,
Patrick

Arjen Poutsma
Jun 9th, 2006, 07:45 AM
So this means this is not interoperable with other clients than JAXB clients?

Perhaps the xsi:type approach works with .NET or other Java Bindings, I have not tried yet..., but can we use this in the future?


The xsi:type is a completely valid XSD construct which is exactly designed for cases like these. It just explicitly sets the schema type for an element. In fact, .NET uses it in this situation too!

What I meant with "more a JAXB thing than anything else" is that JAXB should be instructed to add this attribute. I'm not a complete JAXB expert, so I don't know how this can be accomplished, but a simple google search resulted in the resources I gave above. They seem related.

Best,

res1st
Jun 9th, 2006, 08:20 AM
Don't you just love that PayloadValidatingInterceptor?
Of course, it's really cute. :)


Note the xsi:type attribute. That tells the XML parser that the type is actually an address data type.
That sounds logical. Now i know my goal, only the way is unknown. If can't do it with jaxb, i'll try another one. It's just a bean exchange with SpringWS....i hope. :)


The trick seems to be to add the xsi:type attribute I mentioned above, which is more a JAXB thing than anything else.
I've posted my problem to java.net. If i get a good answer, i'll post it here.


<complexType name="CasDataTypeWrapper">
<choice>
<element name="AddressDataType" type="tns:AddressDataType" />
<element name="OtherExtendedCasDataType" type="tns:OtherExtendedCasDataType" />
</choice>
</complexType>
Thank you Patrick! I tried it and i have now an AddressDataType element. The "type=AddressDataType" thing seems to be more correct, but your solution is much better than nothing. Thank you.

Cheers,

Ingo

res1st
Jun 19th, 2006, 07:15 AM
<createDataTypesResponse xmlns="http://springws.cas.de" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<casDataTypes xsi:type="AddressDataType" >
<key>123</key>
<FirstName>Fritz</FirstName>
<LastName>Meier</LastName>
</casDataTypes>
</createDataTypesResponse>
JAXB 1.6 doesn't handle that it right, it never produces the xsi:type attribute which i need.
I switched back to JAXB 2.0 and it's working nearly fine. I got the following soap response:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<ns2:createDataTypesResponse xmlns:ns2="http://springws.cas.de">
<ns2:casDataType
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns2:AddressDataType">
<ns2:key>123</ns2:key>
<ns2:firstName>Fritz</ns2:firstName>
<ns2:lastName>Meier</ns2:lastName>
</ns2:casDataType>
</ns2:createDataTypesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The Problem is, that i get an validation error in my log file. Any idea why?


DEBUG webservice.CreateDataTypesRequestEndpoint - Unmarshalled payload request to [javax.xml.bind.JAXBElement@13ed2e3]
DEBUG webservice.CreateDataTypesRequestEndpoint - Marshalling [javax.xml.bind.JAXBElement@1873ad9] to response payload
ERROR endpoint.PayloadValidatingInterceptor - XML validation error on response: UndeclaredPrefix: Cannot resolve 'ns2:AddressDataType' as a QName: the prefix 'ns2' is not declared.
ERROR endpoint.PayloadValidatingInterceptor - XML validation error on response: cvc-elt.4.1: The value 'ns2:AddressDataType' of attribute 'http://www.w3.org/2001/XMLSchema-instance,type' of element 'ns2:casDataType' is not a valid QName.
ERROR endpoint.PayloadValidatingInterceptor - XML validation error on response: UndeclaredPrefix: Cannot resolve 'ns2:AddressDataType' as a QName: the prefix 'ns2' is not declared.
ERROR endpoint.PayloadValidatingInterceptor - XML validation error on response: cvc-attribute.3: The value 'ns2:AddressDataType' of attribute 'xsi:type' on element 'ns2:casDataType' is not valid with respect to its type, 'QName'.
ERROR endpoint.PayloadValidatingInterceptor - XML validation error on response: cvc-complex-type.2.4.d: Invalid content was found starting with element 'ns2:firstName'. No child element is expected at this point.

Cheers,

Ingo

Arjen Poutsma
Jun 19th, 2006, 11:28 AM
The Problem is, that i get an validation error in my log file. Any idea why?


Hmm, that's weird. It seems the validator cannot resolve the ns2 namespace, even though it's there. Just for an experiment, can you copy the payload of your message to a separate file, and use the standard javax.xml.validation api to validate? Something along the lines of:



SchemaFactory factory = SchemaFactory.newInstance(XMLConstants. W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new File("schema.xsd");
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File("payload.xml"));


If that doesn't give errors, it's a bug. If that also gives errors, it is consistent (though wrong). Upgrading to a newer XML parser (such as Xerces 2.8.0) might help.

Keep me informed,

res1st
Jun 20th, 2006, 06:43 AM
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCH EMA_NS_URI);
Schema schema = factory.newSchema(new File("echo.xsd"));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File("payload.xml")));
Here i'm validating against my echo.xsd from my web service. The response is:
org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'SOAP-ENV:Envelope'.
at com.sun.org.apache.xerces.internal.jaxp.validation .Util.toSAXParseException(Unknown Source)
I can understand that in that way, that i define my message types but i doesn't define the soap envelop. That's why he doesn't know the "Envelope" tag.

If i use the soap envelope schema(not my echo.xsd), it's not working.
The response is:

org.xml.sax.SAXParseException: cvc-elt.4.2: Cannot resolve 'ns2:
AddressDataType' to a type definition for element 'ns2:casDataType'.
at com.sun.org.apache.xerces.internal.jaxp.validation .Util.toSAXParseException(Unknown Source)
Ok, that's also clear. The soap-envelope schema doesn't contain my message types.

But if i use that tool (https://msv.dev.java.net) to validate against the soap envelope schema, it's says that my document is valid.

And if i use that tool to validate my payload against my echo.xsd schema, i get this response(not valid):

Error at line:3, column:61 of file:///C:/download/msv-20060319/payload.xml
tag name "SOAP-ENV:Envelope" is not allowed. Possible tag names are:
<createDataTypesRequest>,<createDataTypesResponse>,<echoRequest>,
<echoResponse>,<secureEchoRequest>,<secureEchoResponse>
the document is NOT valid.

I'm somehow confused now...any idea what's wrong?


Upgrading to a newer XML parser (such as Xerces 2.8.0) might help.
I haven't added a parser, so i think i'm using the build in parser of java5. How can i switch to the xerces-j 2.8 parser?

Cheers,

Ingo

Arjen Poutsma
Jun 20th, 2006, 10:09 AM
What I meant was just put the payload in a separate payload.xml file, just for test purposes. The file should contain something like:



<ns2:createDataTypesResponse xmlns:ns2="http://springws.cas.de">
<ns2:casDataType
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns2:AddressDataType">
<ns2:key>123</ns2:key>
<ns2:firstName>Fritz</ns2:firstName>
<ns2:lastName>Meier</ns2:lastName>
</ns2:casDataType>
</ns2:createDataTypesResponse>


Then use the snipped I gave in the previous post to validate that:



SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCH EMA_NS_URI);
Schema schema = factory.newSchema(new File("echo.xsd"));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File("payload.xml")));


And see if that works.

res1st
Jun 21st, 2006, 01:03 AM
Ok sorry.
It works, no exception. It's a bug then.

Ingo

Arjen Poutsma
Jun 21st, 2006, 04:48 AM
If it does work if you put it a separate file, it's probably a bug in SWS. Could you file one at the JIRA (http://opensource2.atlassian.com/projects/spring/browse/SWS)?

Thanks,

exgorth
Aug 15th, 2007, 12:13 PM
So is it a bug? Is there a solution to get validator working with abstract schema types?

I'm facing the same problem (http://forum.springframework.org/showthread.php?t=42668)

res1st
Aug 16th, 2007, 01:19 AM
Hi Exgorth.

Yes, it's a bug of the Java validator. I thought they will automatically update to a new xerces version which would solve the problem (i hope).

Arjen described a workaroud in my JIRA report (http://opensource.atlassian.com/projects/spring/browse/SWS-35) and i use it until now...

Cheers,

Ingo

exgorth
Aug 16th, 2007, 04:46 AM
I've set the system property:


<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<systemProperties>
<systemProperty>
<name>javax.xml.validation.SchemaFactory</name>
<value>org.apache.xerces.jaxp.validation.XMLSchemaFactory</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>

and i'm still getting the same errors :(


XML validation error on request: UndeclaredPrefix: Cannot resolve 'sch:Flight' as a QName: the prefix 'sch' is not declared.
XML validation error on request: cvc-elt.4.1: The value 'sch:Flight' of attribute 'http://www.w3.org/2001/XMLSchema-instance,type' of element 'sch:details' is not a valid QName.
XML validation error on request: cvc-type.2: The type definition cannot be abstract for element sch:details.
XML validation error on request: UndeclaredPrefix: Cannot resolve 'sch:Flight' as a QName: the prefix 'sch' is not declared.
XML validation error on request: cvc-attribute.3: The value 'sch:Flight' of attribute 'xsi:type' on element 'sch:details' is not valid with respect to its type, 'QName'.

My schema is differs from listed in SWS-35 (http://opensource.atlassian.com/projects/spring/browse/SWS-35)
in attributeFormDefault="unqualified" instead of attributeFormDefault="qualified"

So why the workaround doesn't works for me?

res1st
Aug 16th, 2007, 04:55 AM
I've set the system property:
I hope you also have a version of the original apache-xerces in your classpath? The property alone isn't enough. As far as i know, if the class of the property isn't fount, then Java falls back to the buggy version.

exgorth
Aug 16th, 2007, 05:52 AM
I've packaged app in .war file and the following jars i have in WEB-INF/lib:


acegi-security-1.0.3.jar
activation-1.1.jar
aopalliance-1.0.jar
commons-logging-1.1.jar
jaxb-api-2.1.jar
jaxb-impl-2.1.3.jar
log4j-1.2.12.jar
mail-1.4.jar
oro-2.0.8.jar
saaj-api-1.3.jar
saaj-impl-1.3.jar
spring-aop-2.0.5.jar
spring-beans-2.0.5.jar
spring-context-2.0.5.jar
spring-core-2.0.6.jar
spring-dao-2.0.6.jar
spring-oxm-1.0-rc3-SNAPSHOT.jar
spring-oxm-tiger-1.0-rc3-20070815.014704-28.jar
spring-remoting-2.0.5.jar
spring-support-2.0.5.jar
spring-web-2.0.5.jar
spring-webmvc-2.0.5.jar
spring-ws-core-1.0-rc3-SNAPSHOT.jar
spring-ws-core-tiger-1.0-rc3-20070815.014704-28.jar
spring-ws-security-1.0-rc3-20070815.014704-28.jar
spring-xml-1.0-rc3-SNAPSHOT.jar
stax-api-1.0-2.jar
stax-api-1.0.1.jar
wsdl4j-1.6.1.jar
xalan-2.7.0.jar
xercesImpl-2.8.1.jar
xml-apis-1.3.03.jar
xmldsig-1.0.jar
xmlsec-1.3.0.jar
xmlsec-2.0.jar
xws-security-2.0-FCS.jar

and deployed the .war to the clean apache-tomcat-6.0.13.

also i've added into the catalina.bat:


set JAVA_OPTS=%JAVA_OPTS% -Djavax.xml.validation.SchemaFactory=org.apache.xer ces.jaxp.validation.XMLSchemaFactory


to noop :(

Arjen Poutsma
Aug 16th, 2007, 06:46 AM
Please read the bug report carefully. The property to set is:



javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema


Note the semicolon, and the W3C schema reference after it.

So for tomcat, you would do:



set JAVA_OPTS=%JAVA_OPTS% -Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema=org.apache.xerces.jaxp.validation.XMLSch emaFactory

exgorth
Aug 16th, 2007, 07:04 AM
Thanx, Arjen and res1st.

It's all validates now!!!

for jetty i've set:


<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<systemProperties>
<systemProperty>
<name>javax.xml.validation.SchemaFactory</name>
<value>http\://www.w3.org/2001/XMLSchema=org.apache.xerces.jaxp.validation.XMLSch emaFactory</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>

and for tomcat:


set JAVA_OPTS=%JAVA_OPTS% -Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema=org.apache.xerces.jaxp.validation.XMLSch emaFactory

Again, thanx a lot!

Arjen Poutsma
Aug 16th, 2007, 07:19 AM
Great!

Note that a slightly better solution for Jetty would be this:

<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<systemProperties>
<systemProperty>
<name>javax.xml.validation.SchemaFactory\:http\://www.w3.org/2001/XMLSchema</name>
<value>org.apache.xerces.jaxp.validation.XMLSchemaFactory</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>

Since the property name is "javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema", after all.