058. 编写一个函数,实现简单的XML文件解析器

在Python中,可以使用xml.etree.ElementTree模块来解析XML文件。这个模块提供了简单易用的API,用于读取和解析XML文件。以下是一个简单的函数,用于解析XML文件并将其内容转换为Python的字典结构。

示例代码

import xml.etree.ElementTree as ET

def parse_xml(file_path):
    """
    解析XML文件
    :param file_path: XML文件的路径
    :return: 解析后的XML数据(以字典形式表示)
    """
    try:
        # 解析XML文件
        tree = ET.parse(file_path)
        root = tree.getroot()

        # 递归函数,将XML元素转换为字典
        def element_to_dict(element):
            # 如果元素没有子元素,直接返回其文本内容
            if len(element) == 0:
                return element.text
            # 如果有子元素,递归处理每个子元素
            return {child.tag: element_to_dict(child) for child in element}

        # 将根元素转换为字典
        return {root.tag: element_to_dict(root)}
    except FileNotFoundError:
        print(f"错误:文件 {file_path} 未找到!")
        return None
    except ET.ParseError as e:
        print(f"错误:XML解析错误 - {e}")
        return None
    except Exception as e:
        print(f"发生错误:{e}")
        return None

# 示例用法
if __name__ == "__main__":
    file_path = "example.xml"  # 替换为你的XML文件路径
    xml_data = parse_xml(file_path)
    if xml_data:
        print(xml_data)

示例XML文件内容

假设有一个名为example.xml的文件,内容如下:

<root>
    <person>
        <name>Alice</name>
        <age>25</age>
        <address>
            <street>123 Main St</street>
            <city>Anytown</city>
            <state>CA</state>
        </address>
    </person>
    <person>
        <name>Bob</name>
        <age>30</age>
        <address>
            <street>456 Elm St</street>
            <city>Othertown</city>
            <state>NY</state>
        </address>
    </person>
</root>

示例运行

运行代码后,输出将为:

{
    'root': {
        'person': [
            {
                'name': 'Alice',
                'age': '25',
                'address': {
                    'street': '123 Main St',
                    'city': 'Anytown',
                    'state': 'CA'
                }
            },
            {
                'name': 'Bob',
                'age': '30',
                'address': {
                    'street': '456 Elm St',
                    'city': 'Othertown',
                    'state': 'NY'
                }
            }
        ]
    }
}

代码说明

ET.parse(file_path):使用xml.etree.ElementTree.parse()函数解析XML文件,并获取根元素。

递归函数element_to_dict

  • 递归地将XML元素及其子元素转换为字典。

  • 如果一个元素没有子元素,则直接返回其文本内容。

  • 如果有子元素,则递归处理每个子元素,并将结果存储在字典中。

异常处理:使用try-except块捕获可能的错误,例如文件未找到(FileNotFoundError)或XML解析错误(ET.ParseError)。

扩展功能

如果你需要更复杂的XML解析功能,比如处理属性、命名空间等,可以进一步扩展这个函数。以下是一个支持处理属性的版本:

import xml.etree.ElementTree as ET

def parse_xml(file_path):
    """
    解析XML文件,支持处理属性
    :param file_path: XML文件的路径
    :return: 解析后的XML数据(以字典形式表示)
    """
    try:
        # 解析XML文件
        tree = ET.parse(file_path)
        root = tree.getroot()

        # 递归函数,将XML元素转换为字典
        def element_to_dict(element):
            # 如果元素有属性,将其属性存储为字典
            if element.attrib:
                result = {"@attributes": element.attrib}
            else:
                result = {}

            # 如果元素有子元素,递归处理每个子元素
            if len(element) > 0:
                children = {}
                for child in element:
                    child_result = element_to_dict(child)
                    if child.tag in children:
                        if not isinstance(children[child.tag], list):
                            children[child.tag] = [children[child.tag]]
                        children[child.tag].append(child_result)
                    else:
                        children[child.tag] = child_result
                result.update(children)
            else:
                # 如果元素没有子元素,直接返回其文本内容
                result = element.text

            return result

        # 将根元素转换为字典
        return {root.tag: element_to_dict(root)}
    except FileNotFoundError:
        print(f"错误:文件 {file_path} 未找到!")
        return None
    except ET.ParseError as e:
        print(f"错误:XML解析错误 - {e}")
        return None
    except Exception as e:
        print(f"发生错误:{e}")
        return None

# 示例用法
if __name__ == "__main__":
    file_path = "example.xml"  # 替换为你的XML文件路径
    xml_data = parse_xml(file_path)
    if xml_data:
        print(xml_data)

示例XML文件内容(带属性)

假设有一个名为example.xml的文件,内容如下:

<root>
    <person id="1">
        <name>Alice</name>
        <age>25</age>
        <address>
            <street>123 Main St</street>
            <city>Anytown</city>
            <state>CA</state>
        </address>
    </person>
    <person id="2">
        <name>Bob</name>
        <age>30</age>
        <address>
            <street>456 Elm St</street>
            <city>Othertown</city>
            <state>NY</state>
        </address>
    </person>
</root>

示例运行

运行代码后,输出将为:

{
    'root': {
        'person': [
            {
                '@attributes': {'id': '1'},
                'name': 'Alice',
                'age': '25',
                'address': {
                    'street': '123 Main St',
                    'city': 'Anytown',
                    'state': 'CA'
                }
            },
            {
                '@attributes': {'id': '2'},
                'name': 'Bob',
                'age': '30',
                'address': {
                    'street': '456 Elm St',
                    'city': 'Othertown',
                    'state': 'NY'
                }
            }
        ]
    }
}

注意事项

文件编码:如果XML文件的编码不是utf-8,可能会导致读取错误。如果文件使用其他编码(如gbk),可以在ET.parse函数中指定正确的编码,例如:

tree = ET.parse(file_path, parser=ET.XMLParser(encoding='gbk'))

XML命名空间:如果XML文件中使用了命名空间,可以在解析时处理命名空间。例如:

for elem in tree.iter():
    # 处理命名空间
    elem.tag = elem.tag.split('}')[-1]

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)