Class 25 Using Multiple Schemas
Handout: orderDap schemas
Handout: SOAP and WSDL Example
A
particular <schema> is associated with a particular targetNS, where its
names reside (in our imagination, anyway).
So using two NS’s necessarily involves two <schema>’s, normally in
two schema docs.
Link.xsd
<link>
elements have the new NS with “/dap” at the end of the URI. Link.xsd is not
complicated, just 3 attributes in the one <link> element which is itself
global, so we don’t need elementFormDefault=”qualified”—that’s only needed when
we have non-global elements.
The
attributes are themselves non-global, i.e. “local” in the schema sense, because
their declarations <attribute…> are not direct children of
<schema>, because of the enclosing <link> element. Using the
default attributeFormDefault =”unqualified”, we never use prefixes on local
attributes, and they belong to no namespace.
Compare
<link> to XLink, covered in notes09.html, which
worked with global attributes, to
support linkage from any element that allowed global attributes in its schema.
OrderDap.xsd
The
greater challenge is understanding OrderDap.xsd. It imports Link.xsd to make its <link>
element declaration usable in its own schema. The <import> element has an
attribute listing the imported NS to make sure the right thing gets imported:
this must match the targetNS of the imported schema. The schemaLocation says
where it is, here “Link.xsd” to say it’s in the same directory as this schema.
In order
to use the imported NS names, a prefix is declared, here ns1. It’s used in ref=”ns1:link” to put a
<link> element in the “representation” type. Note that ref is typed as QName in the schema
of schemas, just like type
(see notes09.html).
Recall that name
is typed as NCName (no-colon name), because when we use it we are introducing
names into the target NS, so we have no choice about the NS. But types and ref’d
elements can come from other NS’s, as we see here.
The
representation type is itself abstract. Like an abstract Java class, we can’t
use this type directly, only by extending it.
The extensions add more things to the sequence, after the <link>
elements of the base.
Type
extension can add attributes as well as children—see the schema primer.
In this
case we only needed the one element <link>, but in other cases we could
import schema types and build our own types and elements based on imported +
local schema.
Type
extension is used in Harold Chap. 1, so we should cover that case too! See the end of the handout:
Another use
of type extension, from Harold’s order.xsd, Chap 1: add an attribute to a
SimpleType, making it a ComplexType.
<xsd:complexType
name="MoneyType">
<xsd:simpleContent>
<xsd:extension
base="xsd:decimal">
<xsd:attribute
name="currency" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
In the XML:
an element of type MoneyType:
<Total currency='USD'>290.79</Total>
Why does
such a simple XML construct need type extension to describe it? We need to put it in context of the whole
schema typing system to try to answer that.
First,
we note that the type we need is a complex type, since a simple type may not
have children elements or attributes.
Using
XPath nodes as our basic model of XML structure, we see that a text node can be
described by a SimpleType when it forms the content of an element:
Picture: <element>à<text>
[picture should be vertical]
And this
is very common at the leaves of our XML trees.
The
structure of the interior of the XML tree, we usually see:
<element>à <attribute>,…
à<element>,… children
With no
text nodes in between, and this is what can be described by our usual XML
Schema complexType declarations with sequences, etc.
If there
are text nodes in between, we say the element has “mixed content”, and XML
Schema allows us to put mixed=”true” in the <complexType> declaration.
But this only allows us to put untyped
text nodes in between the children and before and after them, and the children
still need to be ordered as specified. This is so restrictive as to be almost
useless, so we don’t often use this option.
So,
although we can type this XML by calling it “mixed” with an attribute, that’s
not great and does not allow us to use a simple type for the content.
The only
way out is to say the basic type is a simple type describing the text content,
and extend it to add in the attribute.
Not pretty!
Sketch
of example from XML Schema primer: case
of importing a type
IPO.xsd:
has
<schema targetNamespace="http://www.example.com/IPO"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ipo="http://www.example.com/IPO">
…
<simpleType
name="SKU">
<restriction base="string">
<pattern
value="\d{3}-[A-Z]{2}"/>
</restriction>
</simpleType>
…
</schema>
Report.xsd imports IPO.xsd and uses its SKU type:
<schema targetNamespace="http://www.example.com/Report"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:r="http://www.example.com/Report"
xmlns:xipo="http://www.example.com/IPO"
elementFormDefault="qualified">
<!-- for SKU -->
<import namespace="http://www.example.com/IPO"/>
…
<complexType name="PartsType">
<sequence>
<element name="part" maxOccurs="unbounded">
<complexType>
<simpleContent>
<extension base="string">
<attribute name="number" type="xipo:SKU"/>
</extension>
</simpleContent>
</complexType>
</element>
</sequence>
</complexType>
</schema>
XML of type PartsType, suitable for <parts>:
<part number="872-AA">Lawnmower</part>
<part number="926-AA">Baby Monitor</part>
<part number="833-AA">Lapis Necklace</part>
<part number="455-BX">Sturdy Shelves</part>
What
we’re seeing is again an element with string content AND an attribute. Now we
know that means using type extension from the simple type describing the
element content.
Anyway,
we see type=”xipo:SKU” to use the type imported from the other schema.
<xsd:include> just
includes other parts of schema for the same NS.
See the XML Schema Primer for examples.
SOAP Web Services
Read REST book, Chap. 11 The Web and WS-*
If interested in WSDL, see tutorial
But start now with Harold, pp. 96-99, 116-118, plus Appendix B, pp. 969-972,
firmly skipping all SOAP-ENC material (obsolete)
Basic scheme: use HTTP POST for all service request/responses, to a single service endpoint, i.e. one URL for the whole service. Use XML messages enclosed in SOAP “envelopes”.
So no idea of URI for each resource here. Orders and payments, etc, are still described in XML as in REST, but are all hidden inside the SOAP server. You ask, in XML, for what you want and the server returns it.
The basic rules of designing WS actions is the same for SOAP and REST. Invent actions that depend only on the message and persistent state held by the server—that is the basic “stateless” rule. In other words, don’t expect the server to remember what you were doing last, even if you have to authenticate yourself to get the service.
So it’s straightforward to convert a REST service to a SOAP service or vice versa. You can even reuse the schema for the “representations” of REST—now they are related to the public view of the persistent objects being manipulated by the service. We will be looking at Amazon S3 storage service. It uses one schema for both its SOAP and REST APIs.
In SOAP, there is a way to find out what requests the server can answer, via its WSDL. Unlike WADL, WSDL is widely supported and used. REST proponents would say that REST doesn’t really need WADL, since the service should give you what to do next at each step. But it would be great to know how to get started.
Pg. 97 Basic examples of SOAP messages
<?xml
version=”1.0”?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”> ßSOAP-ENV
is a prefix
<SOAP-ENV:Body>
<getQuote xmlns=”http://namespaces.cafeconleche.org/xmljava/ch2/”>
<symbol>RHAT</symbol>
</getQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
and similar message for
response
Here we see local names Envelope and Body of the SOAP envelope NS.
Notes on this simple SOAP message:
- envelope in one standard NS
- body in an app-related NS
- no address
- interoperable (like REST)
o J2EE (TOMCAT, WEBSPHERE)
.NET solution
Internationalized: XML in UTF-8 (like REST)
Lack of address: keeping it free of transport mechanism: could be HTTP, SMTP, ..., as we saw for media types used in REST.
Schema for this
SOAP Message XML
Schema for the body: See pg. 103 for schema for the request message, trading.xsd. It has our usual setup: default NS = targetNS, elementFormDefault=”qualified”.
<xsd:element name=”symbol” type=”...>
This is introducing the local name “symbol” for the target NS.
type = “StockSymbol” refers to the StockSymbol in the default NS.
We now look at how the SOAP envelope schema can handle the message part inside, which is designed by the app developers. It’s similar to the XHTML example of class 11, except it tries to validate (processContents = “lax”) rather than skipping over the enclosed XML (processContents = “skip”).
Understanding the
SOAP Envelope Schema
Not covered in
class:
If we look at the SOAP Envelope schema in Appendix B, pg. 969, we see a different starting setup than we have been using for schemas:
<xsd:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/”
targetNamespace=”http://schemas.xmlsoap.org/soap/envelope/”
…
We see there is no elementFormDefault=”qualified”. It doesn’t matter, though, because all element definitions are global, i.e, their <element> definitions are direct children of <schema>.
Here “tns” means target NS, which it is by the third line.
So there are more prefixes in this schema than we usually see:
<xs:element name=”Envelope” type = “tns:Envelope”/>
^^^
This prefix makes it very clear that the type name is in the NS, and strangely, they have both the element name “Envelope” and the type name “Envelope”, both in the namespace. There is one localname “Envelope” in the NS, with double duty as an element name and as a type name. Similarly with Body.
It uses <any ...> to allow the app to fill in any message format in XML. The <any> element is on pg. 971, inside schema element name=”Body”. The processContents = “lax” means try to use a schema if you can find one.
Validating a whole
SOAP message: need to import one schema into another
This is another example of schema using two schemas together, here the SOAP envelope schema and the app schema for the contents of Body. Need to import one schema into another.
It’s a little different than our orderDap.xsd + Link.xsd because the outer schema doesn’t itself use the elements, etc., defined in the imported schema. Consequently, it doesn’t need to define a prefix for the imported NS. Also, we aren’t in control of the outer schema (we shouldn’t edit it), so we need to expand from it in our own document, and this is where <include> comes in to use.
Harold shows us the way here, on pg. 117-118. Drop the import of “.../soap/encoding”, which we’re not using, but keep the xsd:import of trading.xsd, and the xsd:include of the SOAP envelope schema.
The <include> brings in the SOAP envelope document the way #include does in C, i.e., verbatim, so at top level of the result is the SOAP envelope schema. The <import> allows another NS’s schema to be helping out with the full schema.
It’s better to avoid the local URL in the schemaLocation value (here or anywhere), unless you are sure the validator knows what the base URL is. Should be safe if in the same directory.
For more examples, if interested: see the W3C Schema Primer, linked to class web page.