xmerl XSD validation vs xmerl_xs:select and namespaces
Robert Raschke
<
>
Thu Jul 30 14:48:18 CEST 2009
Hi,
I'm a bit confused by the xmerl XSD validation. It seems that trying to
validate internal elements sometimes fails for reasons that are not clear to
me.
When using the purchase order example from
http://www.w3.org/TR/xmlschema-0/with the changes to make it use
namespaces:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://www.example.com/PO1"
targetNamespace="http://www.example.com/PO1"
elementFormDefault="qualified">
<xsd:element name="purchaseOrder" type="po:PurchaseOrderType"/>
<xsd:element name="comment" type="xsd:string"/>
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element name="shipTo" type="po:USAddress"/>
<xsd:element name="billTo" type="po:USAddress"/>
<xsd:element ref="po:comment" minOccurs="0"/>
<xsd:element name="items" type="po:Items"/>
</xsd:sequence>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
<xsd:complexType name="USAddress">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="street" type="xsd:string"/>
<xsd:element name="city" type="xsd:string"/>
<xsd:element name="state" type="xsd:string"/>
<xsd:element name="zip" type="xsd:decimal"/>
</xsd:sequence>
<xsd:attribute name="country" type="xsd:NMTOKEN"
fixed="US"/>
</xsd:complexType>
<xsd:complexType name="Items">
<xsd:sequence>
<xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="productName" type="xsd:string"/>
<xsd:element name="quantity">
<xsd:simpleType>
<xsd:restriction base="xsd:positiveInteger">
<xsd:maxExclusive value="100"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="USPrice" type="xsd:decimal"/>
<xsd:element ref="po:comment" minOccurs="0"/>
<xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="partNum" type="po:SKU" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<!-- Stock Keeping Unit, a code for identifying products -->
<xsd:simpleType name="SKU">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[A-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
And a simple XML file that goes with this:
<?xml version="1.0"?>
<purchaseOrder xmlns="http://www.example.com/PO1"
orderDate="1999-10-20">
<shipTo country="US">
<name>Alice Smith</name>
<street>123 Maple Street</street>
<city>Mill Valley</city>
<state>CA</state>
<zip>90952</zip>
</shipTo>
<billTo country="US">
<name>Robert Smith</name>
<street>8 Oak Avenue</street>
<city>Old Town</city>
<state>PA</state>
<zip>95819</zip>
</billTo>
<comment>Hurry, my lawn is going wild</comment>
<items>
<item partNum="926-AA">
<productName>Baby Monitor</productName>
<quantity>1</quantity>
<USPrice>39.98</USPrice>
<shipDate>1999-05-21</shipDate>
</item>
</items>
</purchaseOrder>
Everything validates just fine:
Erlang (BEAM) emulator version 5.6.5 [smp:2] [async-threads:0]
Eshell V5.6.5 (abort with ^G)
1> rr(xmerl).
[xmerl_event,xmerl_fun_states,xmerl_scanner,xmlAttribute,
xmlComment,xmlContext,xmlDecl,xmlDocument,xmlElement,
xmlNamespace,xmlNode,xmlNsNode,xmlObj,xmlPI,xmlText]
2> {X01, _} = xmerl_scan:file("po.xml").
{#xmlElement{
name = purchaseOrder,expanded_name = purchaseOrder,
nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [],pos = 1,
attributes =
[#xmlAttribute{
name = xmlns,expanded_name = [],nsinfo = [],namespace = [],
parents = [],pos = 1,language = [],
value = "http://www.example.com/PO1",normalized = false},
#xmlAttribute{
name = orderDate,expanded_name = [],nsinfo = [],
namespace = [],parents = [],pos = 2,language = [],
value = "1999-10-20",normalized = false}],
content =
[#xmlText{
parents = [{purchaseOrder,1}],
pos = 1,language = [],value = "\n ",type = text},
#xmlElement{
name = shipTo,expanded_name = shipTo,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 2,
attributes =
[#xmlAttribute{
name = country,expanded_name = [],nsinfo = [],
namespace = [],parents = [],pos = 1,language =
[],...}],
content =
[#xmlText{
parents = [{shipTo,2},{purchaseOrder,1}],
pos = 1,language = [],value = "\n ",type = text},
#xmlElement{
name = name,expanded_name = name,nsinfo = [],
namespace = #xmlNamespace{...},
parents = [...],...},
#xmlText{
parents = [{shipTo,2},{purchaseOrder,...}],
pos = 3,language = [],
value = [...],...},
#xmlElement{
name = street,expanded_name = street,nsinfo =
[],...},
#xmlText{parents = [{...}|...],pos = 5,...},
#xmlElement{name = city,...},
#xmlText{...},
{...}|...],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 3,language = [],value = "\n ",type = text},
#xmlElement{
name = billTo,expanded_name = billTo,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 4,
attributes =
[#xmlAttribute{
name = country,expanded_name = [],nsinfo = [],
namespace = [],parents = [],...}],
content =
[#xmlText{
parents = [{billTo,4},{purchaseOrder,...}],
pos = 1,language = [],
value = [...],...},
#xmlElement{
name = name,expanded_name = name,nsinfo = [],...},
#xmlText{parents = [{...}|...],pos = 3,...},
#xmlElement{name = street,...},
#xmlText{...},
{...}|...],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 5,language = [],value = "\n ",type = text},
#xmlElement{
name = comment,expanded_name = comment,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 6,attributes = [],
content = [#xmlText{parents = [{...}|...],pos = 1,...}],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 7,language = [],value = "\n ",type = text},
#xmlElement{
name = items,expanded_name = items,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 8,attributes = [],
content = [#xmlText{...},{...}|...],
language = [],
xmlbase = [...],...},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 9,language = [],value = "\n",type = text}],
language = [],xmlbase = ".",elementdef = undeclared},
[]}
3> xmerl_xsd:process_validate("po.xsd", X01).
{#xmlElement{
name = purchaseOrder,expanded_name = purchaseOrder,
nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [],pos = 1,
attributes =
[#xmlAttribute{
name = xmlns,expanded_name = [],nsinfo = [],namespace = [],
parents = [],pos = 1,language = [],
value = "http://www.example.com/PO1",normalized = false},
#xmlAttribute{
name = orderDate,expanded_name = [],nsinfo = [],
namespace = [],parents = [],pos = 2,language = [],
value = "1999-10-20",normalized = false}],
content =
[#xmlText{
parents = [{purchaseOrder,1}],
pos = 1,language = [],value = "\n ",type = text},
#xmlElement{
name = shipTo,expanded_name = shipTo,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 2,
attributes =
[#xmlAttribute{
name = country,expanded_name = [],nsinfo = [],
namespace = [],parents = [],pos = 1,language =
[],...}],
content =
[#xmlText{
parents = [{shipTo,2},{purchaseOrder,1}],
pos = 1,language = [],value = "\n ",type = text},
#xmlElement{
name = name,expanded_name = name,nsinfo = [],
namespace = #xmlNamespace{...},
parents = [...],...},
#xmlText{
parents = [{shipTo,2},{purchaseOrder,...}],
pos = 3,language = [],
value = [...],...},
#xmlElement{
name = street,expanded_name = street,nsinfo =
[],...},
#xmlText{parents = [{...}|...],pos = 5,...},
#xmlElement{name = city,...},
#xmlText{...},
{...}|...],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 3,language = [],value = "\n ",type = text},
#xmlElement{
name = billTo,expanded_name = billTo,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 4,
attributes =
[#xmlAttribute{
name = country,expanded_name = [],nsinfo = [],
namespace = [],parents = [],...}],
content =
[#xmlText{
parents = [{billTo,4},{purchaseOrder,...}],
pos = 1,language = [],
value = [...],...},
#xmlElement{
name = name,expanded_name = name,nsinfo = [],...},
#xmlText{parents = [{...}|...],pos = 3,...},
#xmlElement{name = street,...},
#xmlText{...},
{...}|...],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 5,language = [],value = "\n ",type = text},
#xmlElement{
name = comment,expanded_name = comment,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 6,attributes = [],
content = [#xmlText{parents = [{...}|...],pos = 1,...}],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 7,language = [],value = "\n ",type = text},
#xmlElement{
name = items,expanded_name = items,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',nodes = []},
parents = [{purchaseOrder,1}],
pos = 8,attributes = [],
content = [#xmlText{...},{...}|...],
language = [],
xmlbase = [...],...},
#xmlText{
parents = [{purchaseOrder,1}],
pos = 9,language = [],value = "\n",type = text}],
language = [],xmlbase = ".",elementdef = undeclared},
{xsd_state,"po.xsd",
[138828883239791335015413488673396043202],
false,".",[],[],[],qualified,unqualified,undefined,
'http://www.example.com/PO1',
[{"po",'http://www.example.com/PO1'},
{"xsd",'http://www.w3.org/2001/XMLSchema'},
{"xml",'http://www.w3.org/XML/1998/namespace'}],
[{'http://www.example.com/PO1',
[{"xsd",'http://www.w3.org/2001/XMLSchema'},
{"po",'http://www.example.com/PO1'}]}],
[{"#this#","po.xsd",'http://www.example.com/PO1'},
{"xml",[],'http://www.w3.org/XML/1998/namespace'}],
28685,false,false,[],[],#Fun<xmerl_xsd.0.57810061>,[],0,[],
[],[],[],...}}
But if I edit the XML to have some prefix namespaced elements around the
outside:
<?xml version="1.0"?>
<p:foo xmlns:p="foobar"><p:bar>
<purchaseOrder xmlns="http://www.example.com/PO1"
orderDate="1999-10-20">
<shipTo country="US">
<name>Alice Smith</name>
<street>123 Maple Street</street>
<city>Mill Valley</city>
<state>CA</state>
<zip>90952</zip>
</shipTo>
<billTo country="US">
<name>Robert Smith</name>
<street>8 Oak Avenue</street>
<city>Old Town</city>
<state>PA</state>
<zip>95819</zip>
</billTo>
<comment>Hurry, my lawn is going wild</comment>
<items>
<item partNum="926-AA">
<productName>Baby Monitor</productName>
<quantity>1</quantity>
<USPrice>39.98</USPrice>
<shipDate>1999-05-21</shipDate>
</item>
</items>
</purchaseOrder>
</p:bar></p:foo>
And then I retrieve the default namespaced purchaseOrder element using
xmerl_xs:select/2, then the XSD validation fails:
4> {X02, _} = xmerl_scan:file("po.xml").
{#xmlElement{
name = 'p:foo',expanded_name = 'p:foo',
nsinfo = {"p","foo"},
namespace =
#xmlNamespace{default = [],nodes = [{"p",foobar}]},
parents = [],pos = 1,
attributes =
[#xmlAttribute{
name = 'xmlns:p',expanded_name = [],nsinfo = [],
namespace = {"xmlns","p"},
parents = [],pos = 1,language = [],value = "foobar",
normalized = false}],
content =
[#xmlElement{
name = 'p:bar',expanded_name = 'p:bar',
nsinfo = {"p","bar"},
namespace =
#xmlNamespace{default = [],nodes = [{"p",foobar}]},
parents = [{'p:foo',1}],
pos = 1,attributes = [],
content =
[#xmlText{
parents = [{'p:bar',1},{'p:foo',1}],
pos = 1,language = [],value = "\n",type = text},
#xmlElement{
name = purchaseOrder,expanded_name = purchaseOrder,
nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',...},
parents = [{...}|...],
pos = 2,...},
#xmlText{
parents = [{'p:bar',1},{'p:foo',1}],
pos = 3,language = [],value = "\n",type = text}],
language = [],xmlbase = ".",elementdef = undeclared}],
language = [],xmlbase = ".",elementdef = undeclared},
[]}
5> [X03] = xmerl_xs:select("/p:foo/p:bar/*", X02).
[#xmlElement{
name = purchaseOrder,expanded_name = purchaseOrder,
nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',
nodes = [{"p",foobar}]},
parents = [{'p:bar',1},{'p:foo',1}],
pos = 2,
attributes =
[#xmlAttribute{
name = xmlns,expanded_name = [],nsinfo = [],namespace = [],
parents = [],pos = 1,language = [],
value = "http://www.example.com/PO1",normalized = false},
#xmlAttribute{
name = orderDate,expanded_name = [],nsinfo = [],
namespace = [],parents = [],pos = 2,language = [],
value = "1999-10-20",normalized = false}],
content =
[#xmlText{
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 1,language = [],value = "\n ",type = text},
#xmlElement{
name = shipTo,expanded_name = shipTo,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',
nodes = [{"p",foobar}]},
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 2,
attributes =
[#xmlAttribute{
name = country,expanded_name = [],nsinfo = [],
namespace = [],parents = [],pos = 1,language =
[],...}],
content =
[#xmlText{
parents =
[{shipTo,2},
{purchaseOrder,2},
{'p:bar',1},
{'p:foo',...}],
pos = 1,language = [],value = "\n ",type = text},
#xmlElement{
name = name,expanded_name = name,nsinfo = [],
namespace = #xmlNamespace{...},
parents = [...],...},
#xmlText{
parents = [{shipTo,2},{purchaseOrder,...},{...}|...],
pos = 3,language = [],
value = [...],...},
#xmlElement{
name = street,expanded_name = street,nsinfo =
[],...},
#xmlText{parents = [{...}|...],pos = 5,...},
#xmlElement{name = city,...},
#xmlText{...},
{...}|...],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 3,language = [],value = "\n ",type = text},
#xmlElement{
name = billTo,expanded_name = billTo,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',
nodes = [{"p",foobar}]},
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 4,
attributes =
[#xmlAttribute{
name = country,expanded_name = [],nsinfo = [],
namespace = [],parents = [],...}],
content =
[#xmlText{
parents = [{billTo,4},{purchaseOrder,...},{...}|...],
pos = 1,language = [],
value = [...],...},
#xmlElement{
name = name,expanded_name = name,nsinfo = [],...},
#xmlText{parents = [{...}|...],pos = 3,...},
#xmlElement{name = street,...},
#xmlText{...},
{...}|...],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 5,language = [],value = "\n ",type = text},
#xmlElement{
name = comment,expanded_name = comment,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',
nodes = [{"p",foobar}]},
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 6,attributes = [],
content = [#xmlText{parents = [{...}|...],pos = 1,...}],
language = [],xmlbase = ".",elementdef = undeclared},
#xmlText{
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 7,language = [],value = "\n ",type = text},
#xmlElement{
name = items,expanded_name = items,nsinfo = [],
namespace =
#xmlNamespace{
default = 'http://www.example.com/PO1',
nodes = [{"p",foobar}]},
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 8,attributes = [],
content = [#xmlText{...},{...}|...],
language = [],
xmlbase = [...],...},
#xmlText{
parents = [{purchaseOrder,2},{'p:bar',1},{'p:foo',1}],
pos = 9,language = [],value = "\n",type = text}],
language = [],xmlbase = ".",elementdef = undeclared}]
6> xmerl_xsd:process_validate("po.xsd", X03).
{error,
[{"p:foo[1]/p:bar[1]",xmerl_xsd,
{element_not_in_schema,
[purchaseOrder,
{purchaseOrder,[],foobar},
{schema,undefined,undefined,undefined,[],[],undefined,
[]}]}}]}
Does anyone know why this might be the case?
Thanks for any info,
Robby
More information about the erlang-questions
mailing list