How do I reference a schema defined in the same WSDL file? - xsd

I got a wsdl file that defines two schemas for the same namespace, like this:
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/payments"
attributeFormDefault="unqualified" elementFormDefault="qualified"
targetNamespace="http://example.com/payments">
<xsd:complexType name="TestType">
<xsd:sequence>
<xsd:element name="Version" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/payments"
attributeFormDefault="unqualified" elementFormDefault="qualified"
targetNamespace="http://example.com/payments">
<xsd:element name="TestRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Header" type="TestType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
Sure enough TestType can't be referenced from the TestRequest. I've found several answers that show how you'd do that for different files via a xsd:include (as I'm using the same targetNamespace), but I'm at a loss at how to give the schemaLocation to include?
Note that whether not this is something I should be doing is not the question. I know the issue disappears if I move the element definitions into the same schema definition.

For XSDs embedded inside WSDLs, things are different than what you've looked at, considering the answer you've linked in your question.
Short answers:
one cannot create xsd:include references between schemas nested within a WSDL's types section.
xsd:import is supported by most WSDL processors. However, you do not supply the schemaLocation attribute. In effect, it creates a dangling schema reference, with the WSDL itself acting similarly to an XML catalog.
There is no standard way to point at schemas inside arbitrary XML files (other then the .XSD file format, where the whole file is for one schema only). Of course, XPointer or something similar might've worked; but nobody seems to have implement a solution for this in an XSD or WSDL processor.
The fact that your schemas with the same namespace are not working shows a limitation in the implementation of your WSDL processor. There should be no reason to have dangling imports resolved, but not schemas with a target namespace. The reason of the latter highlight is that schemas with no namespace can be included and/or imported, which would cause ambiguity.

WSDL is itself not the XSD Schema language, so to reference it from your XSD file through xs:include you will have to get rid of the surrounding wsdl:types and you will have to store both schema's in separate files (or, since they are in the same namespace anyway, simply remove the extra xsd:schema element, but not its contents).
You could do that with a trivial XSLT (root note removed for brevity, make sure to declare the relevant namespaces):
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" />
</xsl:copy>
</xsl:template>
<xsl:template match="wsdl:types">
<xsl:apply-templates select="xsd:schema[1]" />
</xsl:template>
<xsl:template match="xsd:schema">
<xsl:copy>
<xsl:copy-of select="#*" />
<xsl:apply-templates />
<xsl:apply-templates select="following-sibling::xsd:schema/*" />
</xsl:copy>
</xsl:template>
If this is a one-off task, then you can simply run this once against your WSDL, save the results and reference them by relative file URI. If you need to do this more often, you should probably automate this.

Related

CXF JAXB basics Equals/Hashcode

I have a problem generating equals and hashcode methods for my imported xsd files which are output to a separate location to my wsdl files. I currently have a .wsdl and .xsd file in the same folder. The .wsdl file imports these xsd files which have a different namespace to the wsdl file. When these xsd files are generated they do not contain equals or hashcode methods. Below is a sample of my pom/xml config and files:
<wsdlOption>
<wsdl>
src/main/xml/wsdl/Rule.wsdl
</wsdl>
<wsdlLocation>classpath:wsdl/Rule.wsdl</wsdlLocation>
<bindingFiles>
<bindingFile>src/main/xml/wsdl/bindings.xjb</bindingFile>
</bindingFiles>
<extraargs>
<extraarg>-impl</extraarg>
<extraarg>-verbose</extraarg>
<extraarg>-xjc-XsimpleEquals</extraarg>
<extraarg>-xjc-XsimpleHashCode</extraarg>
</extraargs>
</wsdlOption>
Sample wsdl (imported Rule.xsd is not generating methods):
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ws.com/Rule/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Rule"
targetNamespace="http://www.ws.com/Rule/">
<wsdl:types>
<xsd:schema targetNamespace="http://http://www.ws.com/Rule/">
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ws.com/Rule/"
xmlns:pref="http://www.xsd.com/Rule" xmlns:pref1="http://www.xsd.com/Common">
<xsd:import schemaLocation="Rule.xsd"
namespace="http://www.xsd.com/Rule">
</xsd:import>
<xsd:import schemaLocation="Common.xsd" namespace="http://www.xsd.com/Common"></xsd:import>
<xsd:element name="ListGrid">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="request"
type="pref:test" maxOccurs="1" minOccurs="1">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
I assume this is a problem with the location of the generated xsd as I can get it to work by moving this to the same parent folder as the wsdl namespace. I would like to get this to work without moving these files locations as I have a large codebase that would require a large refactor if I do this.
Any suggestions would be welcome.
I found a solution to this problem by adding the following to the pom.xml configuration:
<extraarg>-p</extraarg>
<extraarg>http://www.xsd.com/Rule=com.xsd.rule</extraarg>
Even though this does not change the namespace/package location it seems to now generate the imported files equals and hashcode methods.

XSD Validation: Use attribute in same file as definition?

I have a large .xsd file structured like this:
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns="foo:bar:baz" xmlns:quux="foo:bar:baz"
quux:attr1="A" quux:attr2="5">
<xsd:attribute name="attr1" type="xsd:string"/>
<xsd:attribute name="attr2" type="xsd:int"/>
<xsd:annotation>
<xsd:documentation>
<xhtml:h1 quux:attr1="A" quux:attr2="5">
Documentation here
</xhtml:h1>
</xsd:documentation>
</xsd:annotation>
<xsd:complexType name=... />
</xsd:schema>
I get the error: "The foo:bar:baz:attr1" attribute is not declared.
Why is it not finding the attribute? It's right there. How can I make these attributes available to the documentation's header?
Future edit: the above schema got the green light from actual XML Validators. Guess there was just something Visual Studio was reading incorrectly.
The XSD you show can be imported or included into another XSD that includes an element declaration, but alone it cannot be used to validate an XML file because it does not declare even a single element.

Referencing an element without including/importing the schemaLocation in which it is defined

I have two xsd files. 1st file is common.xsd and the other is node.xsd. Both node.xsd and common.xsd share the same targetNamespace. common.xsd references an element defined in node.xsd using ref attribute. However, node.xsd is NOT included in common.xsd either using include or import. But the XML that I validate using these xsd files, passes the validation (Tried all corner usecases).
I wonder how this is possible. Is this because, they share the same namespace? Also is referencing an element without including/importing legal in XSD?
EDIT:
Simplified Code Snippets(The actual xsd's are much more complex and they are written in this format for bigger reason):
common.xsd
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:my="my-namespace"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
targetNamespace="my-namespace"
elementFormDefault="qualified">
<xsd:element name="common" type="my:commonType" />
<xsd:complexType name="commonType">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="my:node"/>
<!-- few other elements -->
</xsd:choice>
</xsd:complexType>
</xsd:schema>
node.xsd
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:my="my-namespace"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
targetNamespace="my-namespace"
elementFormDefault="qualified">
<xsd:include schemaLocation=common.xsd"/>
<xsd:element name="node" type="my:nodeType"
substitutionGroup="my:common" />
<xsd:complexType name="nodeType">
<xsd:complexContent>
<xsd:extension base="my:commonType">
<!-- some 5-7 attributes -->
<xsd:anyAttribute/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
These xsd's let me nest element within itself any number of times.
E.g
<my:node>
<my:node />
<my:node>
<my:node />
</my:node>
</my:node>
You can observe that my:node is referenced in common.xsd without including node.xsd. (Curious as to how this even works.)
I can make this look even more wicked... You can remove the xsd:include in node.xsd and still validate your XML! Take a look at this Xerces API for how you could do it.
The idea is that from a spec perspective, an XML Schema processor can resolve schema locations in many ways. It also means that some XSD files when looked at individually may not be valid due to dangling references, yet when put together through APIs like the one above, or custom resolvers (e.g. supporting "catalog" files) the result is an equivalent schema that is valid.
The way an XSD processor typically works, is that it puts together all the schema components that can be loaded through the references it can resolve, then it looks at the result as a whole, irrespective of where these components come from. In your case, node.xsd brings in common.xsd; the result is a valid schema, since all that is needed for components in common.xsd can be found among components already brought in by node.xsd.
In your case it is as if the inner content of the xsd:schema tag in common.xsd replaces the xsd:include in node.xsd. If you do that by hand, the result is correct, right?
As I side note, I would point out that the snippets you've shown don't illustrate the use of the common substitution group. As a reminder, you have to reference the head of the substitution group if you want you to get substitution going.

XSD annotation and documentation elements, and how to use them

We are creating xml files that we want to be compliant with the following xsd: http://www.topografix.com/gpx/1/1/gpx.xsd This xsd supports '...extending by adding your own elements here ...', see the extensionsType, which I have copied below for convenience.
1) I don't understand whether annotation and documentation are literal element names that would appear in compliant xml. I believe they are not but need confirmation. I'm assuming then that a compliant document would simply have any number of our own custom elements anywhere inside of any [extensions] element, correct?
2) Why are there two pairs of annotation/documentation elements below, with one in a sequence?
<xsd:complexType name="extensionsType">
<xsd:annotation>
<xsd:documentation>
You can add extend GPX by adding your own elements from another schema here.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
You can add extend GPX by adding your own elements from another schema here.
</xsd:documentation>
</xsd:annotation>
</xsd:any>
</xsd:sequence>
</xsd:complexType>
1) From the XML Schema specification: "Annotations provide for human- and machine-targeted annotations of schema components." Schema authors use xsd:documentation as, say Java or .NET, developers use comments.
Annotations are XML Schema artifacts; they are not to show up in an XML document. And yes, your extensions elements should go under <extensions/>; you may use any namespace, other than http://www.topografix.com/GPX/1/1
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1" creator="creator1" xmlns="http://www.topografix.com/GPX/1/1">
<extensions>
<my:element xmlns:my="urn:tempuri-org:some">Hello!</my:element>
</extensions>
</gpx>
2) Hard to say why there are two with the same comment; the difference though is that one documents the complex type, while the other the xsd:any element. I would personally have used different comments, first to explain what the complex type is for, the second just as shown.

Use XML schema to specify default namespace in XML instance

I'm not sure if it matters, but I'm using BizTalk 2009 to generate the XML.
Is there a way to specify in my XML schema that the generated XML instance should use the target namespace as the default namespace?
If I have an xsd file like this:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/">
<xs:element name="example">
<xs:complexType>
<xs:attribute name="value" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:schema>
It creates an XML file like this:
<ns0:example value="something" xmlns:ns0="http://example.com/" />
But I want it to create an XML file like this:
<example value="something" xmlns="http://example.com/" />
I know that they're technically equivalent, but the consumers (vendor APIs) are poorly implemented and I'd like to give them what they expect.
I would expect that it depends on the software generating the instance, not the schema. XSD Schema was developed for validation of XML instances against a schema, not for generating instances from it. So it is unlikely to be present explicitly in XMLSchema. The generating tools might, however, use the fact that elements were (un)qualified
elementFormDefault="(un)qualified"
to trigger the prefixing.
Not completely in scope, but the following is worth reading for schema design: http://www.xfront.com/HideVersusExpose.html
One way would be to define a schema without the namespace. Map the BizTalk schema to the newly defined schema without namespace. From a BizTalk viewpoint, you would have a schema which represents the actual contract with the consumers. (i.e. without namespaces) Also, BizTalk uses namespace#rootnodename to define messageTypes. In this example, you would have two schemas
somenamespace#somerootnodename
#somerootnodename
The possible drawbacks of this approach are this would limiting the usage of this schema (#rootnodename) to 1 instance with the BizTalk group.
This is the default behaviour of BizTalk working this XML schemas and, as far as I know, there is no builtin way to change this.
What you really want, however, is that outbound messages conform to a cleaner and more liberal format than what is used by BizTalk. You can do this by using a custom pipeline component (and a custom send pipeline) to process the outgoing message before it leaves BizTalk.
The idea is to change the namespace prefix as part of sending the message outside BizTalk. The transformation happens during the processing of the send pipeline.
Nic Barden has blogged and provided some source code about this here. You can use his sample as the basis for performing replacement of namespace prefixes, rather than replacing namespaces themselves.
I strongly encourage you to check out the whole series of posts he's done about Developing Streaming Pipeline Components. Nic has made an extensive and thorough job of describing all that's needed to author robust and enterprise-class pipeline components.
Part 1
Part 2
Part 3
Part 4
Part 5
The ns0 prefix is added whenever a BizTalk btm maps a message. It shouldn't matter as this is still valid xml, however this could be a problem when sending messages to partners with legacy or incomplete xml parsers.
You can remove the ns0 prefix and instead make ns0 your default namespace on the output message by changing your btm from a visual map to an .xslt map.
e.g. Once you have converted your map to xslt, change the xslt from:
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl s0"
version="1.0"
xmlns:ns0="http://targetns"
xmlns:s0="http://sourcens"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="s0:FromRoot" />
</xsl:template>
<xsl:template match="s0:FromRoot">
<ns0:ToRoot>
<xsl:for-each select="s0:FromElement">
<ns0:ToElement>
<xsl:value-of select="text()"/>
</ns0:ToElement>
</xsl:for-each>
</ns0:ToRoot>
</xsl:template>
</xsl:stylesheet>
To:
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
exclude-result-prefixes="msxsl s0"
version="1.0"
xmlns="http://targetns"
xmlns:s0="http://sourcens"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="s0:FromRoot" />
</xsl:template>
<xsl:template match="s0:FromRoot">
<ToRoot>
<xsl:for-each select="s0:FromElement">
<ToElement>
<xsl:value-of select="text()"/>
</ToElement>
</xsl:for-each>
</ToRoot>
</xsl:template>
</xsl:stylesheet>
i.e. change the default xmlns and then remove the ns0 prefixes automatically.
A more generic solution is also possible (e.g. similar to Firras' answer here), which could be useful e.g. to place as a send port map to strip out all prefixes from elements. However, one needs to be wary if there are more than one xmlns on the output message!

Resources