Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Python

ANN: XML builder for Python

 

 

Python python RSS feed   Index | Next | Previous | View Threaded


jonas at codeazur

Jul 2, 2008, 5:16 PM

Post #1 of 12 (131 views)
Permalink
ANN: XML builder for Python

Not sure if it's been done before, but still...

from __future__ import with_statement
from xmlbuilder import builder, element

xml = builder(version="1.0", encoding="utf-8")
with xml.feed(xmlns='http://www.w3.org/2005/Atom'):
xml.title('Example Feed')
xml.link(None, href='http://example.org/')
xml.updated('2003-12-13T18:30:02Z')
with xml.author:
xml.name('John Doe')
xml.id('urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6')
with xml.entry:
xml.title('Atom-Powered Robots Run Amok')
xml.link(None, href='http://example.org/2003/12/13/atom03')
xml.id('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a')
xml.updated('2003-12-13T18:30:02Z')
xml.summary('Some text.')
print xml

Will produce:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Example Feed</title>
<link href="http://example.org/" />
<updated>2003-12-13T18:30:02Z</updated>
<author>
<name>John Doe</name>
</author>
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
<entry>
<title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03" />
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary>
</entry>
</feed>

http://github.com/galvez/gae-rest/tree/258066f5e1a32c999e04a9313943fdfa8e64edd9/xmlbuilder.py

--Jonas Galvez
--
http://mail.python.org/mailman/listinfo/python-list


stefan_ml at behnel

Jul 2, 2008, 9:59 PM

Post #2 of 12 (131 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Jonas Galvez wrote:
> Not sure if it's been done before, but still...

Obviously ;)

http://codespeak.net/lxml/tutorial.html#the-e-factory

... and tons of other tools that generate XML, check PyPI.

Stefan
--
http://mail.python.org/mailman/listinfo/python-list


stefan_ml at behnel

Jul 2, 2008, 10:02 PM

Post #3 of 12 (131 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Stefan Behnel wrote:
> Jonas Galvez wrote:
>> Not sure if it's been done before, but still...
>
> Obviously ;)
>
> http://codespeak.net/lxml/tutorial.html#the-e-factory
>
> ... and tons of other tools that generate XML, check PyPI.

Although it might be the first time I see the with statement "misused" for
this. :)

Stefan
--
http://mail.python.org/mailman/listinfo/python-list


grflanagan at gmail

Jul 3, 2008, 12:29 AM

Post #4 of 12 (122 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Jonas Galvez wrote:
> Not sure if it's been done before, but still...
>
> from __future__ import with_statement
> from xmlbuilder import builder, element
>
> xml = builder(version="1.0", encoding="utf-8")
> with xml.feed(xmlns='http://www.w3.org/2005/Atom'):
> xml.title('Example Feed')
> xml.link(None, href='http://example.org/')
> xml.updated('2003-12-13T18:30:02Z')
> with xml.author:
> xml.name('John Doe')
> xml.id('urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6')
> with xml.entry:
> xml.title('Atom-Powered Robots Run Amok')
> xml.link(None, href='http://example.org/2003/12/13/atom03')
> xml.id('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a')
> xml.updated('2003-12-13T18:30:02Z')
> xml.summary('Some text.')
> print xml
>
> Will produce:
>
> <?xml version="1.0" encoding="utf-8"?>
> <feed xmlns="http://www.w3.org/2005/Atom">
> <title>Example Feed</title>
> <link href="http://example.org/" />
> <updated>2003-12-13T18:30:02Z</updated>
> <author>
> <name>John Doe</name>
> </author>
> <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
> <entry>
> <title>Atom-Powered Robots Run Amok</title>
> <link href="http://example.org/2003/12/13/atom03" />
> <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
> <updated>2003-12-13T18:30:02Z</updated>
> <summary>Some text.</summary>
> </entry>
> </feed>
>
> http://github.com/galvez/gae-rest/tree/258066f5e1a32c999e04a9313943fdfa8e64edd9/xmlbuilder.py
>
> --Jonas Galvez
> --
> http://mail.python.org/mailman/listinfo/python-list
>

Nice! Here's a version that uses elementtree:

8<----------------------------------------------------
from __future__ import with_statement
from xml.etree import ElementTree as ET


class element(object):
def __init__(self, name, parent):
self.parent = parent
self.element = ET.SubElement(parent, name)
def __str__(self):
return ET.tostring(self.parent)
def __getattr__(self, name):
return element(name, self.parent)
def __getitem__(self, name):
return element(name, self.parent)
def __enter__(self):
self.parent = self.element
return self
def __exit__(self, type, value, tb):
pass
def __call__(self, value='', **kargs):
self.element.text = value
self.element.attrib = kargs
return self

class builder(element):
def __init__(self, version, encoding):
self.parent = ET.Element('root')

if __name__ == "__main__":
xml = builder(version="1.0", encoding="utf-8")
with xml.feed(xmlns='http://www.w3.org/2005/Atom') as feed:
feed.title('Example Feed')
feed.link(href='http://example.org/')
feed.updated('2003-12-13T18:30:02Z')
with feed.author as author:
author.name('John Doe')
feed.id('urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6')
with feed.entry as entry:
entry.title('Atom-Powered Robots Run Amok', class_='l')
entry.link(href='http://example.org/2003/12/13/atom03')
entry.id('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a')
entry.updated('2003-12-13T18:30:02Z')
entry.summary('Some text.')
with feed.entry as entry:
entry.title('2')
entry.link(href='2')
entry.id('2')
entry.updated('2')
entry.summary('2')
print xml
8<----------------------------------------------------




--
http://mail.python.org/mailman/listinfo/python-list


walter at livinglogic

Jul 3, 2008, 4:37 AM

Post #5 of 12 (114 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Stefan Behnel wrote:
> Stefan Behnel wrote:
>> Jonas Galvez wrote:
>>> Not sure if it's been done before, but still...
>> Obviously ;)
>>
>> http://codespeak.net/lxml/tutorial.html#the-e-factory
>>
>> ... and tons of other tools that generate XML, check PyPI.
>
> Although it might be the first time I see the with statement "misused" for
> this. :)

XIST has been using with blocks since version 3.0.

Take a look at:
http://www.livinglogic.de/Python/xist/Examples.html


from __future__ import with_statement

from ll.xist import xsc
from ll.xist.ns import html, xml, meta

with xsc.Frag() as node:
+xml.XML()
+html.DocTypeXHTML10transitional()
with html.html():
with html.head():
+meta.contenttype()
+html.title("Example page")
with html.body():
+html.h1("Welcome to the example page")
with html.p():
+xsc.Text("This example page has a link to the ")
+html.a("Python home page", href="http://www.python.org/")
+xsc.Text(".")

print node.conv().bytes(encoding="us-ascii")

Servus,
Walter
--
http://mail.python.org/mailman/listinfo/python-list


stefan_ml at behnel

Jul 3, 2008, 6:32 AM

Post #6 of 12 (110 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Hi, two comments.

Gerard flanagan <grflanagan <at> gmail.com> writes:
> Nice! Here's a version that uses elementtree:
[...]
> def __call__(self, value='', **kargs):
> self.element.text = value

This should spell

def __call__(self, value=None, **kargs):


> class builder(element):
> def __init__(self, version, encoding):
> self.parent = ET.Element('root')

And this might need some more work to fix as the root element shouldn't be
necessary. But it's a good start. Look at the link I posted for some more
ideas.

Stefan


--
http://mail.python.org/mailman/listinfo/python-list


jonas at codeazur

Jul 3, 2008, 8:12 AM

Post #7 of 12 (113 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Walter Dörwald wrote:
> XIST has been using with blocks since version 3.0.
> [...]
> with xsc.Frag() as node:
> +xml.XML()
> +html.DocTypeXHTML10transitional()
> with html.html():
> [...]

Sweet! I don't like having to use the unary operator tho, I wanted
something as simple as possible, so I wouldn't even have to assign a
variable on the with block ("as something"). I plan to add some
validation and error checking, but for generating feeds for my Atom
store it's reasonably fast and lean (just over 50 lines of code).

--Jonas Galvez, http://jonasgalvez.com.br/log
--
http://mail.python.org/mailman/listinfo/python-list


stefan_ml at behnel

Jul 3, 2008, 12:04 PM

Post #8 of 12 (107 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Hi,

Walter Dörwald wrote:
> XIST has been using with blocks since version 3.0.
>
> Take a look at:
> http://www.livinglogic.de/Python/xist/Examples.html
>
>
> from __future__ import with_statement
>
> from ll.xist import xsc
> from ll.xist.ns import html, xml, meta
>
> with xsc.Frag() as node:
> +xml.XML()
> +html.DocTypeXHTML10transitional()
> with html.html():
> with html.head():
> +meta.contenttype()
> +html.title("Example page")
> with html.body():
> +html.h1("Welcome to the example page")
> with html.p():
> +xsc.Text("This example page has a link to the ")
> +html.a("Python home page", href="http://www.python.org/")
> +xsc.Text(".")
>
> print node.conv().bytes(encoding="us-ascii")

Interesting. Is the "+" actually required? Are there other operators that make
sense here? I do not see what "~" or "-" could mean.

Or is it just a technical constraint?

I'm asking because I consider adding such a syntax to lxml as a separate
module. And I'd prefer copying an existing syntax over a (badly) home grown one.

Stefan
--
http://mail.python.org/mailman/listinfo/python-list


jonas at codeazur

Jul 3, 2008, 1:49 PM

Post #9 of 12 (107 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Stefan Behnel wrote:
> Interesting. Is the "+" actually required? Are there other operators
> that make sense here? I do not see what "~" or "-" could mean.
> Or is it just a technical constraint?
> I'm asking because I consider adding such a syntax to lxml as
> a separate module. And I'd prefer copying an existing syntax over
> a (badly) home grown one.

I believe it's related to something tricky about the with statement.

You have to be able to call the "element builder" both in the with statement:

with xml.element ...

And also inside the block itself:

with xml.element ...:
xml.otherelement()

Except the with element expects an object that implements __enter__()
and __exit__().

The solution I found to this was to make __getattr__() return a
ready-to-use object that implements those methods while also taking
keyword parameters but *not* text. So for instance:

with xml.element(foo=1):
xml.foo("bar")

Will work (<element foo=1><foo>bar</foo></element>) but:

with xml.element("text", foo=1):
xml.foo("bar")

Will not. Also, in inline calls to the builder you have to explictly
set the element-content (value) parameter, even if it's simply None,
so __call__() can identify that you're (supposedly) calling it inline
and not with the 'with' statement.

That is an acceptable tradeoff, however, considering you would rarely
append text nodes right after an element while also having other child
elements. I believe my xmlbuilder will work well for Atom, XML-RPC,
SOAP etc, but definitely not for HTML! :)

Overriding + is a rather clever way to prevent this (so you can
actually know you're calling it inline), but I don't really see a need
for it for most things XML.

--Jonas Galvez, http://jonasgalvez.com.br/log
--
http://mail.python.org/mailman/listinfo/python-list


walter at livinglogic

Jul 3, 2008, 2:46 PM

Post #10 of 12 (106 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Stefan Behnel wrote:
> Hi,
>
> Walter Dörwald wrote:
>> XIST has been using with blocks since version 3.0.
>>
>> Take a look at:
>> http://www.livinglogic.de/Python/xist/Examples.html
>>
>>
>> from __future__ import with_statement
>>
>> from ll.xist import xsc
>> from ll.xist.ns import html, xml, meta
>>
>> with xsc.Frag() as node:
>> +xml.XML()
>> +html.DocTypeXHTML10transitional()
>> with html.html():
>> with html.head():
>> +meta.contenttype()
>> +html.title("Example page")
>> with html.body():
>> +html.h1("Welcome to the example page")
>> with html.p():
>> +xsc.Text("This example page has a link to the ")
>> +html.a("Python home page", href="http://www.python.org/")
>> +xsc.Text(".")
>>
>> print node.conv().bytes(encoding="us-ascii")
>
> Interesting. Is the "+" actually required? Are there other operators that make
> sense here? I do not see what "~" or "-" could mean.

Of course the node constructor could append the node to the currently
active element. However there might be cases where you want to do
something else with the newly created node, so always appending the node
is IMHO the wrong thing.

> Are there other operators that make
> sense here? I do not see what "~" or "-" could mean.
>
> Or is it just a technical constraint?

You need *one* operator/method that appends a node to the currently
active block without opening another new block. This operator should be
short to type and should have the right connotations. I find that unary
+ is perfect for that.

> I'm asking because I consider adding such a syntax to lxml as a separate
> module. And I'd prefer copying an existing syntax over a (badly) home
grown one.

"Existing syntax" might be a little exaggeration, I know of no other
Python package that uses __pos__ for something similar. (But then again,
I know of no other Python package that uses with block for generating
XML ;)).

Servus,
Walter

--
http://mail.python.org/mailman/listinfo/python-list


walter at livinglogic

Jul 3, 2008, 2:48 PM

Post #11 of 12 (107 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Jonas Galvez wrote:
> Walter Dörwald wrote:
>> XIST has been using with blocks since version 3.0.
>> [...]
>> with xsc.Frag() as node:
>> +xml.XML()
>> +html.DocTypeXHTML10transitional()
>> with html.html():
>> [...]
>
> Sweet! I don't like having to use the unary operator tho, I wanted
> something as simple as possible, so I wouldn't even have to assign a
> variable on the with block ("as something").

You only have to assign the node a name in the outermost with block so
that you can use the node object afterwards. But of course you can
always implement the outermost __enter__/__exit__ in such a way, that
the node gets written to an outputstream immediately.

> I plan to add some
> validation and error checking, but for generating feeds for my Atom
> store it's reasonably fast and lean (just over 50 lines of code).

Servus,
Walter
--
http://mail.python.org/mailman/listinfo/python-list


jonas at codeazur

Jul 3, 2008, 7:30 PM

Post #12 of 12 (100 views)
Permalink
Re: ANN: XML builder for Python [In reply to]

Walter Dörwald wrote:
> Of course the node constructor could append the
> node to the currently active element. However there
> might be cases where you want to do something else
> with the newly created node, so always appending the
> node is IMHO the wrong thing.

Unless you're using it as a templating engine of sorts, much like
Ruby's builder used in Rails.

Which is exactly what I'm trying to get at. I don't want to store the
tree in any way or be able to modify it afterwards, I just want to
generate the XML as the block is executed. Using ElementTree as
suggested previously might be a good solution if you want to preserve
what you've generated, tho.

--Jonas Galvez
--
http://mail.python.org/mailman/listinfo/python-list

Python python RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact lists@gossamer-threads.com
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.