# xml_hivenet模块说明 xml_hivenet模块主要实现了xml文件的简单处理处理,模块使用lxml.etree进行底层处理。 支持的主要功能: 1、支持xml文件解析处理,以及与字典对象的相互转换; 2、支持html文件解析(基于xpath); 3、扩展支持xpath2.0语法。 ## SimpleXml的基本使用参考 ### 基本使用说明 1、构造函数 ``` 示例:xmldoc = SimpleXml('test.xml', obj_type=EnumXmlObjType.File) 主要参数如下: @param {object} xml_obj - 要装载的报文载体(与obj_type结合来判断是什么对象),例如(仅供参考): obj_type = EnumXmlObjType.File 时,obj为文件路径 obj_type = EnumXmlObjType.FileHandle 时,obj为文件句柄 obj_type = EnumXmlObjType.String 时,obj为报文文本 @param {EnumXmlObjType} obj_type=EnumXmlObjType.File - xml对象类型 @param {string} encoding=encoding - 装载字符编码,如果传None代表自动判断 @param {bool} use_chardet=True - 当自动判断的时候,是否使用chardet库 @param {str} parser='xml' - 解析器类型,默认为xml xml - 标准xml解析器 html - html解析器,兼容html一些不规范的地方 @param {dict} register_namespace=None - 注册命名空间别名,格式为: {prefix: uri, prefix: uri, ... } 其中prefix和uri都为字符串 注册命名空间后,后续的节点就可以通过tag='{uri}tagname'的方式添加带命名空间的节点 @param {bool} use_xpath2=False - 使用xpath2.0,默认只支持xpath1.0 @param {**kwargs} kwargs - 扩展的装载参数,包括XMLParser的参数 attribute_defaults - inject default attributes from DTD or XMLSchema dtd_validation - validate against a DTD referenced by the document load_dtd - use DTD for parsing no_network - prevent network access for related files (default: True) ns_clean - clean up redundant namespace declarations recover - try hard to parse through broken XML remove_blank_text - discard blank text nodes that appear ignorable 装载时是否将空白文本去掉,只有含这个参数,打印时pretty_print才生效 remove_comments - discard comments remove_pis - discard processing instructions strip_cdata - replace CDATA sections by normal text content (default: True) compact - save memory for short text content (default: True) collect_ids - use a hash table of XML IDs for fast access (default: True, always True with DTD validation) resolve_entities - replace entities by their text value (default: True) huge_tree - disable security restrictions and support very deep trees target - a parser target object that will receive the parse events schema - an XMLSchema to validate against ``` 2、提供各类函数获取及修改节点值和属性,主要的检索使用XPath语法; 3、支持另存为文件 ``` 示例:xmldoc.save('test1.xml', encoding='utf-8', xml_declaration=True) @param {string|object} file=None - 要保存的文件的完整路径,如果不传代表修改原文件 注:也可以传入打开的文件句柄 @param {string} encoding=None - 文件编码,如果为None代表使用创建时的编码 @param {**kwargs} kwargs - 扩展的装载参数,包括ElementTree.write的参数 xml_declaration=None - 控制是否在文件中添加xml的声明,True - 一直添加, False - 不添加 如果传None,代表只有encoding不是US-ASCII or UTF-8 or Unicode的时候才添加声明 ``` ### 存在命名空间的情况 对于存在命名空间的情况,SimpleXml并不支持“{namespace}tag”这种类型的xPath语法处理,标准的使用方法如下: ``` # 指定命名空间字典,key值为命名空间的别名,可自定义 _ns = { 'people': 'http://people.example.com', 'role': 'http://characters.example.com' } # 获取节点值,需注意xPath中命名空间下的每个节点都需要指定别名 _text = _pfile.get_value('people:actor[1]/people:name', default='None', namespaces=_ns) _text = _pfile.get_value( '/people:actors/people:actor[1]/role:character[1]', default='None', namespaces=_ns) # 创建带命名空间的节点,节点tag需要带命名空间的指定标识"{namespace}" _tag = '{%s}%s' % (_ns['role'], 'tagname') _node = ET.Element(_tag, nsmap=_ns) _pfile.append_node('/people:actors', _node, namespaces=_ns) ``` ### 将指定节点生成字典对象 to_dict函数可以将指定的节点生成字典对象(需注意不支持节点属性的情况),规则如下: 1、访问字典从节点的标签(tag)作为key,例如根节点的tag为data,则可通过_dict['data']进行对应的节点信息访问; ``` 例如: val1 val2 转换为字典:{'data': {'a': 'val1', 'b': 'val2'} } ``` 2、xml中可通过type属性指定节点的类型,支持 dict, list, tuple, bool, int, float, string 这7种类型:其中dict 类型是默认类型,在字典中对应的value是一个字典,key为子节点的tag; bool, int, float, string 类型在字典中对应的value是节点的text转换过来的值;list、tuple是列表类型,在字典中对应得value是列表; ``` 例如: val1 3 v1 v2 d1 转换为字典: { 'data': { 'a': 'val1', 'b': 3, 'c': ['v1', 'v2', {'d': 'd1'}] } } ``` 3、如果节点没有指定type属性,将自动根据子节点判断当前节点的类型,如果当前节点没有子节点,按string类型转换;如果当前节点有子节点,且子节点的tag没有重复情况,则按dict类型转换;如果子节点的tag有重复,则按list类型转换; 4、可以通过item_dict_xpaths参数指定某个list节点的列表项,不是直接取节点值,而是生成key值为tag的列表项: ``` 例如: x1 x2 v1 v2 d1 指定item_dict_xpaths={'/data/c': None} 转换为字典: { 'data': { 'a': ['x1', 'x2'], 'c': [{'c1': 'v1'}, {'c2': 'v2'}, {'c3': {'d': 'd1'}}, ] } } ``` ### 将字典对象添加到xml中 可以通过 set_value_by_dict 函数将字典对象添加到xml文档的指定节点中,程序会自动判断类型并进行相应转换,示例如下: ``` # 创建SimpleXml对象 _doc = SimpleXml('test1', obj_type=EnumXmlObjType.String) # 要添加到b节点下的字典对象 _dict = { 'b': True, 'c': 10, 'd': 3.4, 'e': 'teste', 'f': [ False, 11, 4.5, 'haha', {'g': 'gteset', 'h': False} ], 'i': {'a': 'tet', 'b': 'ddd'} } # 执行添加动作,通过with_type指定自动识别对象类型 _doc.set_value_by_dict('/root/b', _dict, with_type=True, debug=True) print(_doc.to_string()) 执行结果显示如下: test1 true 10 3.4 teste false 11 4.5 haha gteset false tet ddd ``` ## lxml.etree的基本使用参考 官方参考文档见:https://lxml.de/api/lxml-module.html ### 主要方法列表 **访问元素属性** Element.tag(): 字符串类型,标识标识次元素类型 Element.text(): 元素内容 Element.attrib(): 属性字典 Element.clear(): 清楚所有子元素 Element.get(key, default=None): 获取key的元素属性,返回属性值,默认None Element.items(): 将元素属性以元组形式返回 Element.keys(): 列表形式返回属性名称 Element.set(key, value): 将元素上的属性设置为value **元素子元素操作** append(subelement): 添加子元素 extend(subelements):零个或多个元素序列追加子元素 find(match, namespaces=None):查找匹配第一个子元素,返回一个元素示例或None,match为标签名或xpath路径 findall(match, namespaces=None): 按照标签名称寻找子元素,match为标签名或者xpath路径 findtext(match, default=None, namespaces=None):返回匹配到的第一个子元素的文本,match可以是标签名或xpath路径,如果一个元素都匹配不到,返回default的值 insert(index, element):在元素指定位置插入子元素 iter(tag=None): 使用当前元素作为跟创建树迭代器 iterfind(match, namespaces=None): 按照标签名和xpath查找所有匹配的子元素,返回迭代 itertext():创建文本迭代器,迭代器按照文本顺序遍历元素和子元素,返回全部文本 remove(subelement): 从元素中删除子元素 ### 遍历XML节点 1、遍历指定节点的子节点 ``` import xml.etree as ET tree = ET.parse('demo.xml') root = tree.getroot() # 获得根节点 # 遍历子节点,可以通过该方法遍历递归遍历所有节点 for child in root: print('%s %s' % (child.tag, child.attrib)) ``` 2、遍历所有节点重可符合匹配条件的节点 ``` for n in root.iter(tag='neighbor'): # 遍历所有节点中tag为'neighbor'的节点 print(n.attrib) ``` ### 查找节点 1、通过XPath查找对象 ``` for n in root.findall(".//year/..[@name='Singapore']") print(n.attrib) ``` 2、带命名空间的情况 xml示例文件: ``` John Cleese Lancelot Archie Leach Eric Idle Sir Robin Gunther Commander Clement ``` 方法1: ``` for actor in root.findall('{http://people.example.com}actor'): name = actor.find('{http://people.example.com}name') print(name.text) for char in actor.findall('{http://characters.example.com}character'): print(' |-->%s' % char.text) ``` 方法2(推荐): ``` ns = { 'real_person': 'http://people.example.com', 'role': 'http://characters.example.com' } for actor in root.findall('real_person:actor', ns): name = actor.find('real_person:name', ns) print(name.text) for char in actor.findall('role:character', ns): print(' |-->%s' % char.text) ``` ### 添加节点 1、先创建要添加的节点元素 ``` # 生成新节点:ET.Element(tag, attrib={}, **extra) # a = ET.Element('a', attrib={'attr1': 'value1', 'attr2': 'value2'}) # b text b = ET.Element('b', text='b text') # c textc-tail c = ET.Element('c', text='c text', tail='c-tail') # 组合节点:ET.SubElement(parent, tag, attrib={}, **extra) # d = ET.SubElement(a, 'd') ``` 2、添加节点到根节点 ``` # b textc textc-tail n = a.append( b.append(c) ) # 添加到根节点 root.append(n) ``` ## XPath参考 具体参考学习网站:https://www.w3school.com.cn/xpath/index.asp ### XML 实例文档 我们将在下面的例子中使用这个 XML 文档。 ``` Harry Potter 29.99 Learning XML 39.95 ``` ### 选取节点 XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。 **下面列出了最有用的路径表达式:** | 表达式 | 描述 | | :------- | :--------------------------------------------------------- | | nodename | 选取此节点的所有子节点。 | | / | 从根节点选取。 | | // | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 | | . | 选取当前节点。 | | .. | 选取当前节点的父节点。 | | @ | 选取属性。 | **实例** 在下面的表格中,我们已列出了一些路径表达式以及表达式的结果: | 路径表达式 | 结果 | | :-------------- | :----------------------------------------------------------- | | bookstore | 选取 bookstore 元素的所有子节点。 | | /bookstore | 选取根元素 bookstore。 注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! | | bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 | | //book | 选取所有 book 子元素,而不管它们在文档中的位置。 | | bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 | | //@lang | 选取名为 lang 的所有属性。 | ### 谓语(Predicates) 谓语用来查找某个特定的节点或者包含某个指定的值的节点。 谓语被嵌在方括号中。 **实例** 在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果: | 路径表达式 | 结果 | | :--------------------------------- | :----------------------------------------------------------- | | /bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 | | /bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 | | /bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 | | /bookstore/book[position()<3] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 | | //title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 | | //title[@lang='eng'] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 | | /bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 | | /bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 | ### 选取未知节点 XPath 通配符可用来选取未知的 XML 元素。 | 通配符 | 描述 | | :----- | :------------------- | | * | 匹配任何元素节点。 | | @* | 匹配任何属性节点。 | | node() | 匹配任何类型的节点。 | **实例** 在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果: | 路径表达式 | 结果 | | :----------- | :-------------------------------- | | /bookstore/* | 选取 bookstore 元素的所有子元素。 | | //* | 选取文档中的所有元素。 | | //title[@*] | 选取所有带有属性的 title 元素。 | ### 选取若干路径 通过在路径表达式中使用“|”运算符,您可以选取若干个路径。 **实例** 在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果: | 路径表达式 | 结果 | | :------------------------------- | :----------------------------------------------------------- | | //book/title \| //book/price | 选取 book 元素的所有 title 和 price 元素。 | | //title \| //price | 选取文档中的所有 title 和 price 元素。 | | /bookstore/book/title \| //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |