Создайте динамические элементы XML с помощью Lxml - PullRequest
0 голосов
/ 29 июня 2018

Мне помогли сгенерировать мой XML с использованием библиотеки lxml, и это было очень полезно, и я смог расширить его, чтобы решить большинство моих проблем. Есть один вариант использования, с которым я борюсь. Я попробовал предложение, но все еще изо всех сил

Простое представление моего набора данных ниже

ID,Currency,Notional,Maturity,Type
ID1,,,,2018-06-01,
ID1-L1,EUR,100,,,Bond
ID1-L2,JPY,110,,A
ID1-L2,CNY,115,,B
ID2,,,,2018-06-01,
ID2-L1,EUR,100,,,Stock
ID2-L2,JPY,110,,C
ID2-L2,JPY,110,,D

По сути, у меня есть две записи: ID-1 и ID2. ID-L1, ID-L2 и т. Д. Являются дочерними элементами ID1, и будет несколько экземпляров ID-L2. Моя проблема в том, что мне нужно идентифицировать все вхождения ID-L2 и т. Д. И создать новый элемент для каждого вхождения, а затем перейти к следующей записи ID2 и повторить. В результате мои результаты будут выглядеть примерно так.

<tradeRequests>
    <ids>
    <mainid>ID1</mainid>
            <element>
                <maturityDate>2018-06-01</maturityDate>
            </element>
                <cffixed>
                    <element>
                        <id>ID-L1</id>
                        <currency>EUR</currency>
                    </element>
                </cffixed>
                <cffloat>
                    <element>
                        <id>ID1-L2</id>
                        <currency>JPY</currency>
                    </element>
                    <element>
                        <id>ID1-L2</id>
                        <currency>CNY</currency>
                    </element>
                </cffloat>
        </ids>
</tradeRequests>

Итак, это фрагмент кода, который я использовал, но я жестко закодировал значения вместо ссылки на содержимое из файла для этого примера.

import csv
import lxml.etree
from lxml.builder import E

with open('tc.csv', 'r') as fb:
         results = E.tradeRequests(*(
             E.ids(
                 E.mainid('id'),
                 E.element(
                     E.MaturityDate('maturity'),
                     E.cffixed(
                         E.element(
                             E.id('id'),
                             E.currency('currency'),
                            ),
                        ),
                    E.cffloat(
                        E.element(
                            E.id('id'),
                            E.currency('id'),
                            ) #for r in ids2_rows,
                        ),
                     ),
    )for row in csv.DictReader(fb))
 )
print(lxml.etree.tostring(results, pretty_print=True))

Моя проблема заключается в том, что я самостоятельно могу найти способ идентифицировать строки, которые ID-L2, но просто не уверен, как заставить цикл for использовать его. Это действительно недостающая головоломка, так что помощь оценена как всегда.

1 Ответ

0 голосов
/ 29 июня 2018

Этот подход использует itertools.groupby для группировки данных по идентификатору перед генерацией элементов. Таким образом, для каждого элемента можно добавить одну mainid.

import itertools
import csv
import lxml.etree
from lxml.builder import E

with open('tc.csv', 'r') as fb:
    cf = csv.DictReader(fb)
    def groupkey(row):
        return row['ID'].split('-')[0] # group by first part of ID

    result_ids = E.ids()
    result = E.tradeRequests(result_ids)

    for main_id, rows in itertools.groupby(cf, key=groupkey):
        rows = list(rows)
        result_ids.extend([
            E.mainid(main_id),
            E.element(E.maturityDate(rows[0]['Type'])),
            E.cffixed(E.element(E.id(rows[1]['ID']), E.currency(rows[1]['Currency']))),
            E.cffloat(*(E.element(E.id(r['ID']), E.currency(r['Currency']))
                for r in rows[2:])),
        ])
print(lxml.etree.tostring(result, pretty_print=True))

Результаты, при запуске с CSV вы указали в вопросе:

<tradeRequests>
  <ids>
    <mainid>ID1</mainid>
    <element>
      <maturityDate>2018-06-01</maturityDate>
    </element>
    <cffixed>
      <element>
        <id>ID1-L1</id>
        <currency>EUR</currency>
      </element>
    </cffixed>
    <cffloat>
      <element>
        <id>ID1-L2</id>
        <currency>JPY</currency>
      </element>
      <element>
        <id>ID1-L2</id>
        <currency>CNY</currency>
      </element>
    </cffloat>
    <mainid>ID2</mainid>
    <element>
      <maturityDate>2018-06-01</maturityDate>
    </element>
    <cffixed>
      <element>
        <id>ID2-L1</id>
        <currency>EUR</currency>
      </element>
    </cffixed>
    <cffloat>
      <element>
        <id>ID2-L2</id>
        <currency>JPY</currency>
      </element>
      <element>
        <id>ID2-L2</id>
        <currency>JPY</currency>
      </element>
    </cffloat>
  </ids>
</tradeRequests>
...