Menu

Array of subclasses of a type xml output issue

Help
Omar
2014-10-15
2014-10-15
  • Omar

    Omar - 2014-10-15

    Hello,

    When I run

    $ pyxbgen -u xsd -m mynf
    $ python test.py
    

    the output is

    <ns1:B xmlns:ns1="mynf"/> <ns1:ArrayOfA xmlns:ns1="mynf"><ns1:A/></ns1:ArrayOfA>

    I would expect the array to be:
    <?xml version="1.0" ?><ns1:ArrayOfA xmlns:ns1="mynf"><ns1:B/></ns1:ArrayOfA>

    Is this a bug, or am I missing something?

    test.py is

    import mynf
    array = mynf.ArrayOfA()
    b = mynf.B()
    array.append(b)
    print b.toxml()
    print array.toxml()
    

    test.xsd

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema targetNamespace="mynf" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="mynf" elementFormDefault="qualified">
    
    <xs:complexType name="ArrayOfAType">
    <xs:sequence><xs:element minOccurs="0" maxOccurs="unbounded" name="A" nillable="true" type="tns:AType"/></xs:sequence>
    </xs:complexType>
    
    <xs:element name="ArrayOfA" nillable="true" type="tns:ArrayOfAType"/>
    
    <xs:complexType name="AType"/>
    <xs:element name="A" nillable="true" type="tns:AType"/>
    
    <xs:complexType name="BType"><xs:complexContent mixed="false">
        <xs:extension base="tns:AType"/></xs:complexContent>
    </xs:complexType>
    <xs:element name="B" nillable="true" type="tns:BType"/>
    
    </xs:schema>
    
     
  • Peter A. Bigot

    Peter A. Bigot - 2014-10-15

    No, PyXB is actually correct here, as demonstrated by independent validation:

    llc[106]$ xmllint --schema x.xsd xa.xml 
    <?xml version="1.0"?>
    <ns1:ArrayOfA xmlns:ns1="mynf"><ns1:A/></ns1:ArrayOfA>
    xa.xml validates
    llc[107]$ xmllint --schema x.xsd xb.xml 
    <?xml version="1.0"?>
    <ns1:ArrayOfA xmlns:ns1="mynf"><ns1:B/></ns1:ArrayOfA>
    xb.xml:1: element B: Schemas validity error : Element '{mynf}B': This element is not expected. Expected is ( {mynf}A ).
    xb.xml fails to validate
    

    In short, your schema does not allow an element {mynf}B to occur within complex type {mynf}ArrayOfAType. PyXB is being helpful here, and implicitly converting the (empty) content of the instance you pass into an instance A which is permitted.

    There are two underlying issues. First, you have two distinct elements A: a global {mynf}A and a local A with no namespace{mynf}A that is scoped only within {mynf}ArrayOfAType. This actually is perfectly valid, but is probably not what you intend.

    The second is that XML is not like object-oriented languages where B extends A means B isa A. You need to use substitution groups to accomplish what you want. Here's a schema that works:

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema targetNamespace="mynf" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="mynf" elementFormDefault="qualified">
    
      <xs:complexType name="ArrayOfAType">
        <xs:sequence>
          <!-- Change this to be a reference to {mynf}A -->
          <xs:element ref="tns:A" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
      </xs:complexType>
    
      <xs:element name="ArrayOfA" nillable="true" type="tns:ArrayOfAType"/>
    
      <xs:complexType name="AType"/>
      <xs:element name="A" nillable="true" type="tns:AType"/>
    
      <xs:complexType name="BType">
        <xs:complexContent mixed="false">
          <xs:extension base="tns:AType"/>
        </xs:complexContent>
      </xs:complexType>
      <!-- Add this to the substitution group for {mynf}A -->
      <xs:element name="B" nillable="true" type="tns:BType" substitutionGroup="tns:A"/>
    
    </xs:schema>
    

    Then your test program produces the desired output (and both sample documents validate).

     

    Last edit: Peter A. Bigot 2014-10-16

Log in to post a comment.