xml解析

发布时间:2019-04-17 21:35:11编辑:auto阅读(2100)

    XML 指可扩展标记语言(eXtensible Markup Language)。XML 被设计用来传输和存储数据。而HTML被用来显示数据。

    XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识。它也是元标记语言,即定义了用于定义其他与特定领域有关的、语义的、结构化的标记语言的句法语言。

    Python对XML解析有三种方式:SAX,DOM,以及ElementTree。

    SAX (simple API for XML )

    python 标准库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。

    DOM(Document Object Model)

    将XML数据在内存中解析成一个树,通过对树的操作来操作XML。

    ElementTree(元素树)

    ElementTree就像一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少。

    注:因DOM需要将XML数据映射到内存中的树,一是比较慢,二是比较耗内存,而SAX流式读取XML文件,比较快,占用内存少,但需要用户实现回调函数。本文使用用ElementTree方式,以名称规范档的下载文本为例。

    在ElementTree中,具体节点的方法主要包括

    tag(标签) attrib(属性) find(寻找节点) set(设置属性) iter(遍历节点) get(获取节点)

    解析XML

    from xml.etree import ElementTree as ET
    #第一种方式
    
    # 打开文件,读取XML内容
    str_xml = open('xo.xml', 'r').read()
    
    # 将字符串解析成xml特殊对象,root代指xml文件的根节点
    root = ET.XML(str_xml)
    
    
    from xml.etree import ElementTree as ET
    #第二种方式
    
    # 直接解析xml文件
    tree = ET.parse("xo.xml")
    
    # 获取xml文件的根节点
    root = tree.getroot()

    操作XML

    遍历XML文档的所有内容

    from xml.etree import ElementTree as ET
    
    # 直接解析xml文件
    tree = ET.parse("test.xml")
    
    # 获取xml文件的根节点
    root = tree.getroot()
    
    
    ### 操作
    
    # 顶层标签
    print(root.tag)
    
    
    # 遍历XML文档的第二层
    for child in root:
        # 第二层节点的标签名称和标签属性
        print(child.tag, child.attrib)
        # 遍历XML文档的第三层
        for i in child:
            # 第二层节点的标签内容
            print(i.text)

    遍历XML中指定的节点

    from xml.etree import ElementTree as ET
    
    # 直接解析xml文件
    tree = ET.parse("test.xml")
    
    # 获取xml文件的根节点
    root = tree.getroot()
    
    # 顶层标签
    print(root.tag) 
    
    # 遍历XML中所有的属性名节点
    for node in root.iter('属性名'):
        # 节点的标签名称和内容
        print(node.text)

    修改节点内容

    xml解析中,要注意修改或者写出XML文件都是在内存中进行,如果要在文件中保存修改,要使用tree的write()方法。set()可设置属性,remove()可删除制定节点,例:
    # 直接解析xml文件
    tree = ET.parse("xo.xml")

    # 获取xml文件的根节点
    root = tree.getroot()
    
    ############ 操作 ############
    
    # 顶层标签
    print(root.tag)
    
    # 循环所有的year节点
    for node in root.iter('year'):
        # 将year节点中的内容自增一
        new_year = int(node.text) + 1
        node.text = str(new_year)
    
        # 设置属性
        node.set('name', 'alex')
        node.set('age', '18')
        # 删除属性
        del node.attrib['name']
    
    
    ############ 保存文件 ############
    tree.write("newnew.xml", encoding='utf-8')

    创建XML文档

    方式一

    from xml.etree import ElementTree as ET
    
    
    # 创建根节点
    root = ET.Element("famliy")
    
    
    # 创建节点大儿子
    son1 = ET.Element('son', {'name': '儿1'})
    # 创建小儿子
    son2 = ET.Element('son', {"name": '儿2'})
    
    # 在大儿子中创建两个孙子
    grandson1 = ET.Element('grandson', {'name': '儿11'})
    grandson2 = ET.Element('grandson', {'name': '儿12'})
    son1.append(grandson1)
    son1.append(grandson2)
    
    
    # 把儿子添加到根节点中
    root.append(son1)
    root.append(son1)
    
    tree = ET.ElementTree(root)
    tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)

    方式二

    from xml.etree import ElementTree as ET
    
    # 创建根节点
    root = ET.Element("famliy")
    
    
    # 创建大儿子
    # son1 = ET.Element('son', {'name': '儿1'})
    son1 = root.makeelement('son', {'name': '儿1'})
    # 创建小儿子
    # son2 = ET.Element('son', {"name": '儿2'})
    son2 = root.makeelement('son', {"name": '儿2'})
    
    # 在大儿子中创建两个孙子
    # grandson1 = ET.Element('grandson', {'name': '儿11'})
    grandson1 = son1.makeelement('grandson', {'name': '儿11'})
    # grandson2 = ET.Element('grandson', {'name': '儿12'})
    grandson2 = son1.makeelement('grandson', {'name': '儿12'})
    
    son1.append(grandson1)
    son1.append(grandson2)
    
    
    # 把儿子添加到根节点中
    root.append(son1)
    root.append(son1)
    
    tree = ET.ElementTree(root)
    tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)

    方式三

    from xml.etree import ElementTree as ET
    
    
    # 创建根节点
    root = ET.Element("famliy")
    
    
    # 创建节点大儿子
    son1 = ET.SubElement(root, "son", attrib={'name': '儿1'})
    # 创建小儿子
    son2 = ET.SubElement(root, "son", attrib={"name": "儿2"})
    
    # 在大儿子中创建一个孙子
    grandson1 = ET.SubElement(son1, "age", attrib={'name': '儿11'})
    grandson1.text = '孙子'
    
    
    et = ET.ElementTree(root)  #生成文档对象
    et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False)

    名称规范档文本

    名称规范档没有提供批量下载同一人物的接口,在数据量大的实验需求中,设计实现了处理批量文本的方法。

    首先,在下载的同一文档中包含不同ID号的多条人物数据,分别以 开头,以结尾,因此第一步,逐行读取文本,匹配结尾标识符“\n”,匹配成功则将先前读取的xml文档写出到新的文件,并给与新的命名以区别不同文本,实现代码如下:

    def file_seperate(file_path,to_path):
        for fileName in os.listdir(file_path):
            f1 = open(file_path+"/"+fileName,'r',encoding="utf-8")
            # print(file_path+"/"+fileName)
            text = ""
            num = 1
            for content in f1.readlines():
                text += content
                if "</collection>"+"\n" == content:
                    num_str = str(num)
                    f2 = open(to_path + "/0" + num_str + fileName ,'w',encoding="utf-8")            
                    f2.write(text)
                    f2.close()
                    text = ""
                    num = num + 1
            f1.close()

    解析结果可得(以沈从文为例)01沈从文.xml、02沈从文.xml、03沈从文.xml,进一步分析,在每一篇XML文件,要获取具体属性值构建目标文本集,为进一步的数据处理提供依据。根据研究需要,获取xml文件中的collection>>record>>datafield>>subfield字段,并限定具体属性的subfield字段,如{'code': 'a'}、{'code': 'f'}、 {'code': '3'}、{'code': 'u'},循环读取进行匹配,匹配成功则构建新的目标文本,与原文本同名。实现代码如下:

    def xml_parse(file_path,Target_path):
        for fileName in os.listdir(file_path):
            file = file_path+"/"+fileName
            text = ''
    
            tree = ET.parse(file)
            root = tree.getroot()
            for node in root:
                for node_node in node:
                    if node_node.attrib == {'tag': '200', 'ind1': ' ', 'ind2': '0'} or node_node.attrib =={'tag': '400', 'ind1': ' ', 'ind2': '0'} or node_node.attrib =={'tag': '810', 'ind1': ' ', 'ind2': ' '} or  node_node.attrib =={'tag': '830', 'ind1': ' ', 'ind2': ' '} or node_node.attrib =={'tag': '856', 'ind1': '4', 'ind2': ' '}:
                        for subfield in node_node:
                            if subfield.attrib == {'code': 'a'} or subfield.attrib == {'code': 'f'} or subfield.attrib == {'code': '3'} or subfield.attrib == {'code': 'u'}:
                                text = text + subfield.text
    
            print(text)
            f = open(Target_path+"/"+fileName,'w',encoding='utf-8')
            f.write(text)
            f.close()

    主函数如下,分别设定原始路径,处理文件路径,目标文件路径:

    if __name__ == "__main__":
        path_Source = "D:/study/name_cluster/test/test02/data-Source"
        path_Separate = "D:/study/name_cluster/test/test02/data-Separate"
        path_Target = "D:/study/name_cluster/test/test02/data-Target"
        file_seperate(path_Source,path_Separate)        
        xml_parse(path_Separate,path_Target)

关键字