Why is there no functional xml?

Rustom Mody rustompmody at gmail.com
Sun Jan 21 10:24:31 EST 2018


On Sunday, January 21, 2018 at 4:51:34 PM UTC+5:30, Peter Otten wrote:
> Rustom Mody wrote:
> 
> > Looking around for how to create (l)xml one sees typical tutorials like
> > this:
> > 
> > https://www.blog.pythonlibrary.org/2013/04/30/python-101-intro-to-xml-parsing-with-elementtree/
> > 
> > 
> > 
> > Given the requirement to build up this xml:
> > <zAppointments reminder="15">
> >     <appointment>
> >         <begin>1181251680</begin>
> >         <uid>040000008200E000</uid>
> >         <alarmTime>1181572063</alarmTime>
> >         <state></state>
> >         <location></location>
> >         <duration>1800</duration>
> >         <subject>Bring pizza home</subject>
> >     </appointment>
> > </zAppointments>
> > 
> > 
> > 
> > the way I would rather do it is thus:
> > 
> > [Note in actual practice the 'contents' such as 1181251680 etc would come
> > from suitable program variables/function-calls
> > ]
> > 
> > 
> > ex = Ea("zAppointments",  {'reminder':'15'},
> >         E("appointment",
> >           En("begin", 1181251680),
> >           Et("uid", "040000008200E000"),
> >           En("alarmTime", 1181572063),
> >           E("state"),
> >           E("location"),
> >           En("duration",1800),
> >           Et("subject", "Bring pizza home")))
> > 
> > 
> > with the following obvious definitions:
> > 
> > [The function names are short so that the above becomes correspondingly
> > [readable]
> > 
> > 
> > from lxml.etree import Element
> > 
> > def Ea(tag, attrib=None, *subnodes):
> >     "xml node constructor"
> >     root = Element(tag, attrib)
> >     for n in subnodes:
> >         root.append(n)
> >     return root
> > 
> > def E(tag, *subnodes):
> >     "Like E but without attributes"
> >     root = Element(tag)
> >     for n in subnodes:
> >         root.append(n)
> >     return root
> > 
> > def Et(tag, text):
> >     "A pure text node"
> >     root = E(tag)
> >     root.text = text
> >     return root
> > 
> > def En(tag, text):
> >     "A node containing a integer"
> >     root = E(tag)
> >     root.text = str(text)
> >     return root
> > 
> > 
> > This approach seems so obvious that I find it hard to believe its not
> > there somewhere… Am I missing something??
> 
> lxml.objectify?
> 
> >>> from lxml import etree
> >>> from lxml.objectify import E
> >>> appointments = E.appointments(
> ...     E.appointment(
> ...         E.begin(1181251680),
> ...         E.uid("040000008200E000"),
> ...         E.alarmTime(1181572063),
> ...         E.state(),
> ...         E.location(),
> ...         E.duration(1800),
> ...         E.subject("Bring pizza home")
> ...     ),
> ...     reminder="15"
> ... )
> >>> print(etree.tostring(appointments, pretty_print=True, encoding=str))
> <appointments xmlns:py="http://codespeak.net/lxml/objectify/pytype" 
> xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" reminder="15">
>   <appointment>
>     <begin py:pytype="int">1181251680</begin>
>     <uid py:pytype="str">040000008200E000</uid>
>     <alarmTime py:pytype="int">1181572063</alarmTime>
>     <state/>
>     <location/>
>     <duration py:pytype="int">1800</duration>
>     <subject py:pytype="str">Bring pizza home</subject>
>   </appointment>
> </appointments>
> 
> >>> 

Nice!
I almost liked it… Then noticed that the attribute dict is in the wrong place
Here's the same without any namespace malarky:

>>> E = objectify.ElementMaker(annotate=False,namespace=None,nsmap=None)
>>> appointments = E.appointments(
    E.appointment(
        E.begin(1181251680),
        E.uid("040000008200E000"),
        E.alarmTime(1181572063),
        E.state(),
        E.location(),
        E.duration(1800),
        E.subject("Bring pizza home")
    ),
    reminder="15"
) 

>>> print(et.tostring(appointments,pretty_print=1).decode('ascii'))
<appointments reminder="15">
  <appointment>
    <begin>1181251680</begin>
    <uid>040000008200E000</uid>
    <alarmTime>1181572063</alarmTime>
    <state/>
    <location/>
    <duration>1800</duration>
    <subject>Bring pizza home</subject>
  </appointment>
</appointments>

>>> 

Its obviously easier in python to put optional/vararg parameters on the
right side rather than on the left of a parameter list.
But its not impossible to get it in the desired order — one just has to 
'hand-parse' the parameter list received as a *param
Thusly:

appointments = E.appointments(
   {"reminder":"15"},
   E.appointment(
        E.begin(1181251680),
        E.uid("040000008200E000"),
        E.alarmTime(1181572063),
        E.state(),
        E.location(),
        E.duration(1800),
        E.subject("Bring pizza home")
    ) 
)

> 
> Personally I'd probably avoid the extra layer and write a function that 
> directly maps dataclasses or database records to xml using the conventional 
> elementtree API.

I dont understand…
[I find the OO/imperative style of making a half-done node and then throwing
piece-by-piece of contents in/at it highly aggravating]





More information about the Python-list mailing list