Python 使用Lxml创建动态XML元素
我在使用lxml库生成XML方面得到了一些帮助,这非常有用,我能够扩展它来解决我的大多数问题。有一个用例我正在努力解决。我试过一个建议,但仍在努力 下面是我的数据集的简单表示Python 使用Lxml创建动态XML元素,python,xml,loops,nested,lxml,Python,Xml,Loops,Nested,Lxml,我在使用lxml库生成XML方面得到了一些帮助,这非常有用,我能够扩展它来解决我的大多数问题。有一个用例我正在努力解决。我试过一个建议,但仍在努力 下面是我的数据集的简单表示 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,J
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>
我的问题是,我可以独立地找到一种识别ID-L2行的方法,但不确定如何让for循环使用它。这确实是缺少的拼图,因此我们一如既往地感谢您的帮助。此方法使用
itertools.groupby
在生成元素之前按ID对数据进行分组。这样就可以为每个元素添加一个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>
ID1
2018-06-01
ID1-L1
欧元
ID1-L2
日元
ID1-L2
人民币
ID2
2018-06-01
ID2-L1
欧元
ID2-L2
日元
ID2-L2
日元
使用etree.XML
或etree.fromstring
构建基础XML。使用xpath找到要添加下一个元素的位置。感谢@shrewmouse的建议。最后,nosklo下面的方法解决了这个问题。这是很棒的@nosklo,看起来不错。我永远不会解决这个问题。谢谢你救了我的命。
<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>