Как пройти через файл .txt для создания XML - PullRequest
1 голос
/ 10 июля 2020

Я хочу создать файл XML через файл .txt следующим образом:

1header
2client_1
3total_1
4promo_1
5promo_1_data
2client_2
3total_1
3total_2
4promo_1
4promo_1
4promo_1
5promo_1_data
4promo_2
5promo_2_data

Каждая строка начинается с определенного c числа, это число является идентификатором типа записи. Например, номер 2 - это идентификатор нового клиента, поэтому все записи, которые идут после него, принадлежат этой сводке до тех пор, пока итерация не получит другой идентификатор 2 и не создаст другую сводку со своими данными c.

Тем не менее, желаемый результат XML:

<SummaryList>
    <Summary>
        <Client_1></Client_1>
        <Total_1></Total_1>
        <Client_Promotions>
            <Promotion>
                <Promo_1></Promo_1>
                <Promo_1_data></Promo_1_data>
            <Promotion>
        </Client_Promotions>
    </Summary>
    <Summary>
        <Client_2></Client_2>
        <Total_1></Total_1>
        <Total_2></Total_2>
        <Client_Promotions>
            <Promotion>
                <Promo_1></Promo_1>
                <Promo_1></Promo_1>
                <Promo_1></Promo_1>          
                <Promo_1_data></Promo_1_data>
            <Promotion>
            <Promotion>
                <Promo_2></Promo_2>
                <Promo_2_data></Promo_2_data>
            </Promotion>
        </Client_Promotions>
    </Summary>
</SummaryList>

Я пробовал это:

filepath = 'data.txt'
lst = []
with open(filepath) as fp:
   line = fp.readline()
   while line:
       line = fp.readline()
       lst.append(line)

Для создания списка и разделения каждой строки на элемент на этот list, поэтому я могу выполнять итерацию, например:

from lxml import etree as ET
root = ET.Element('SummaryList')
root.text = '\n'
max_lines = len(lst)
line_number = 0
while line_number <= max_lines:
    if lst[line_number][0] == '2':
        a = lst[line_number]
        summary = ET.Element('Summary')
        summary.text = '\n'
        root.append(summary)
        dc = ET.Element("Client")
        dc.text = '\n'
        summary.append(dc)
        e = ET.SubElement(dc, "someClientData")
        e.text = a[1:19].strip()
        e.tail = '\n'
        dc.tail = '\n'
        totalDescount = ET.Element("Total")  # id record type 3
        totalDescount.text = '\n'
        summary.append(totalDescount)
        promoDetail  = ET.Element("ClientPromotions")  # id record type 4
        promoDetail.text = '\n'
        summary.append(promoDetail)
        summary.tail = '\n'
        
    if lst[line_number][0] == '3':
        a = lst[line_number]
        subtotal = ET.Element("SubTotal")
        subtotal.text = '\n'
        totalDescount.append(subtotal)
        e = ET.Element("description")
        e.text = a[1:101].strip()
        e.tail = '\n'
        subtotal.append(e)
        e = ET.Element("someData")
        e.text = format_money(a[101:116])
        e.tail = '\n'
        subtotal.append(e)
        subtotal.tail = '\n'
        totalDescount.tail = '\n'

    if lst[line_number][0] == '4':
        a = lst[line_number]
        promotion = ET.SubElement(promoDetail, "Promotion")  # registro 4 sub array
        promotion.text = '\n'
        promo = ET.Element("Promo")
        promo.text = '\n'
        promotion.append(promo)
        e = ET.SubElement(promo, "someClientData")
        e.text = a[1:19]
        e.tail = '\n'
        promo.tail = '\n'
        promotion.tail = '\n'
        promoDetail= '\n'

    if lst[line_number][0] == '5':
        a = lst[line_number]
        promoData = ET.Element("Promo_data")
        promoData.text = '\n'
        promotion.append(promoData)
        promoData.tail = '\n'
    line_number += 1

Я создаю promoDetail в итерации сводки, потому что мне нужен только один из этих тегов в каждой сводке. Но мне нужно создать тег продвижения для каждого типа записи идентификатора 4, пока он не найдет тип записи идентификатора 5. Я не могу этого добиться. Я получаю эту ошибку:

Traceback (most recent call last):
  File "C:/Users/tartega/PycharmProjects/LP/test.py", line 211, in <module>
    promotion = ET.SubElement(promoDetail, "Promotion") 
TypeError: Argument '_parent' has incorrect type (expected lxml.etree._Element, got str)

Если я добавлю сюда печать:

if lst[line_number][0] == '4':
       a = lst[line_number]
       print(type(promoDetail))

Я получаю такой результат:

<class 'lxml.etree._Element'>
<class 'str'>

Итак, это похоже, что первая итерация проходит хорошо, но вторая не создает этот элемент. Пожалуйста, помогите мне с этим? Я новичок с Python и l xml. Спасибо!

Ответы [ 2 ]

1 голос
/ 11 июля 2020

Ошибка, которую вы получаете, связана с тем, что вы назначаете строку promoData в этой строке:

promoDetail= '\n'

, тогда как вы предполагаете, что это ET.Element в этой строке:

promotion = ET.SubElement(promoDetail, "Promotion")

Из контекста похоже, что вы имели в виду promoDetail.tail = '\n'.

Еще несколько советов, не относящихся непосредственно к вашему вопросу:

  • Вы можете использовать fp.readlines(), чтобы прочитать строки fp в списке. Если вы хотите избавиться от первой строки (которая на самом деле не требуется в вашем фрагменте кода), вы можете использовать fp.readlines()[1:].
  • Поскольку Python использует индексирование с нуля , max_lines - 1 - это самый большой индекс для lst в вашем коде. Следовательно, ваш while l oop должен содержать только go до line_number < max_lines (вместо `line_number <= max_lines). </li>
  • Чтобы перебирать элементы в списке, одновременно отслеживая индекса элемента вы можете использовать enumerate() (в вашем случае for line_number, line in enumerate(lst)). Таким образом, вам не придется снова и снова писать lst[line_number].
0 голосов
/ 16 июля 2020

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

while line_number <= max_lines:
    if lst[line_number][0] == '2':
        a = lst[line_number]
        five = []  # Only id 5 for this resume
        for i in only_fives:
            if i[168:180] in a[19:32]:
                five.append(i)
        four = []
        for i in only_fours:
            if i[19:32] in a[19:32]:
                four.append(i)

И это функция для создания данных в этих тегах 4 и 5:

def fours_and_fives(fours, fives, parent):
    for d2 in fives:
        PROMOTION= ET.SubElement(parent, "Promotion")
        PROMOTION.text = '\n'
        title= ET.SubElement(PROMOTION, "PromotionTitle")
        title.text = d2[1:51].strip()
        title.tail = '\n'
        for d1 in fours:
            if d1[139:189].strip() in d2[1:51].strip():
                dt = ET.SubElement(PROMOTION, "promo")
                dt.text = '\n'
                a = d1
                e = ET.SubElement(dt, "name")
                e.text = a[1:19]
                e.tail = '\n'
                e = ET.SubElement(dt, "idClient")
                e.text = a[19:32].lstrip('0')
                e.tail = '\n'
                e = ET.SubElement(dt, "card")
                e.text = a[32:52].strip()
                e.tail = '\n'
                e = ET.SubElement(dt, "lastDigits")
                e.text = a[52:56]
                e.tail = '\n'
                e = ET.SubElement(dt, "date")
                e.text = format_fecha(a[56:64])
                e.tail = '\n'
                e = ET.SubElement(dt, "nameMarket")
                e.text = a[64:114].strip()
                e.tail = '\n'
                e = ET.SubElement(dt, "coupon")
                e.text = a[114:122]
                e.tail = '\n'
                e = ET.SubElement(dt, "numberOfPayments")
                e.text = a[122:124]
                e.tail = '\n'
                e = ET.SubElement(dt, "spending")
                e.text = format_money(a[124:139])
                e.tail = '\n'
                e = ET.SubElement(dt, "promotion")
                e.text = a[139:189].strip()
                e.tail = '\n'
                e = ET.SubElement(dt, "refund")
                e.text = format_money(a[189:204])
                e.tail = '\n'
                e = ET.SubElement(dt, "thing")
                e.text = format_money(a[204:219])
                e.tail = '\n'
                e = ET.SubElement(dt, "dateRefund")
                e.text = format_fecha(a[219:227])
                e.tail = '\n'
                dt.tail = '\n'
                st = ET.SubElement(PROMOTION, "PromoSubtotal")  # Elements 5
                st.text = '\n'
                e = ET.SubElement(st, "promotion")
                e.text = d2[1:51].strip()
                e.tail = '\n'
                e = ET.SubElement(st, "description")
                e.text = d2[51:151].strip()
                e.tail = '\n'
                e = ET.SubElement(st, "spending")
                e.text = format_money(d2[151:166])
                e.tail = '\n'
                st.tail = '\n'
        PROMOCION.tail = '\n'

format_money - это функция, которая форматирует строку цифр в цифры с тысячи точек и десятичных запятых.

format_fecha - еще одна функция, которая форматирует дату.

...