【问题标题】:Best way to generate xml? [duplicate]生成xml的最佳方法? [复制]
【发布时间】:2011-04-20 03:37:24
【问题描述】:

我正在创建一个 web api,需要一种快速生成格式良好的 xml 的好方法。我在 python 中找不到任何好的方法。

注意:有些库看起来很有前途,但要么缺少文档,要么只输出到文件。

【问题讨论】:

    标签: python xml api


    【解决方案1】:

    ElementTree 是一个很好的读取 xml 和写入的模块,例如

    from xml.etree.ElementTree import Element, SubElement, tostring
    
    root = Element('root')
    child = SubElement(root, "child")
    child.text = "I am a child"
    
    print(tostring(root))
    

    输出:

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

    请参阅此tutorial 了解更多详细信息以及如何进行漂亮的打印。

    或者,如果您的 XML 很简单,请不要低估字符串格式化的力量 :)

    xmlTemplate = """<root>
        <person>
            <name>%(name)s</name>
            <address>%(address)s</address>
         </person>
    </root>"""
    
    data = {'name':'anurag', 'address':'Pune, india'}
    print xmlTemplate%data
    

    输出:

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

    您也可以使用 string.Template 或一些模板引擎来进行复杂的格式化。

    【讨论】:

    • 小心使用第二种方法,因为它不引用特殊字符,所以如果您的数据包含诸如&lt;&gt;&amp; 之类的字符,您最终可能会得到格式错误的 xml。
    • ...或者更糟的是,它可能允许注入攻击,具体取决于您是否在其中放置任何类型的用户输入。
    【解决方案2】:

    使用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
    

    输出:

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

    请参阅tutorial 了解更多信息。

    【讨论】:

    • 如何将结果写入 xml 文件?
    【解决方案3】:

    我会使用yattag 库。

    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())
    

    仅供参考,我是图书馆的作者。

    【讨论】:

    • 我不确定,我应该认为它实际上是美丽的还是丑陋的。到目前为止,我已经使用with 语句打开文件,我认为它有助于“清理”或“关闭”我在with 语句之后直接写的任何内容。所以在这种情况下,它会关闭标签?还是在打开文件时会像文件句柄一样把它们扔掉?如果它把它扔掉,那为什么它还在最终输出中?一定是因为那个text() 函数。但这不是绕开了with 语句的特性吗?
    • yattag.org 上的官方文档很好地解释了它是如何工作的“标签方法返回一个上下文管理器。在 Python 中,上下文管理器是一个可以在 with 语句中使用的对象。上下文manager 有 enterexit 方法。enter 方法在 with 块和 exit 的开头调用离开块时调用方法。现在我想你可以明白为什么这对于生成 xml 或 html 很有用。with tag('h1') 创建一个

      标签。它将在 with 块的末尾关闭。这样您就不必担心关闭标签。”

    【解决方案4】:

    使用 lxml.builder 类,来自: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)
    

    输出:

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

    【讨论】:

    • 这太棒了,谢谢!想使用 John Smith Optional 提供的 Yattag,但很高兴知道我最喜欢的 lxml 有相同的方法。
    【解决方案5】:

    如果你想使用纯 Python 的可选方式:

    ElementTree 适用于大多数情况,但不能CDatapretty print

    所以,如果你需要 CDatapretty print 你应该使用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>
    

    【讨论】:

      【解决方案6】:

      我已经尝试了这个线程中的一些解决方案,但不幸的是,我发现其中一些很麻烦(即在做一些不平凡的事情时需要过度努力)并且不优雅。因此,我想我会将我的首选解决方案web2py HTML helper objects 加入其中。

      首先,安装standalone web2py module

      pip install web2py
      

      不幸的是,上面安装了一个非常过时的 web2py 版本,但对于这个例子来说已经足够了。更新的来源是here

      导入记录在 here 的 web2py HTML 帮助器对象。

      from gluon.html import *
      

      现在,您可以使用 web2py 助手来生成 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>
      

      【讨论】:

        猜你喜欢
        • 2011-11-30
        • 2011-02-08
        • 1970-01-01
        • 2020-07-17
        • 1970-01-01
        • 2013-10-19
        • 2011-06-09
        • 2012-01-31
        • 2011-05-18
        相关资源
        最近更新 更多