Hello,

 

We have been using lxml.objectify for a while for our xml work in python and I really appreciate its neat way of converting xml Elements to python objects and vice-versa.  

That worked great until we needed to add support for an xml-based standard which extensively uses hyphens in its element names (Specifically the MDX from  ASAM https://www.asam.net/standards/detail/mdx/wiki/ ). The resulting lxml.objectify objects have a lot of attributes with hyphens which makes their use in python very cumbersome, since using hyphens in variable names in forbidden in python and results in a syntax error.

 

Googling pointed me to use getattr() / setattr() instead of the dot notation, which I have done, also in combination with xpath expressions to avoid ridiculous getattr() chains. It does do the job but the resulting code is a nightmare to work with and maintain (See example code as post scriptum below).

 

I kindly ask those of you who have extensive experience with hyphened elements to provide me some guidance on what would be the best way to proceed from here. The alternatives I see in front of me are:

1         Convert all element names to use another character (e.g. underscore) instead of hyphen before objectify parsing, and then converting back before exporting.

2         Continue with getattr() / setattr()

3         give up objectify

Obviously (and unfortunately) changing the standard is not an option.

If you have any other approaches not listed above I would be very happy if you could share them with me!

 

I am seriously considering giving alternative 1 a try and figured out I would need to convert both the schema and the xml to make objectify work.  Any tips on doing that in a smart way would be also welcome.

 

Happy holidays and thank you for your help!

 

Jonian Grazhdani

EMS Software Architect

Powertrain Control System Development

Scania CV AB

SE-151 87 Södertälje, Sweden

 

tel:    +46 (0)8 553 53427

e-mail: jonian.grazhdani@scania.com

 

P.S. Example code with two implementations:

 

    NAMESPACE = "http://www.asam.net/schema/MDX/r1.3"

    E = objectify.ElementMaker(annotate=False,

                               namespace=NAMESPACE, 

                               nsmap={ None: NAMESPACE,

                                      'xsd': 'http://www.w3.org/2001/XMLSchema',

                                      'xsi': 'http://www.w3.org/2001/XMLSchema-instance'})

 

# Implementation 1: dot notation which results in a syntax error

    self.sw_feature = E.SW-FEATURE(

        E.SHORT-NAME(self.short_name),

        E.CATEGORY("FCT"),

        E.SW-FEATURE-OWNED-ELEMENT-SETS(

            E.SW-FEATURE-OWNED-ELEMENT-SET(

                E.SW-FEATURE-ELEMENTS()

        ),

        E.SW-FEATURE-INTERFACES(),

        ID = self.id

    )

 

    if len(self.owned_elements['SW-VARIABLE-REFS']) > 0:

        self.sw_feature.SW-FEATURE-OWNED-ELEMENT-SETS.SW-FEATURE-OWNED-ELEMENT-SET.SW-FEATURE-ELEMENTS.SW-VARIABLE-REFS = E.SW-VARIABLE-REFS()

        self.sw_feature.SW-FEATURE-OWNED-ELEMENT-SETS.SW-FEATURE-OWNED-ELEMENT-SET.SW-FEATURE-ELEMENTS.SW-VARIABLE-REFS = self.owned_elements['SW-VARIABLE-REFS']

 

 

# Implementation 2: getattr / setattr with the occasional xpath

    self.sw_feature = getattr(E,'SW-FEATURE')(

        getattr(E,'SHORT-NAME')(self.short_name),

        E.CATEGORY("FCT"),

        getattr(E,'SW-FEATURE-OWNED-ELEMENT-SETS')(

            getattr(E,'SW-FEATURE-OWNED-ELEMENT-SET')(

                getattr(E,'SW-FEATURE-ELEMENTS')()                                       

            )

        ),

        getattr(E,'SW-FEATURE-INTERFACES')(),

        ID = self.id

    )

   

    mdx_sw_feature_elements = self.sw_feature.find("./{ns}SW-FEATURE-OWNED-ELEMENT-SETS/{ns}SW-FEATURE-OWNED-ELEMENT-SET/{ns}SW-FEATURE-ELEMENTS".format(ns="{" + NAMESPACE + "}"))

    if self.owned_elements['SW-VARIABLE-REFS']:

        setattr(mdx_sw_feature_elements, 'SW-VARIABLE-REFS', getattr(E, 'SW-VARIABLE-REFS')())

        mdx_sw_refs = getattr(mdx_sw_feature_elements, 'SW-VARIABLE-REFS')

        #set the objects children (e.g. SW-VARIABLE-REFS.SW-VARIABLE-REF)

        setattr('SW-VARIABLE-REFS', 'SW-VARIABLE-REF', self.owned_elements['SW-VARIABLE-REFS'])