影刀RPA XML文件处理:解析与生成 影刀RPA XML文件处理解析与生成署名林焱什么情况用什么RPA流程中遇到XML格式的配置文件如SVG、OFD发票、Sitemap或者调用WebService接口返回XML格式数据。虽然JSON更流行但很多老系统和企业级接口仍使用XML。场景推荐库特点简单XML解析xml.etree.ElementTree标准库无需安装复杂XML操作lxml支持XPath功能强大XML生成xml.etree.ElementTree树形构建怎么做一解析XMLimportxml.etree.ElementTreeasET xml_string?xml version1.0 encodingUTF-8? orders order id001 customer张三/customer items item name商品A price99.9 qty2/ item name商品B price199.0 qty1/ /items total398.8/total /order order id002 customer李四/customer items item name商品C price50.0 qty3/ /items total150.0/total /order /orders # 解析XML字符串rootET.fromstring(xml_string)# 遍历所有orderfororderinroot.findall(order):order_idorder.get(id)# 属性customerorder.find(customer).text# 子元素文本totalorder.find(total).textprint(f订单号:{order_id}, 客户:{customer}, 总价:{total})# 遍历items下的itemforiteminorder.findall(items/item):nameitem.get(name)priceitem.get(price)qtyitem.get(qty)print(f 商品:{name}, 价格:{price}, 数量:{qty})二读取XML文件拼多多店群自动化上架方案importxml.etree.ElementTreeasET# 从文件读取treeET.parse(rD:\config\settings.xml)roottree.getroot()# root.tag → 根标签名# root.attrib → 根属性字典print(f根标签:{root.tag})# 递归遍历所有元素defprint_element(elem,level0):indent *level textelem.text.strip()ifelem.textandelem.text.strip()else![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/748982c20b3746ecb1927d4783d1a643.png#pic_center)attrs .join(f{k}{v}fork,vinelem.attrib.items())iftext:print(f{indent}{elem.tag}{attrs}{text}/{elem.tag})else:print(f{indent}{elem.tag}{attrs})forchildinelem:print_element(child,level1)print_element(root)三生成XMLimportxml.etree.ElementTreeasET# 创建XML树rootET.Element(report)root.set(date,2024-06-15)root.set(type,daily)# 添加子元素summaryET.SubElement(root,summary)summary.set(currency,CNY)ET.SubElement(summary,total_orders).text150ET.SubElement(summary,total_amount).text45678.90ET.SubElement(summary,avg_amount).text304.53# 添加明细detailsET.SubElement(root,details)orders[{id:001,customer:张三,amount:199.0},{id:002,customer:李四,amount:350.5},]fororderinorders:order_elemET.SubElement(details,order)order_elem.set(id,order[id])ET.SubElement(order_elem,customer).textorder[customer]ET.SubElement(order_elem,amount).textorder[amount]# 生成XML字符串xml_strET.tostring(root,encodingunicode)# 美化输出标准库不支持缩进Python 3.9有ET.indentET.indent(root,space ,level0)xml_strET.tostring(root,encodingunicode)print(xml_str)# 写入文件treeET.ElementTree(root)tree.write(rD:\报告\daily_report.xml,encodingutf-8,xml_declarationTrue)四用XPath查找lxmlfromlxmlimportetree# 解析treeetree.fromstring(xml_string.encode(utf-8))# XPath查找# 所有订单的客户名customerstree.xpath(//customer/text())print(f所有客户:{customers})# 总价大于200的订单big_orderstree.xpath(//order[total 200]/id)print(f大额订单:{big_orders})# 第一个订单的所有商品名itemstree.xpath((//order)[1]/items/item/name)print(f商品名:{items})# 带条件的查找数量大于1的商品bulk_itemstree.xpath(//item[qty 1]/name)print(f多数量商品:{bulk_items})完整流程Sitemap解析采集importxml.etree.ElementTreeasETimportrequests# yd_input: sitemap_urlsitemap_urlyd_input.get(sitemap_url,https://example.com/sitemap.xml)# 下载并解析Sitemapresprequests.get(sitemap_url,timeout30)rootET.fromstring(resp.content)# 提取所有URLurls[]# Sitemap命名空间ns{ns:http://www.sitemaps.org/schemas/sitemap/0.9}forurl_eleminroot.findall(ns:url,ns):locurl_elem.find(ns:loc,ns)lastmodurl_elem.find(ns:lastmod,ns)iflocisnotNone:url_info{url:loc.text,lastmod:lastmod.textiflastmodisnotNoneelse}urls.append(url_info)print(f共找到{len(urls)}个URL)# 去重seenset()unique_urls[]foruinurls:ifu[url]notinseen:seen.add(u[url])unique_urls.append(u)print(f去重后{len(unique_urls)}个URL)yd_output{status:ok,urls:unique_urls,count:len(unique_urls)}有什么坑坑一XML命名空间导致findall找不到元素现象XML有xmlns命名空间声明findall(order)返回空列表。原因带命名空间的XML元素名需要加上命名空间前缀才能匹配。解决importxml.etree.ElementTreeasET# XML有命名空间# orders xmlnshttp://example.com/orders# order id001.../order# /orders# 错误直接用标签名找不到# orders root.findall(order) ❌ 返回空# 正确1用完整命名空间ns{d:http://example.com/orders}ordersroot.findall(d:order,ns)# 正确2用通配符ordersroot.findall(.//{http://example.com/orders}order)# 正确3去掉命名空间后再解析foreleminroot.iter():if}inelem.tag:elem.tagelem.tag.split(})[1]# 去掉命名空间部分# 现在可以直接用标签名ordersroot.findall(order)坑二XML中的特殊字符现象生成XML时文本包含、、等字符导致解析报错。原因XML中、、、、是特殊字符必须转义。解决用ElementTree自动转义或手动处理TEMU店群如何管理运营importxml.etree.ElementTreeasETfromxml.sax.saxutilsimportescape,unescape# ElementTree自动转义elemET.Element(note)elem.text价格 100 库存 0xml_strET.tostring(elem,encodingunicode)# 自动转义为: note价格 lt; 100 amp; 库存 gt; 0/note# 手动转义texta b c descapedescape(text)# a lt; b amp; c gt; d# 手动反转义originalunescape(escaped)# a b c d坑三解析XML时编码错误现象解析包含中文的XML文件报UnicodeDecodeError或ParseError。原因文件实际编码与XML声明中的编码不一致或者文件有BOM头。解决importxml.etree.ElementTreeasET# 方案1以bytes方式读取让ET自动检测编码withopen(rD:\config\中文.xml,rb)asf:contentf.read()rootET.fromstring(content)# ET根据XML声明自动解码# 方案2先去掉BOM头withopen(rD:\config\中文.xml,rb)asf:contentf.read()ifcontent[:3]b\xef\xbb\xbf:# UTF-8 BOMcontentcontent[3:]rootET.fromstring(content)# 方案3用lxml更健壮fromlxmlimportetree treeetree.parse(rD:\config\中文.xml)roottree.getroot()坑四生成的XML没有缩进和换行现象用ElementTree生成的XML是一行没有缩进难以阅读。原因ElementTree默认不格式化输出。解决importxml.etree.ElementTreeasET# Python 3.9用ET.indentrootET.Element(root)ET.SubElement(root,child).texthelloET.indent(root,space )# 缩进2空格xml_strET.tostring(root,encodingunicode)print(xml_str)# root![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/accc3cf32b0d4170809dc89a5f37a75b.png#pic_center)# childhello/child# /root# Python 3.8及以下用minidom美化importxml.dom.minidom xml_strET.tostring(root,encodingunicode)domxml.dom.minidom.parseString(xml_str)prettydom.toprettyxml(indent )print(pretty)