Search code examples
xmlpython-3.xpyxb

How to avoid the creation of anonymous classes in pyxb when using xsd file


I'm trying to implement a connection to some API. During the communication I get as payload xml code. They provide a .xsd-file with the xml description. Now I want to parse the xml string and get the appropriate class in return. This functionality seems to be implemented best by PyXB.

To create the python bindings, I used the following code:

pyxben -u my_schema.csd -m my_schema

If I import my_schema in python3 and use my_schema.CreateFromDocument('some correct looking xml'), for some classes it returns the correct class, for some classes it returns some anonymous class type. The variables are all implemented correctly, meaning they become an attribute of the returned class, but the type of the class is incorrect.

This is obvious from the source my_schema.py, because the type of class is set to CTD_ANON_XX. Some friend implemented the same in C# and everything worked out fine, so the xsd scheme seems to be alright (and the source suggests that it should be alright).

The python bindings work e.g. for the following class:

<xs:complexType name="OrdrBookEntry">
    <xs:attribute name="ordrId" type="longType" use="required"/>
    <xs:attribute name="qty" type="quantityType" use="required"/>
    <xs:attribute name="px" type="priceType" use="required"/>
    <xs:attribute name="ordrEntryTime" type="dateTimeType" use="required"/>
    <xs:attribute name="ordrExeRestriction" type="ordrRestrictionType" use="optional"/>
    <xs:attribute name="ordrType" type="ordrType" use="optional" />
</xs:complexType>

But it fails for the following type:

<xs:element name="PblcOrdrBooksResp" final="#all">
    <xs:complexType>
        <xs:annotation>
            <xs:documentation>

            </xs:documentation>
        </xs:annotation>
        <xs:sequence>
            <xs:element name="StandardHeader" type="standardHeaderType" minOccurs="1" maxOccurs="1"/>
            <xs:element name="OrdrbookList"  minOccurs="0" maxOccurs="1">
                <xs:complexType>
                    <xs:sequence minOccurs="1" maxOccurs="1">
                        <xs:element name="OrdrBook" type="OrdrBook" minOccurs="0" maxOccurs="unbounded"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>

As mentioned, the definition works fine in C#. Is this a bug in pyxb or is there something wrong with the xml definition? Do I miss something about the usage of pyxb? Can anyone help me?

I want to avoid playing around with the scheme definition. If there is a new release, I would need to start fixing everything over and over...

EDIT: To clarify: We get a xml header like the following:

<?xml version="1.0" ?><PblcOrdrBooksResp xmlns="www.apisite.com">
<StandardHeader marketId="EPEX"/>
<OrdrbookList>
...
</OrdrbookList></PblcOrdrBooksResp>

We now want to use pyxb to initiate the correct class and then read from the object what kind of content was send!?

So from the example above we would expect (or wish)

my_object = mypyxb.module.CreatefromDocument(xml)
type(my_object)

to return its type

PblcOrdrBooksResp

Or at least have a attribute with the correct type...


Solution

  • This is neither a bug in PyXB nor something wrong with your schema--it's a consequence of the schema design. The inner OrdrBookList element has a type that does not have a name in its own right, because it's defined within the context of another type, the one for the enclosing element PblkOrdrBooksResp (which also does not have a name). Elements and types are not the same thing, so they have to have different names: attempting to infer a non-anonymous name for an inner type can create conflicts when the same element uses a different type in a different context. PyXB avoids that by making the anonymity explicit.

    There's discussion of this schema style and how deal with it in the PyXB documentation. See also this posting and others on that forum.

    Response to edit

    You are instantiating the class from the xml. You converted XML to a Python instance of a Python type that corresponds to an XML type that has no name. The Python type has a name: a unique identifier that indicates it's an anonymous complex type.

    It sounds like what you call "class" is what PyXB calls an element. PyXB lets you use elements in code as if they were classes to create bound instances, but they aren't classes.

    The instance you created from XML is bound to an element which has an expanded name. You'll see it when you convert the instance back to XML, or can get the name, scope, and other information by calling my_object._element():

    print my_object._element().name()