【问题标题】:Generating XML in Python在 Python 中生成 XML
【发布时间】:2013-04-27 04:56:51
【问题描述】:

我正在使用 Python 开发一个 API,它使用 XML 进行服务器调用。我正在讨论是否使用库(例如http://wiki.python.org/moin/MiniDom),或者使用字符串连接来生成用于每个请求的 XML 是否会“更好”(意味着更少的开销和更快的速度)。此外,我将生成的 XML 将是非常动态的,所以我不确定允许我动态管理元素的东西是否会带来好处。

【问题讨论】:

  • 个人资料,个人资料,个人资料。
  • 为什么不使用 JSON?该模块易于使用,是 Web API 的标准,并且独立于平台。
  • 我希望你使用 JSON。不幸的是,我使用的 API (Authorize.net) 并没有完全适应更好的网络技术。

标签: python xml


【解决方案1】:

既然您只是使用 authorize.net,为什么不使用 a library specifically designed for the Authorize.net API 而忘记构建自己的 XML 调用?

如果您想要或需要使用自己的方式使用 XML,请不要使用 minidom,而是使用带有 ElementTree 接口的东西,例如 cElementTree(在标准库中)。它会少得多痛苦和probably much faster。您肯定需要一个 XML 库来解析您生成的 XML,因此您不妨为两者使用相同的 API。

使用 XML 库的开销不太可能成为问题,而干净的代码和知道您不能生成无效 XML 的好处非常大。

如果您绝对肯定需要尽可能快,请使用可用于 Python 的extremely fast templating libraries 之一。它们可能比你做的任何简单的字符串连接都要快得多,而且也是安全的(即进行适当的转义)。

【讨论】:

    【解决方案2】:

    另一种选择是使用Jinja,尤其是当您的 xml 的动态特性相当简单时。这是flask中用于生成html响应的常用习语。

    这是一个 jinja 模板示例,它生成 aws S3 list objects 响应的 XML。我通常将模板存储在一个单独的文件中,以避免用丑陋的 xml 污染我优雅的 python。

    from datetime import datetime
    from jinja2 import Template
    
    list_bucket_result = """<?xml version="1.0" encoding="UTF-8"?>
    <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
        <Name>{{bucket_name}}</Name>
        <Prefix/>
        <KeyCount>{{object_count}}</KeyCount>
        <MaxKeys>{{max_keys}}</MaxKeys>
        <IsTruncated>{{is_truncated}}</IsTruncated>
        {%- for object in object_list %}
        <Contents>
            <Key>{{object.key}}</Key>
            <LastModified>{{object.last_modified_date.isoformat()}}</LastModified>
            <ETag></ETag>
            <Size>{{object.size}}</Size>
            <StorageClass>STANDARD</StorageClass>
        </Contents>{% endfor %}
    </ListBucketResult>
    """
    
    class BucketObject:
        def __init__(self, key, last_modified_date, size):
            self.key = key
            self.last_modified_date = last_modified_date
            self.size = size
    
    object_list = [
        BucketObject('/foo/bar.txt', datetime.utcnow(), 10*1024 ),
        BucketObject('/foo/baz.txt', datetime.utcnow(), 29*1024 ),
    ]
    
    template = Template(list_bucket_result)
    result = template.render(
        bucket_name='test-bucket',
        object_count=len(object_list),
        max_keys=1000,
        is_truncated=False,
        object_list=object_list
    )
    print result
    

    输出:

    <?xml version="1.0" encoding="UTF-8"?>
    <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
        <Name>test-bucket</Name>
        <Prefix/>
        <KeyCount>2</KeyCount>
        <MaxKeys>1000</MaxKeys>
        <IsTruncated>False</IsTruncated>
        <Contents>
            <Key>/foo/bar.txt</Key>
            <LastModified>2017-10-31T02:28:34.551000</LastModified>
            <ETag></ETag>
            <Size>10240</Size>
            <StorageClass>STANDARD</StorageClass>
        </Contents>
        <Contents>
            <Key>/foo/baz.txt</Key>
            <LastModified>2017-10-31T02:28:34.551000</LastModified>
            <ETag></ETag>
            <Size>29696</Size>
            <StorageClass>STANDARD</StorageClass>
        </Contents>
    </ListBucketResult>
    

    【讨论】:

      【解决方案3】:

      我绝对建议您使用其中一个 Python 库;如MiniDomElementTreelxml.etreepyxser。没有理由不这样做,并且潜在的性能影响将是最小的。

      虽然,我个人更喜欢使用simplejson(或简称json)。

      my_list = ["Value1", "Value2"]
      json = simplejson.dumps(my_list)
      # send json
      

      【讨论】:

        【解决方案4】:

        我真正的问题是,对于您要完成的工作,最大的担忧是什么?如果您担心速度/内存,那么是的,minidom 确实会受到打击。如果您想要一些可以快速部署的相当可靠的东西,我会说使用它。

        对于用任何语言(Java、Python、C#、Perl 等)处理 XML,我的建议是考虑使用已经存在的东西。每个人都至少编写过一次自己的 XML 解析器,然后他们就再也不会这样做了,因为这在背后太痛苦了。公平地说,这些库已经解决了您遇到的任何问题的 99.5%。

        【讨论】:

          【解决方案5】:

          我推荐LXML。它是一个绑定非常快的 C 库 libxml2libxslt 的 Python 库。

          LXML 支持 XPATH,并具有 elementTree 实现。 LXML 还有一个名为 objectify 的接口,用于将 XML 编写为对象层次结构:

          from lxml import etree, objectify
          E = objectify.ElementMaker(annotate=False)
          
          my_alpha = my_alpha = E.alpha(E.beta(E.gamma(firstattr='True')),
                                        E.beta(E.delta('text here')))
          etree.tostring(my_alpha)
          # '<alpha><beta><gamma firstattr="True"/></beta><beta><delta>text here</delta></beta></alpha>'
          
          etree.tostring(my_alpha.beta[0])
          # '<beta><gamma firstattr="True"/></beta>'
          
          my_alpha.beta[1].delta.text
          # 'text here'
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-10-04
            • 1970-01-01
            • 2021-11-22
            • 2017-03-17
            • 2011-03-04
            相关资源
            最近更新 更多