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')
添加回答
舉報