使用python';s zip和列表理解以将xml转换为csv

使用python';s zip和列表理解以将xml转换为csv,python,xml,csv,zip,list-comprehension,Python,Xml,Csv,Zip,List Comprehension,我一直在看关于zip和魔法的其他问题,这对我理解它的工作原理有很大帮助。例如: 尽管我还得想一想到底发生了什么,但我现在已经有了更好的理解。因此,我试图实现的是将xml文档转换为csv。上面的最后一个链接非常接近我想要做的事情,但是我的源xml没有最一致的结构,这就是我遇到麻烦的地方。下面是我的源xml的一个示例(为了这个示例而简化): 虽然这为我提供了一种可以用来编写csv的格式,但它有两个问题: 它跳过第二个子元素,因为它没有元素(我想)。如果我只通过设置tags=('Name'

我一直在看关于zip和魔法的其他问题,这对我理解它的工作原理有很大帮助。例如:

尽管我还得想一想到底发生了什么,但我现在已经有了更好的理解。因此,我试图实现的是将xml文档转换为csv。上面的最后一个链接非常接近我想要做的事情,但是我的源xml没有最一致的结构,这就是我遇到麻烦的地方。下面是我的源xml的一个示例(为了这个示例而简化):

虽然这为我提供了一种可以用来编写csv的格式,但它有两个问题:

  • 它跳过第二个子元素,因为它没有
    元素(我想)。如果我只通过设置
    tags=('Name','姓氏')
    搜索存在于两个子元素中的元素,那么我有两个列表(太棒了!)

  • 第一个孩子实际上有两个电话号码,但只返回一个

  • 根据我的测试,当zip*开始发挥作用时,东西开始消失。。。我如何设置默认值以便保留空值

    更新:为了更清楚地说明我打算做什么,这里是预期的输出格式(带有分号分隔符的CSV,其中每个字段中的多个值用逗号分隔):


    谢谢

    关于第一个问题,您说“[i]f我只搜索两个子节点中存在的元素……我有两个列表返回”,这意味着第二个子节点缺少输出与两个
    子节点之间的交互有关。事实并非如此。您似乎忽略了
    zip
    行为的一个方面是
    zip
    在用尽最短的参数后停止处理其参数

    考虑以下代码简化的输出:

    for child in data:
        print [child.findall(x) for x in tags]
    
    输出将为(忽略内存地址):

    这将产生:

    ['John', 'Doe', '123456', '654321', '111111']
    ['Tom', 'Cat', '98765', '56789', '00000']
    

    我把它拼凑起来了。阅读csv模块的文档,如果需要更具体的格式,请进行相应的更改

    from csv import DictWriter
    from StringIO import StringIO
    import xml.etree
    from xml.etree import ElementTree
    
    xml_str = \
    '''
    <?xml version="1.0" encoding="utf-8"?>
    <root>
        <child>
            <Name>John</Name>
            <Surname>Doe</Surname>
            <Phone>123456</Phone>
            <Phone>654321</Phone>
            <Fax>111111</Fax>
        </child>
        <child>
            <Name>Tom</Name>
            <Surname>Cat</Surname>
            <Phone>98765</Phone>
            <Phone>56789</Phone>
            <Phone>00000</Phone>
        </child>
    </root>
    '''
    
    root = ElementTree.parse(StringIO(xml_str.strip()))
    entry_list = []
    for child_tag in root.iterfind("child"):
        child_tags = child_tag.getchildren()
    
        tag_count = {}
        [tag_count.__setitem__(tag.tag, tag_count.get(tag.tag, 0) + 1) for tag in child_tags]
    
        m_count = dict([(key, 0) for (key, val) in filter(lambda (x, y): y > 1, tag_count.items())])
    
        enum = lambda x: ("%s%s" % (x.tag, (" %d" % m_count.setdefault(x.tag, m_count.pop(x.tag) + 1)) if(tag_count[x.tag] > 1) else ""), x.text)
        tmp_dict = dict([enum(tag) for tag in child_tags])
    
        entry_list.append(tmp_dict)
    
    field_order = ["Name", "Surname", "Phone 1", "Phone 2", "Phone 3", "Fax"]
    field_check = lambda q: field_order.index(q) if(field_order.count(q)) else sys.maxint
    
    all_fields = list(reduce(lambda x, y: x | set(y.keys()), entry_list, set([])))
    all_fields.sort(cmp=lambda x, y: field_check(x) - field_check(y))
    
    with open("test.csv", "w") as file_h:
        writer = DictWriter(file_h, all_fields, restval="", extrasaction="ignore", dialect="excel", lineterminator="\n")
        writer.writerow(dict(zip(all_fields, all_fields)))
        writer.writerows(entry_list)
    
    从csv导入DictWriter
    从StringIO导入StringIO
    导入xml.etree
    从xml.etree导入元素树
    xml_str=\
    '''
    约翰
    雌鹿
    123456
    654321
    111111
    汤姆
    猫
    98765
    56789
    00000
    '''
    root=ElementTree.parse(StringIO(xml_str.strip()))
    条目列表=[]
    对于root.iterfind(“child”)中的child_标记:
    child\u tags=child\u tag.getchildren()
    标记_计数={}
    [tag\u count.\uuuuu setitem\uuuuuu(tag.tag,tag\u count.get(tag.tag,0)+1)用于子\u标记中的标记]
    m_count=dict([(key,0)表示过滤器中的(key,val)(lambda(x,y):y>1,tag_count.items()))
    enum=lambda x:(“%s%s%”(x.tag,(“%d”%m_count.setdefault(x.tag,m_count.pop(x.tag)+1))如果(tag_count[x.tag]>1)else“”,x.text)
    tmp_dict=dict([子标签中标签的枚举(标签)])
    条目列表追加(tmp目录)
    字段顺序=[“姓名”、“姓氏”、“电话1”、“电话2”、“电话3”、“传真”]
    field_check=lambda q:field_order.index(q)if(field_order.count(q))else sys.maxint
    所有字段=列表(reduce(lambda x,y:x | set(y.keys()),entry_list,set([]))
    所有字段。排序(cmp=lambda x,y:field\u check(x)-field\u check(y))
    打开(“test.csv”、“w”)作为文件:
    writer=DictWriter(文件,所有字段,restval=,extraction=“忽略”,dialogue=“excel”,lineterminator=“\n”)
    writer.writerow(dict(zip(所有字段,所有字段)))
    writer.writerows(条目列表)
    
    你好,阿尔普,谢谢你的回复。然而,它遗漏了几点。我将编辑我的回复,添加预期的输出,使其更加清晰。我的目的是将结果转换为csv格式,以便您的输出在该上下文中不正常。这就是我最终想要的:
    John;乔;123456,654321;111111;汤姆;猫;98765,56789;00000;;因此,如果我有2个
    元素,它们需要在一个csv“字段”中结束。此外,顺序很重要,作为csv,每个字段都必须与相应的标题明显匹配。。。这很好,但我得花好几个小时去理解你刚才在那里做的一切!谢谢
    for child in data:
        print [child.findall(x) for x in tags]
    
    [[<Element 'Name'>], [<Element 'Surname'>], [<Element 'Phone'>, <Element 'Phone'>], [<Element 'Fax'>]]
    [[<Element 'Name'>], [<Element 'Surname'>], [<Element 'Phone'>, <Element 'Phone'>, <Element 'Phone'>], []]
    
    for child in data:
        print [x.text for x in child]
    
    ['John', 'Doe', '123456', '654321', '111111']
    ['Tom', 'Cat', '98765', '56789', '00000']
    
    from csv import DictWriter
    from StringIO import StringIO
    import xml.etree
    from xml.etree import ElementTree
    
    xml_str = \
    '''
    <?xml version="1.0" encoding="utf-8"?>
    <root>
        <child>
            <Name>John</Name>
            <Surname>Doe</Surname>
            <Phone>123456</Phone>
            <Phone>654321</Phone>
            <Fax>111111</Fax>
        </child>
        <child>
            <Name>Tom</Name>
            <Surname>Cat</Surname>
            <Phone>98765</Phone>
            <Phone>56789</Phone>
            <Phone>00000</Phone>
        </child>
    </root>
    '''
    
    root = ElementTree.parse(StringIO(xml_str.strip()))
    entry_list = []
    for child_tag in root.iterfind("child"):
        child_tags = child_tag.getchildren()
    
        tag_count = {}
        [tag_count.__setitem__(tag.tag, tag_count.get(tag.tag, 0) + 1) for tag in child_tags]
    
        m_count = dict([(key, 0) for (key, val) in filter(lambda (x, y): y > 1, tag_count.items())])
    
        enum = lambda x: ("%s%s" % (x.tag, (" %d" % m_count.setdefault(x.tag, m_count.pop(x.tag) + 1)) if(tag_count[x.tag] > 1) else ""), x.text)
        tmp_dict = dict([enum(tag) for tag in child_tags])
    
        entry_list.append(tmp_dict)
    
    field_order = ["Name", "Surname", "Phone 1", "Phone 2", "Phone 3", "Fax"]
    field_check = lambda q: field_order.index(q) if(field_order.count(q)) else sys.maxint
    
    all_fields = list(reduce(lambda x, y: x | set(y.keys()), entry_list, set([])))
    all_fields.sort(cmp=lambda x, y: field_check(x) - field_check(y))
    
    with open("test.csv", "w") as file_h:
        writer = DictWriter(file_h, all_fields, restval="", extrasaction="ignore", dialect="excel", lineterminator="\n")
        writer.writerow(dict(zip(all_fields, all_fields)))
        writer.writerows(entry_list)