2

I have a schema with targetNamespace and unqualified element form default:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://shiporder.hu/Shiporder" 
    xmlns="http://shiporder.hu/Shiporder"
    elementFormDefault="unqualified">
    <xs:complexType name="shipordertype">
        <xs:sequence>
            <xs:element name="orderid" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
    <xs:element name="shiporder" type="shipordertype" />
</xs:schema>

I do not understand why the following instance is invalid:

<?xml version="1.0" encoding="UTF-8"?>
<shiporder 
xmlns="http://shiporder.hu/Shiporder" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://shiporder.hu/Shiporder shiporder_unqualified.xsd">
  <orderid>123456</orderid>
</shiporder>

Jaxb validation says that "Invalid content was found starting with element 'orderid'. One of '{orderid}' is expected." I am particularly puzzled by this message, if "orderid" is expected, then what's the problem with "orderid"?

This is the validation error:

org.xml.sax.SAXParseException; systemId: file:/home/riskop/git/xml_schema_elementformdefault_question/src/main/resources/order_unqualified_with_default_ns.xml; lineNumber: 6; columnNumber: 12; cvc-complex-type.2.4.a: Invalid content was found starting with element 'orderid'. One of '{orderid}' is expected. at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203) at ...

I have a little demo on github:

https://github.com/riskop/xml_schema_elementformdefault_question.git

riskop
  • 1,693
  • 1
  • 16
  • 34

3 Answers3

2

It would have been easier for you to see what was going on if instead of just telling you what it was expecting, the validator had also told you what it was finding instead.

Your schema declares that any element whose expanded name is {http://shiporder.hu/Shiporder}shiporder is of type {http://shiporder.hu/Shiporder}shipordertype. Like all elements of that type, it is declared as having exactly one child, whose expanded name is {}orderid. (Or, in the notation apparently used by your validator, {orderid}.)

The outer element in your instance has the expanded name {http://shiporder.hu/Shiporder}shiporder but it does not obey the constraint: it has a single child element, but that child has the expanded name {http://shiporder.hu/Shiporder}orderid. (Or, in the notation apparently used by your validator, http://shiporder.hu/Shiporder{orderid}.

If you want your instances to look like this sample instance, the simplest fix is to change elementFormDefault to 'qualified'. But you can also change your instance to

<?xml version="1.0" encoding="UTF-8"?>
<shiporder 
  xmlns="http://shiporder.hu/Shiporder" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://shiporder.hu/Shiporder 
  shiporder_unqualified.xsd">
    <orderid xmlns="">123456</orderid>
</shiporder>

If your reaction to the explanation just given is anything but a head-slap accompanied by "D'oh!", you may want to review the meanings of the terms "[namespace-]qualified" and "[namespace-]unqualified" and the meaning of default and other namespace declarations.

kjhughes
  • 106,133
  • 27
  • 181
  • 240
C. M. Sperberg-McQueen
  • 24,596
  • 5
  • 38
  • 65
0

Try one of the following instances instead:

<shiporder 
    xmlns="http://shiporder.hu/Shiporder"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://shiporder.hu/Shiporder shiporder_unqualified.xsd">
    <orderid>123456</orderid>
</shiporder>

or

<q:shiporder 
    xmlns:q="http://shiporder.hu/Shiporder"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://shiporder.hu/Shiporder shiporder_unqualified.xsd">
    <q:orderid>123456</q:orderid>
</q:shiporder>

elementFormDefault doesn't do what you think it does; see eg. What does elementFormDefault do for XML/When is it used? for an explanation.

imhotap
  • 2,275
  • 1
  • 8
  • 16
  • Thanks for the answer! Your first instance fails validation with ...lineNumber: 6; columnNumber: 14; cvc-complex-type.2.4.a: Invalid content was found starting with element 'orderid'. One of '{orderid}' is expected." Your second instance fails with "...lineNumber: 6; columnNumber: 16; cvc-complex-type.2.4.a: Invalid content was found starting with element 'q:orderid'. One of '{orderid}' is expected." – riskop Sep 13 '17 at 06:54
0

McQueen's answer was enlightening, thanks!

I'd like to summarize that and my understanding:

  1. elementFormDefault="unqualified" in the schema specifies two things:
    1. globally declared elements must be explicitly qualified in the instances.
    2. locally declared elements must NOT be qualified in the instances.
  2. the element "orderid" is a locally declared element in the schema, therefore "orderid" must not be qualified in the instances.
  3. the element "shiporder" in the instance is specifying a default namespace therefore all of it's children elements will be qualified therefore "orderid" in the instance is qualified, and this contradicts the 2nd point above.

That answers my question.

I still think that the JAXB validation message is puzzling and cryptic: "Invalid content was found starting with element 'orderid'. One of '{orderid}' is expected.". '{orderid}' is not as expressing as '{}orderid' would be, and also I miss the actual element from the message. I'd like to see something like this: "invalid content starting at 'orderid': actual: '{http://shiporder.hu/Shiporder}orderid'", expected: '{}orderid'. This is basically what McQueen said first in his answer.

Anyway, possible fixes in the instance are either undeclaring namespace in "orderid" element ( <orderid xmlns=""> ):

<q:shiporder 
    xmlns:q="http://shiporder.hu/Shiporder"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://shiporder.hu/Shiporder shiporder_unqualified.xsd">
    <orderid >123456</orderid>
</q:shiporder>

or not using default namespace:

<q:shiporder 
    xmlns:q="http://shiporder.hu/Shiporder"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://shiporder.hu/Shiporder shiporder_unqualified.xsd">
    <orderid >123456</orderid>
</q:shiporder>

possible fixes in the schema are either change it to qualified:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://shiporder.hu/Shiporder" 
    xmlns="http://shiporder.hu/Shiporder"
    elementFormDefault="qualified">
    <xs:complexType name="shipordertype">
        <xs:sequence>
            <xs:element name="orderid" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
    <xs:element name="shiporder" type="shipordertype" />
</xs:schema>

or change to global declarations ("unqualified" has no effect on globally declared elements, and in this case "orderid" is globally declared as well as "shiporder"):

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://shiporder.hu/Shiporder" 
    xmlns="http://shiporder.hu/Shiporder"
    elementFormDefault="unqualified">
    <xs:complexType name="shipordertype">
        <xs:sequence>
            <xs:element ref="orderid" />
        </xs:sequence>
    </xs:complexType>
    <xs:element name="shiporder" type="shipordertype" />
    <xs:element name="orderid" type="xs:string" />
</xs:schema>

...

Note that I agree with Michael Kay that specifying "qualified" for elementFormDefault in the schema, is nearly always the right thing to do...

riskop
  • 1,693
  • 1
  • 16
  • 34
  • 1
    Roughly correct, but a little oddly phrased. A schema defines a set of valid documents; it does not say you or your documents MUST do or refrain from anything; it is perfectly happy whether your documents are valid or invalid. It's also not quite true that setting elementFormDefault has effects on *all* local elements; the default value can be overridden. If one thinks in terms of the expanded names of elements as given in the schema and in the document instance, the rule is simpler: instance elements match declarations only if they have the same (expanded) name. – C. M. Sperberg-McQueen Sep 19 '17 at 16:38