1 回答
TA贡献1796条经验 获得超10个赞
您可以构建一个列表列表来表示表的行。每当需要新行时,都会使用默认的所有已知列构建一个新列表"",并将其附加到外部列表的底部。当需要插入新列时,只需旋转现有内部列表并附加默认""单元格即可。保留已知列名称的映射以在行中建立索引。现在,当您浏览事件时,您可以使用标记名称来查找行索引并将其值添加到表中的最新行。
看起来您想要“log”和“alarm”标签,但我编写了元素选择器来获取具有“eventType”子元素的任何元素。由于“longName”和“shortName”对于给定的所有事件都是通用的,因此有一个外部循环来获取这些事件并将其应用于表的每个新行。我切换到xpath这样我就可以设置命名空间并更简洁地编写选择器。个人喜好,但我认为它使 xpath 更具可读性。
import csv
import lxml.etree
from lxml.etree import QName
import operator
class ExpandingTable:
"""A 2 dimensional table where columns are exapanded as new column
types are discovered"""
def __init__(self):
"""Create table that can expand rows and columns"""
self.name_to_col = {}
self.table = []
def add_column(self, name):
"""Add column named `name` unless already included"""
if name not in self.name_to_col:
self.name_to_col[name] = len(self.name_to_col)
for row in self.table:
row.append('')
def add_cell(self, name, value):
"""Add value to named column in the current row"""
if value:
self.add_column(name)
self.table[-1][self.name_to_col[name]] = value.strip().replace("\r\n", " ")
def new_row(self):
"""Create a new row and make it current"""
self.table.append([''] * len(self.name_to_col))
def header(self):
"""Gather discovered column names into a header list"""
idx_1 = operator.itemgetter(1)
return [name for name, _ in sorted(self.name_to_col.items(), key=idx_1)]
def prepend_header(self):
"""Gather discovered column names into a header and
prepend it to the list"""
self.table.insert(0, self.header())
def events_to_table(elem):
""" Builds table from <family> child elements and their contained alarms and
logs."""
ns = {"f":"urn:nortel:namespaces:mcp:faults"}
table = ExpandingTable()
for family in elem.xpath("f:family", namespaces=ns):
longName = family.get("longName")
shortName = family.get("shortName")
for event in family.xpath("*/*[f:eventType]", namespaces=ns):
table.new_row()
table.add_cell("longName", longName)
table.add_cell("shortName", shortName)
for cell in event:
tag = QName(cell.tag).localname
if tag == "severities":
tag = "severity"
text = ",".join(severity.text for severity in cell.xpath("*"))
print("severities", repr(text))
else:
text = cell.text
table.add_cell(tag, text)
table.prepend_header()
return table.table
def main(filename):
doc = lxml.etree.parse(filename)
table = events_to_table(doc.getroot())
with open('test.csv', 'w', newline='', encoding='utf-8') as fileobj:
csv.writer(fileobj).writerows(table)
main('test.xml')
添加回答
举报