About

Why

Python soap clients are either dead or follow the all-in-one pattern that hides all the complexity of the api from the end-user.

Python XML Binding libraries exist but either they never worked for the schemas I was working with or generated code that was very hard to read and understand.

Concept

xsData is trying to work with schema definitions by making a few assumptions about them:

  • They are opinionated

  • They are too abstract

  • There are more than one way to achieve the same result

  • There are no best practices

  • In the end Elements are classes and Attributes are class fields

  • The rest is noise or metadata :)

Compare

xsData

@dataclass
class PurchaseOrderType:
    """
    :ivar ship_to:
    :ivar bill_to:
    :ivar comment:
    :ivar items:
    :ivar order_date:
    """
    ship_to: Optional[Usaddress] = field(
        default=None,
        metadata=dict(
            name="shipTo",
            type="Element",
            required=True
        )
    )
    bill_to: Optional[Usaddress] = field(
        default=None,
        metadata=dict(
            name="billTo",
            type="Element",
            required=True
        )
    )
    comment: Optional[Comment] = field(
        default=None,
        metadata=dict(
            name="comment",
            type="Element"
        )
    )
    items: Optional[Items] = field(
        default=None,
        metadata=dict(
            name="items",
            type="Element",
            required=True
        )
    )
    order_date: Optional[str] = field(
        default=None,
        metadata=dict(
            name="orderDate",
            type="Attribute"
        )
    )

pyXB

# Complex type PurchaseOrderType with content type ELEMENT_ONLY
class PurchaseOrderType (pyxb.binding.basis.complexTypeDefinition):
    """Complex type PurchaseOrderType with content type ELEMENT_ONLY"""
    _TypeDefinition = None
    _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_ELEMENT_ONLY
    _Abstract = False
    _ExpandedName = pyxb.namespace.ExpandedName(Namespace, 'PurchaseOrderType')
    _XSDLocation = pyxb.utils.utility.Location('/home/chris/projects/xsdata/docs/examples/primer.xsd', 15, 2)
    _ElementMap = {}
    _AttributeMap = {}
    # Base type is pyxb.binding.datatypes.anyType

    # Element comment uses Python identifier comment
    __comment = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(Namespace, 'comment'), 'comment', '__AbsentNamespace0_PurchaseOrderType_comment', False, pyxb.utils.utility.Location('/home/chris/projects/xsdata/docs/examples/primer.xsd', 13, 2), )


    comment = property(__comment.value, __comment.set, None, None)


    # Element shipTo uses Python identifier shipTo
    __shipTo = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'shipTo'), 'shipTo', '__AbsentNamespace0_PurchaseOrderType_shipTo', False, pyxb.utils.utility.Location('/home/chris/projects/xsdata/docs/examples/primer.xsd', 17, 6), )


    shipTo = property(__shipTo.value, __shipTo.set, None, None)


    # Element billTo uses Python identifier billTo
    __billTo = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'billTo'), 'billTo', '__AbsentNamespace0_PurchaseOrderType_billTo', False, pyxb.utils.utility.Location('/home/chris/projects/xsdata/docs/examples/primer.xsd', 18, 6), )


    billTo = property(__billTo.value, __billTo.set, None, None)


    # Element items uses Python identifier items
    __items = pyxb.binding.content.ElementDeclaration(pyxb.namespace.ExpandedName(None, 'items'), 'items', '__AbsentNamespace0_PurchaseOrderType_items', False, pyxb.utils.utility.Location('/home/chris/projects/xsdata/docs/examples/primer.xsd', 20, 6), )


    items = property(__items.value, __items.set, None, None)


    # Attribute orderDate uses Python identifier orderDate
    __orderDate = pyxb.binding.content.AttributeUse(pyxb.namespace.ExpandedName(None, 'orderDate'), 'orderDate', '__AbsentNamespace0_PurchaseOrderType_orderDate', pyxb.binding.datatypes.date)
    __orderDate._DeclarationLocation = pyxb.utils.utility.Location('/home/chris/projects/xsdata/docs/examples/primer.xsd', 22, 4)
    __orderDate._UseLocation = pyxb.utils.utility.Location('/home/chris/projects/xsdata/docs/examples/primer.xsd', 22, 4)

    orderDate = property(__orderDate.value, __orderDate.set, None, None)

    _ElementMap.update({
        __comment.name() : __comment,
        __shipTo.name() : __shipTo,
        __billTo.name() : __billTo,
        __items.name() : __items
    })
    _AttributeMap.update({
        __orderDate.name() : __orderDate
    })
_module_typeBindings.PurchaseOrderType = PurchaseOrderType
Namespace.addCategoryObject('typeBinding', 'PurchaseOrderType', PurchaseOrderType)

JaxB

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PurchaseOrderType", propOrder = {
    "shipTo",
    "billTo",
    "comment",
    "items"
})
public class PurchaseOrderType {

    @XmlElement(required = true)
    protected USAddress shipTo;
    @XmlElement(required = true)
    protected USAddress billTo;
    protected String comment;
    @XmlElement(required = true)
    protected Items items;
    @XmlAttribute(name = "orderDate")
    @XmlSchemaType(name = "date")
    protected XMLGregorianCalendar orderDate;

    /**
     * Lots of getters/setters
     */
}