TONY.SU
Loxun - потоковая генерация xml в python
Loxun - отличная замена для XMLGenerator из xml.sax. В чем его плюсы перед последним:
SAX:
xml = XMLGenerator(out) xml.startDocument() xml.startElement('root') xml.startElement('body') xml.startElement('item') xml.characters('some data') xml.endElement('item') xml.endElement('body') xml.endElement('root') xml.endDocument()
Loxun:
xml = XmlWriter(out) xml.startTag('root') xml.startTag('body') xml.startTag('item') xml.text('somedata') xml.endTag() xml.endTag() xml.endTag()
Либо еще короче вместо трех вызовов endTag можно сделать xml.endTags() и все открытые элементы закроются автоматически.
Пойдем далее, необходимо добавить элемент вида:
<addr host="127.0.0.1" port="8080" />
SAX:
xml.startElement('addr', {'host': '127.0.0.1', 'port': 8000}) xml.endElement('addr')
Loxun:
xml.tag('addr', {'host': '127.0.0.1', 'port': 8080})
Работа с xmlns
SAX:
xml = XMLGenerator(out) xml.startDocument() xml.startElement('root', {'xmlns:g': '/some/url/to/xmlns'}) xml.startElement('item') xml.startElementNS('image', 'g') xml.characters('some data') xml.endElementNS('image', 'g') # ....
Loxun:
xml = XmlWriter(out) xml.addNamespace('xmlns:g', '/some/url/to/xmlns') xml.startTag('root') xml.startTag('item') xml.startTag('g:image') xml.text('somedata') xml.endTags()
Преимущество такого подхода в том, что значительно упрощается автоматизация, ниже будет пример. Но есть и другие полезные вещи loxun которых нет в SAX:
- Никаких UnicodeDecodeError loxun конвертирует в unicode сам.
- XmlWriter сам по себе является context-manager'ом, а значит можно использовать with.
- Полезная функция сделанная мной - возможно использовать method chaining.
- pretty-print из коробки.
И так, пример генерации google merchant feed.
from loxun import ChainXmlWriter SITE_TITLE = 'tony.su' SITE_LINK = 'tony.su' SITE_DESCRIPTION = "tony's blog" def export_merchant_xml(file, products): with ChainXmlWriter(file) as xml: xml.addNamespace('g', 'http://base.google.com/ns/1.0') xml.startTag('rss', {'version': '2.0'}).startTag('channel') xml.startTag('title').text(SITE_TITLE).endTag() xml.startTag('link').text(SITE_LINK).endTag() xml.startTag('description').cdata(SITE_DESCRIPTION).endTag() xml_fields = ( ('title', 'title'), ('link', 'get_absolute_url'), ('description', 'descr_short'), ('g:image_link', 'get_pic_url'), ('g:price', 'price'), ('g:condition', 'condition'), ('g:id', 'get_merchant_id'), ) for product in products: xml.startTag('item') for xml_field, attr_name in xml_fields: xml.startTag(xml_field) attr = getattr(product, attr_name) xml.text(unicode(attr if not callable(attr) else attr())) xml.endTag() xml.endTag() xml.endTags() def main(): with open('merchant.xml', 'w') as f: products = [] # итератор с объектами загруженными из базы данных export_merchant_xml(f, products) if __name__ == '__main__': main()
- 05 Ноя 23:00
