Рубрики
Без рубрики

Разбор XML и создание счета-фактуры PDF с Python

Получите практические, реальные навыки Python на наших ресурсах и пути

Автор оригинала: Mike Driscoll.

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

Одной из общих задач, которые мне приведены в моем дневной работе, состоит в том, чтобы предпринять ввод формата данных и разбирать его, чтобы создать отчет или какой-то другой документ. Сегодня мы посмотрим на приему немного XML-ввода, расставив его с языком программирования Python, а затем создавая букву в формате PDF с помощью REPORTLAB, пакета 3-го вечеринка для Python. Допустим, моя компания получает заказ на три предмета, которые мне нужно выполнить. XML для этого может выглядеть следующим кодом:



    456789
    789654
    John Doe
    123 Dickens Road
    Johnston, IA 55555
    
    
        
            11123
            Expo Dry Erase Pen
            1.99
            5
        
        
            22245
            Cisco IP Phone 7942
            300
            1
        
        
            33378
            Waste Basket
            9.99
            1
        
    

Сохраните код выше как order.xml. Теперь мне просто нужно написать анализатор и генератор PDF в Python. Вы можете использовать библиотеки анализа Python встроенные XML, которые включают SAX, MiniDom или ElectionTree или вы можете выйти и загрузить одну из множества внешних пакетов для анализа XML. Мой любимый – LXML, который включает в себя версию ElectionTree, а также действительно хороший кусок кода, который они называют «объектом». Эта последняя часть будет в основном взять XML и превратить его в точечную запись Python. Я буду использовать его, чтобы сделать наш анализ, потому что это так быстро, легко реализовать и понимать. Как говорится ранее, я буду использовать ReportLab, чтобы сделать произведение PDF.

Вот простой скрипт, который сделает все, что нам нужно:

from decimal import Decimal
from lxml import etree, objectify

from reportlab.lib import colors
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch, mm
from reportlab.pdfgen import canvas
from reportlab.platypus import Paragraph, Table, TableStyle

########################################################################
class PDFOrder(object):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, xml_file, pdf_file):
        """Constructor"""
        self.xml_file = xml_file
        self.pdf_file = pdf_file
        
        self.xml_obj = self.getXMLObject()
        
    #----------------------------------------------------------------------
    def coord(self, x, y, unit=1):
        """
        # http://stackoverflow.com/questions/4726011/wrap-text-in-a-table-reportlab
        Helper class to help position flowables in Canvas objects
        """
        x, y = x * unit, self.height -  y * unit
        return x, y  
        
    #----------------------------------------------------------------------
    def createPDF(self):
        """
        Create a PDF based on the XML data
        """
        self.canvas = canvas.Canvas(self.pdf_file, pagesize=letter)
        width, self.height = letter
        styles = getSampleStyleSheet()
        xml = self.xml_obj
        
        address = """ 
        SHIP TO:

%s
%s
%s
%s
""" % (xml.address1, xml.address2, xml.address3, xml.address4) p = Paragraph(address, styles["Normal"]) p.wrapOn(self.canvas, width, self.height) p.drawOn(self.canvas, *self.coord(18, 40, mm)) order_number = 'Order #%s ' % xml.order_number p = Paragraph(order_number, styles["Normal"]) p.wrapOn(self.canvas, width, self.height) p.drawOn(self.canvas, *self.coord(18, 50, mm)) data = [] data.append(["Item ID", "Name", "Price", "Quantity", "Total"]) grand_total = 0 for item in xml.order_items.iterchildren(): row = [] row.append(item.id) row.append(item.name) row.append(item.price) row.append(item.quantity) total = Decimal(str(item.price)) * Decimal(str(item.quantity)) row.append(str(total)) grand_total += total data.append(row) data.append(["", "", "", "Grand Total:", grand_total]) t = Table(data, 1.5 * inch) t.setStyle(TableStyle([ ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black) ])) t.wrapOn(self.canvas, width, self.height) t.drawOn(self.canvas, *self.coord(18, 85, mm)) txt = "Thank you for your business!" p = Paragraph(txt, styles["Normal"]) p.wrapOn(self.canvas, width, self.height) p.drawOn(self.canvas, *self.coord(18, 95, mm)) #---------------------------------------------------------------------- def getXMLObject(self): """ Open the XML document and return an lxml XML document """ with open(self.xml_file) as f: xml = f.read() return objectify.fromstring(xml) #---------------------------------------------------------------------- def savePDF(self): """ Save the PDF to disk """ self.canvas.save() #---------------------------------------------------------------------- if __name__ == "__main__": xml = "order.xml" pdf = "letter.pdf" doc = PDFOrder(xml, pdf) doc.createPDF() doc.savePDF()

Вот выход PDF: буква .pdf

Давайте займем пару минут, чтобы пройти этот код. Первый выкл это группа импорта. Это просто устанавливает нашу среду с необходимыми союзами от ReportLab и LXML. Я также импортирую десятичный модуль, так как я буду добавлять суммы, и это гораздо точнее для поплавки математики, чем просто используя нормальную математику Python. Далее мы создаем наш класс PDForder, который принимает два аргумента: файл XML и путь к файлу PDF. В нашем методе инициализации мы создаем свойства пары класса, прочитайте файл XML и вернуть объект XML. Метод CORRES предназначен для позиционирования FlowBable ReportLab, которые являются динамическими объектами с возможностью разделяться на страницах и принять различные стили.

Метод CreatePDF – это мясо программы. Объект Canvas используется для создания нашего PDF и «ничья» на нем. Я настроил его, чтобы быть размером букв, и я также захватываю таблицу стилей по умолчанию. Затем я создаю адрес доставки и позиционируйте его рядом с верхней частью страницы, 18 мм слева и 40 мм сверху. После этого я создаю и разместить номер заказа. Наконец, я повторяю свои предметы в заказе и поместите их в вложенный список, который затем помещается в таблицу ReportLab Flowbable. Наконец, я устанавливаю таблицу и пропустите его некоторые стили, чтобы дать ему границу и внутреннюю решетку. Наконец, мы сохраняем файл на диск.

Документ создан, и теперь у меня есть хороший прототип, чтобы показать мои коллеги. На данный момент все, что мне нужно сделать, это настроить внешний вид документа, проходя в разных стилях для текста (I.E. Bold, курсив, размер шрифта) или немного изменение макета. Обычно это зависит от управления или клиента, поэтому вам придется ждать и посмотреть, что они хотят.

Теперь вы знаете, как разбирать документ XML в Python и создать PDF из анализируемых данных.

Исходный код

xml2pdfex.zip