最近在工作中,要测试这样的一个需求:
要验证股票公司事件的数据入库规则,需要对开发的etl代码以及映射规则进行验证,然后数据源给的源文件格式是xml格式的,人工核对起来的话,考虑到有的字段还有枚举值映射关系或者一些简单的格式处理之类的,如果每次都人工去Ctrl + F去xml文件里面搜索标签去校验对应数据的话,效率不是特别的高,也不利于后续开发代码调整后的快速验证,因此我考虑自己用python脚本去按照分析师的规则文档自己解析一下xml文件,然后用自己解析出来的结果跟开发解析出来的数据进行一下对比,在一定程度上,能够稍微提升一下工作的效率。
既然是要解析xml文件,我的第一反应是百度搜索“python xml解析”
然后我选中了菜鸟教程中的一个文档进行查看:
https://www.runoob.com/python/python-xml.html
在页面中可以看到,包括一般百度到的文章介绍都是说有三种方式可以解析:
接下来用一个案例去演示一下解析xml文件:
测试案例的xml文件demo如下:
- "1.0"?>
- <corporate_actions
- xmlns="https://mp.weixin.qq.com/s/RGkBjpX5ipGHYNSOPaxktA" >
- <Students CLASSID="1" ID_REVISION="0000" ID_EVENT="12345678" xml:id="UCAEvent111212120000">
- <student name="小博">
- <classId>1classId>
- <year>2011year>
- <heigth>173heigth>
- student>
- <student name="张三">
- <classId>2classId>
- <year>2011year>
- <heigth>175heigth>
- student>
- Students>
- corporate_actions>
接下来我们先写代码去获取Students这个标签的数据:
然后很神奇的发现,直接用root.find去查找元素的时候,居然为空,看了网上的代码都是这么写的呀,一度陷入迷茫中。
经过不断的搜索,最终看到别的小伙伴也遇到过这种问题:
经过查找,发现在xml中,如果文件头中带有xmlns属性的话,表示这个是带有命名空间的,在解析的时候,要加上命名空间。
关于xml的命名空间,可以参考下面的文章:
https://www.w3school.com.cn/xml/xml_namespaces.asp
最终可以匹配到元素的代码如下:
-
- import xml.etree.ElementTree as ET
-
- xml_path = f"D:\\MyScripts\\PythonStudy\\QuotesApi\\ice.xml"
- tree = ET.parse(xml_path) # 打开xml文档
- root = tree.getroot()
- student1 = root.find("Students")
- student2 = root.find("{https://mp.weixin.qq.com/s/RGkBjpX5ipGHYNSOPaxktA}Students")
-
- print(student1) # 没加命名空间,匹配不到元素
- print(student2) # 加了命名空间,匹配不到元素
思考
1、像上面那样写的话,每次定位元素都要在前面加上这么一长串的命名空间的代码,感觉有点冗余,有没有什么好的方式可以只写一次,后面不用写呢?(当然,为了测试方便的话,可以把xml文件中的命名空间的内容去掉即可)
2、现在有现成的库可以直接把xml转dict,这样的话,在转换格式后可以借助jsonpath去提取文件中的数据,感觉比xml提取内容会方便一些。比如使用
xmltodict库。