Создание XML в Python

Я разрабатываю API с использованием Python, который делает серверные вызовы с использованием XML. Я обсуждаю, следует ли использовать библиотеку (например, http://wiki.python.org/moin/MiniDom), или если она будет "лучше" (что означает меньше накладных расходов и быстрее) использовать конкатенацию строк, чтобы генерировать XML, используемый для каждого запроса. Кроме того, создаваемый XML-код будет довольно динамичным, поэтому я не уверен, что преимущество, которое позволяет мне управлять элементами динамически, будет преимуществом.

Ответ 1

Я определенно рекомендую вам использовать одну из библиотек Python; например MiniDom, ElementTree, lxml.etree или pyxser. Нет причин не делать этого, и потенциальное воздействие на производительность будет минимальным.

Хотя я лично предпочитаю использовать simplejson (или просто json).

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

Ответ 2

Поскольку вы просто используете authorize.net, почему бы не использовать библиотеку, специально разработанную для API Authorize.net, и забудьте о создании собственные XML-вызовы?

Если вам нужно или нужно идти своим путем с XML, не используйте мини-диск, используйте что-то с интерфейсом ElementTree, например cElementTree (который находится в стандартной библиотеке). Это будет гораздо менее болезненным, и вероятно намного быстрее. Вам обязательно понадобится XML-библиотека для анализа XML, который вы создаете, поэтому вы можете использовать тот же API для обоих.

Очень маловероятно, что накладные расходы на использование библиотеки XML будут проблемой, и преимущество в чистом коде и зная, что вы не можете создать недопустимый XML, очень велико.

Если вам абсолютно необходимо, чтобы вы были как можно быстрее, используйте одну из чрезвычайно быстрых библиотек шаблонов, доступных для Python. Они, вероятно, будут намного быстрее, чем любая наивная последовательность конкатенаций, которую вы делаете, и также будете в безопасности (т.е. Правильно экранируйте).

Ответ 3

Мой реальный вопрос - вот что представляет собой самая большая проблема для того, чего вы пытаетесь достичь? Если вы беспокоитесь о скорости/памяти, то да, minidom делает хит. Если вы хотите что-то достаточно надежное, что вы можете быстро развертывать, я бы сказал, используйте его.

Мое предложение по работе с XML на любом языке (Java, Python, С#, Perl и т.д.) заключается в том, чтобы использовать уже существующее. Каждый из них написал свой собственный XML-парсер хотя бы один раз, а затем они никогда не делают этого снова, потому что это такая боль взади. И, честно говоря, в этих библиотеках уже зафиксировано 99,5% любых проблем, с которыми вы столкнулись.

Ответ 4

Я рекомендую LXML. Это библиотека связок Python для очень быстрых библиотек C libxml2 и libxslt.

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'

Ответ 5

Другой вариант - использовать Jinja, особенно если динамический характер вашего xml довольно прост. Это обычная идиома в колбе для генерации html-ответов.

Ниже приведен пример шаблона jinja, который генерирует XML файл aws S3 список объектов. Я обычно храню шаблон в отдельном файле, чтобы избежать загрязнения моего элегантного python с уродливым xml.

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>