xmerl XSD validation vs xmerl_xs:select and namespaces

Robert Raschke rtrlists@REDACTED
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