Menu

Create instance of element (instead of type) which exists in a nested element structure

Help
theSiegs
2015-04-24
2015-05-06
  • theSiegs

    theSiegs - 2015-04-24

    My schema uses the style that W3 calls "Named Types" (see here, and scroll down). Basically, I have all of my ComplexType types defined, and each type definition contains the appropriate elements. I then have one root element. An excerpt from the linked page that is similar to my setup is below.

    ~~~~~~~~~~~
    <xs:complexType name="itemtype">
    <xs:sequence>
    <xs:element name="title" type="stringtype"/>
    <xs:element name="note" type="stringtype" minOccurs="0"/>
    <xs:element name="quantity" type="inttype"/>
    <xs:element name="price" type="dectype"/>
    </xs:sequence>
    </xs:complexType>

    <xs:complexType name="shipordertype">
    <xs:sequence>
    <xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
    </xs:sequence>
    <xs:attribute name="orderid" type="inttype" use="required"/>
    </xs:complexType>

    <xs:element name="shiporder" type="shipordertype"/>
    ~~~~~~~~~~~~~

    My question is; how do I create an instance of item (of type itemtype) without creating a valid instance of shiporder every time? My use-case is using xml fragments to assemble the fully-formed xml document, which will be valid against the schema. My nesting goes pretty deep, so I'd need to create 5 or 6 parent elements in some cases if I went that route. I also don't want to have every one of my complexTypes to have a top-level element in the schema.

    I can create an instance of itemtype, but as has been pointed out repeatedly, it won't be bound to an element, and therefore I can't .toxml() it, etc.

    Thanks for any insight!

     
  • Peter A. Bigot

    Peter A. Bigot - 2015-04-24

    As you note, you can create an instance of itemtype directly and use it. It will be bound to the element when you assign it to the corresponding attribute of a complex type, you just won't be able to treat it as an XML element instance (e.g. convert it to XML) until it's been bound.

    If you do want to treat it as XML before it's been bound, you need to use _setElement. For that you also need the corresponding element binding, which you can get from _ElementBindingDeclForName given the immediately containing complex type and the name of the element within that type.

    In the example you reference you'd do something like:

    import shiporder
    i = shiporder.itemtype(title='t', quantity=2, price='2.49')
    (eb, ed) = shiporder.shipordertype._ElementBindingDeclForName('item')
    i._setElement(eb)
    print i.toxml('utf-8')
    

    Be careful overriding which element a given type instance is associated with: validation generally requires a bidirectional link, and changing the element of a type instance without removing the reference to that instance from the element it used to be associated with could result in inconsistent data structures.

     
  • theSiegs

    theSiegs - 2015-05-06

    Thanks for the response, Peter, and sorry about the delay.

    I'm not able to use the string name of the element in the parent complexType to get the element binding, as you demonstrated. I get:

    AttributeError: type object 'str' has no attribute 'elementBinding'
    

    It seems that it wants an instance of pyxb.namespace.ExpandedName.

    I've tried getting that from the class, but if there are a bunch of entries in the _ElementMap for the class, I have to loop and find the matching localName.

    for el in shiporder.shipordertype._ElementMap:
        if el.localName() = 'item':
            expName = el
            break
    (eb, ed) = shiporder.shipordertype._ElementBindingDeclForName(expName)
    i._setElement(eb)
    
     
  • Peter A. Bigot

    Peter A. Bigot - 2015-05-06

    Yes, if the element has a name that isn't in an absent namespace you'd need an ExpandedName to do the lookup. You can get one with something like:

    shiporder.Namespace.createExpandedName('item')
    
     

Log in to post a comment.