开发者

Best way to generate xml? [duplicate]

This question already has answers here: Creating a simple XML file using python (6 answers) Closed 5 years ago.

I'm creating an web api and need a good way to very quickly generate some well formatted xml. I cannot find any good way of doing this in开发者_如何学C python.

Note: Some libraries look promising but either lack documentation or only output to files.


ElementTree is a good module for reading xml and writing too e.g.

from xml.etree.ElementTree import Element, SubElement, tostring

root = Element('root')
child = SubElement(root, "child")
child.text = "I am a child"

print(tostring(root))

Output:

<root><child>I am a child</child></root>

See this tutorial for more details and how to pretty print.

Alternatively if your XML is simple, do not underestimate the power of string formatting :)

xmlTemplate = """<root>
    <person>
        <name>%(name)s</name>
        <address>%(address)s</address>
     </person>
</root>"""

data = {'name':'anurag', 'address':'Pune, india'}
print xmlTemplate%data

Output:

<root>
    <person>
        <name>anurag</name>
        <address>Pune, india</address>
     </person>
</root>

You can use string.Template or some template engine too, for complex formatting.


Using lxml:

from lxml import etree

# create XML 
root = etree.Element('root')
root.append(etree.Element('child'))
# another child with text
child = etree.Element('child')
child.text = 'some text'
root.append(child)

# pretty string
s = etree.tostring(root, pretty_print=True)
print s

Output:

<root>
  <child/>
  <child>some text</child>
</root>

See the tutorial for more information.


I would use the yattag library.

from yattag import Doc

doc, tag, text = Doc().tagtext()

with tag('food'):
    with tag('name'):
        text('French Breakfast')
    with tag('price', currency='USD'):
        text('6.95')
    with tag('ingredients'):
        for ingredient in ('baguettes', 'jam', 'butter', 'croissants'):
            with tag('ingredient'):
                text(ingredient)
    

print(doc.getvalue())

FYI I'm the author of the library.


Use lxml.builder class, from: http://lxml.de/tutorial.html#the-e-factory

import lxml.builder as lb
from lxml import etree

nstext = "new story"
story = lb.E.Asset(
  lb.E.Attribute(nstext, name="Name", act="set"),
  lb.E.Relation(lb.E.Asset(idref="Scope:767"),
            name="Scope", act="set")
  )

print 'story:\n', etree.tostring(story, pretty_print=True)

Output:

story:
<Asset>
  <Attribute name="Name" act="set">new story</Attribute>
  <Relation name="Scope" act="set">
    <Asset idref="Scope:767"/>
  </Relation>
</Asset>


An optional way if you want to use pure Python:

ElementTree is good for most cases, but it can't CData and pretty print.

So, if you need CData and pretty print you should use minidom:

minidom_example.py:

from xml.dom import minidom

doc = minidom.Document()

root = doc.createElement('root')
doc.appendChild(root)

leaf = doc.createElement('leaf')
text = doc.createTextNode('Text element with attributes')
leaf.appendChild(text)
leaf.setAttribute('color', 'white')
root.appendChild(leaf)

leaf_cdata = doc.createElement('leaf_cdata')
cdata = doc.createCDATASection('<em>CData</em> can contain <strong>HTML tags</strong> without encoding')
leaf_cdata.appendChild(cdata)
root.appendChild(leaf_cdata)

branch = doc.createElement('branch')
branch.appendChild(leaf.cloneNode(True))
root.appendChild(branch)

mixed = doc.createElement('mixed')
mixed_leaf = leaf.cloneNode(True)
mixed_leaf.setAttribute('color', 'black')
mixed_leaf.setAttribute('state', 'modified')
mixed.appendChild(mixed_leaf)
mixed_text = doc.createTextNode('Do not use mixed elements if it possible.')
mixed.appendChild(mixed_text)
root.appendChild(mixed)

xml_str = doc.toprettyxml(indent="  ")
with open("minidom_example.xml", "w") as f:
    f.write(xml_str)

minidom_example.xml:

<?xml version="1.0" ?>
<root>
  <leaf color="white">Text element with attributes</leaf>
  <leaf_cdata>
<![CDATA[<em>CData</em> can contain <strong>HTML tags</strong> without encoding]]>  </leaf_cdata>
  <branch>
    <leaf color="white">Text element with attributes</leaf>
  </branch>
  <mixed>
    <leaf color="black" state="modified">Text element with attributes</leaf>
    Do not use mixed elements if it possible.
  </mixed>
</root>


I've tried a some of the solutions in this thread, and unfortunately, I found some of them to be cumbersome (i.e. requiring excessive effort when doing something non-trivial) and inelegant. Consequently, I thought I'd throw my preferred solution, web2py HTML helper objects, into the mix.

First, install the the standalone web2py module:

pip install web2py

Unfortunately, the above installs an extremely antiquated version of web2py, but it'll be good enough for this example. The updated source is here.

Import web2py HTML helper objects documented here.

from gluon.html import *

Now, you can use web2py helpers to generate XML/HTML.

words = ['this', 'is', 'my', 'item', 'list']
# helper function
create_item = lambda idx, word: LI(word, _id = 'item_%s' % idx, _class = 'item')
# create the HTML
items = [create_item(idx, word) for idx,word in enumerate(words)]
ul = UL(items, _id = 'my_item_list', _class = 'item_list')
my_div = DIV(ul, _class = 'container')

>>> my_div

<gluon.html.DIV object at 0x00000000039DEAC8>

>>> my_div.xml()
# I added the line breaks for clarity
<div class="container">
   <ul class="item_list" id="my_item_list">
      <li class="item" id="item_0">this</li>
      <li class="item" id="item_1">is</li>
      <li class="item" id="item_2">my</li>
      <li class="item" id="item_3">item</li>
      <li class="item" id="item_4">list</li>
   </ul>
</div>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜