详解在Python程序中解析并修改XML内容的方法

需求
在实际应用中,需要对xml配置文件进行实时修改,

1.增加、删除 某些节点

2.增加,删除,修改某个节点下的某些属性

3.增加,删除,修改某些节点的文本

使用xml文档

<?xml version="1.0" encoding="UTF-8"?>
<framework>
  <processers>
    <processer name="AProcesser" file="lib64/A.so"
      path="/tmp">
    </processer>
    <processer name="BProcesser" file="lib64/B.so" value="fordelete">
    </processer>
    <processer name="BProcesser" file="lib64/B.so2222222"/>

    <services>
      <service name="search" prefix="/bin/search?"
        output_formatter="OutPutFormatter:service_inc">

        <chain sequency="chain1"/>
        <chain sequency="chain2"></chain>
      </service>
      <service name="update" prefix="/bin/update?">
        <chain sequency="chain3" value="fordelete"/>
      </service>
    </services>
  </processers>
</framework>

实现思想
使用ElementTree,先将文件读入,解析成树,之后,根据路径,可以定位到树的每个节点,再对节点进行修改,最后直接将其输出

实现代码

#!/usr/bin/python
# -*- coding=utf-8 -*-
# author : wklken@yeah.net
# date: 2012-05-25
# version: 0.1

from xml.etree.ElementTree import ElementTree,Element

def read_xml(in_path):
  '''读取并解析xml文件
    in_path: xml路径
    return: ElementTree'''
  tree = ElementTree()
  tree.parse(in_path)
  return tree

def write_xml(tree, out_path):
  '''将xml文件写出
    tree: xml树
    out_path: 写出路径'''
  tree.write(out_path, encoding="utf-8",xml_declaration=True)

def if_match(node, kv_map):
  '''判断某个节点是否包含所有传入参数属性
    node: 节点
    kv_map: 属性及属性值组成的map'''
  for key in kv_map:
    if node.get(key) != kv_map.get(key):
      return False
  return True

#---------------search -----
def find_nodes(tree, path):
  '''查找某个路径匹配的所有节点
    tree: xml树
    path: 节点路径'''
  return tree.findall(path)

def get_node_by_keyvalue(nodelist, kv_map):
  '''根据属性及属性值定位符合的节点,返回节点
    nodelist: 节点列表
    kv_map: 匹配属性及属性值map'''
  result_nodes = []
  for node in nodelist:
    if if_match(node, kv_map):
      result_nodes.append(node)
  return result_nodes

#---------------change -----
def change_node_properties(nodelist, kv_map, is_delete=False):
  '''修改/增加 /删除 节点的属性及属性值
    nodelist: 节点列表
    kv_map:属性及属性值map'''
  for node in nodelist:
    for key in kv_map:
      if is_delete:
        if key in node.attrib:
          del node.attrib[key]
      else:
        node.set(key, kv_map.get(key))

def change_node_text(nodelist, text, is_add=False, is_delete=False):
  '''改变/增加/删除一个节点的文本
    nodelist:节点列表
    text : 更新后的文本'''
  for node in nodelist:
    if is_add:
      node.text += text
    elif is_delete:
      node.text = ""
    else:
      node.text = text

def create_node(tag, property_map, content):
  '''新造一个节点
    tag:节点标签
    property_map:属性及属性值map
    content: 节点闭合标签里的文本内容
    return 新节点'''
  element = Element(tag, property_map)
  element.text = content
  return element

def add_child_node(nodelist, element):
  '''给一个节点添加子节点
    nodelist: 节点列表
    element: 子节点'''
  for node in nodelist:
    node.append(element)

def del_node_by_tagkeyvalue(nodelist, tag, kv_map):
  '''同过属性及属性值定位一个节点,并删除之
    nodelist: 父节点列表
    tag:子节点标签
    kv_map: 属性及属性值列表'''
  for parent_node in nodelist:
    children = parent_node.getchildren()
    for child in children:
      if child.tag == tag and if_match(child, kv_map):
        parent_node.remove(child)

if __name__ == "__main__":
  #1. 读取xml文件
  tree = read_xml("./test.xml")

  #2. 属性修改
   #A. 找到父节点
  nodes = find_nodes(tree, "processers/processer")
   #B. 通过属性准确定位子节点
  result_nodes = get_node_by_keyvalue(nodes, {"name":"BProcesser"})
   #C. 修改节点属性
  change_node_properties(result_nodes, {"age": "1"})
   #D. 删除节点属性
  change_node_properties(result_nodes, {"value":""}, True)

  #3. 节点修改
   #A.新建节点
  a = create_node("person", {"age":"15","money":"200000"}, "this is the firest content")
   #B.插入到父节点之下
  add_child_node(result_nodes, a)

  #4. 删除节点
    #定位父节点
  del_parent_nodes = find_nodes(tree, "processers/services/service")
    #准确定位子节点并删除之
  target_del_node = del_node_by_tagkeyvalue(del_parent_nodes, "chain", {"sequency" : "chain1"})

  #5. 修改节点文本
    #定位节点
  text_nodes = get_node_by_keyvalue(find_nodes(tree, "processers/services/service/chain"), {"sequency":"chain3"})
  change_node_text(text_nodes, "new text")

  #6. 输出到结果文件
  write_xml(tree, "./out.xml")

修改后的结果

<?xml version='1.0' encoding='utf-8'?>
<framework>
  <processers>
    <processer file="lib64/A.so" name="AProcesser" path="/tmp">
    </processer>
    <processer age="1" file="lib64/B.so" name="BProcesser">
      <person age="15" money="200000">this is the firest content</person>
    </processer>
    <processer age="1" file="lib64/B.so2222222" name="BProcesser">
      <person age="15" money="200000">this is the firest content</person>
    </processer>

    <services>
      <service name="search" output_formatter="OutPutFormatter:service_inc"
        prefix="/bin/search?">

        <chain sequency="chain2" />
      </service>
      <service name="update" prefix="/bin/update?">
        <chain sequency="chain3" value="fordelete">new text</chain>
      </service>
    </services>
  </processers>
</framework>
(0)

相关推荐

  • Python通过DOM和SAX方式解析XML的应用实例分享

    XML.DOM 需求 有一个表,里面数据量比较大,每天一更新,其字段可以通过xml配置文件进行配置,即,可能每次建表的字段不一样. 上游跑时会根据配置从源文件中提取,到入库这一步需要根据配置进行建表. 解决 写了一个简单的xml,配置需要字段及类型 上游读取到对应的数据 入库这一步,先把原表删除,根据配置建新表 XML文件 <?xml version="1.0" encoding="UTF-8"?> <!-- 表名 ,数据库名 可灵活配置插入哪个库

  • 详解在Python程序中解析并修改XML内容的方法

    需求 在实际应用中,需要对xml配置文件进行实时修改, 1.增加.删除 某些节点 2.增加,删除,修改某个节点下的某些属性 3.增加,删除,修改某些节点的文本 使用xml文档 <?xml version="1.0" encoding="UTF-8"?> <framework> <processers> <processer name="AProcesser" file="lib64/A.so&q

  • 详解在Python程序中使用Cookie的教程

    大家好哈,上一节我们研究了一下爬虫的异常处理问题,那么接下来我们一起来看一下Cookie的使用. 为什么要使用Cookie呢? Cookie,指某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密) 比如说有些网站需要登录后才能访问某个页面,在登录之前,你想抓取某个页面内容是不允许的.那么我们可以利用Urllib2库保存我们登录的Cookie,然后再抓取其他页面就达到目的了. 在此之前呢,我们必须先介绍一个opener的概念. 1.Opener 当你获取一个

  • 详解在Python程序中自定义异常的方法

    通过创建一个新的异常类,程序可以命名它们自己的异常.异常应该是典型的继承自Exception类,通过直接或间接的方式. 以下为与RuntimeError相关的实例,实例中创建了一个类,基类为RuntimeError,用于在异常触发时输出更多的信息. 在try语句块中,用户自定义的异常后执行except块语句,变量 e 是用于创建Networkerror类的实例. class Networkerror(RuntimeError): def __init__(self, arg): self.arg

  • 详解微信小程序中的页面代码中的模板的封装

    详解微信小程序中的页面代码中的模板的封装 最近在进行微信小程序中的页面开发,其实在c++或者说是js中都会出现这种情况,就是相同的代码会反复出现,这就是进行一定的封装,封装的好处就是可以是程序中在于减少一定的代码量,并且可是使代码结构更加清晰.那今天所要记录的就是关于微信小程序中的页面的模板封装. 在微信小程序中的文件名都带有wxml等样式,在wxml中提供了模板,即可以在模板中定义代码片段,然后可以在页面中的不同位置进行调用,模板的定义: <templatename="products&

  • 分析如何在Python中解析和修改XML

    目录 一.什么是XML? 二.Python XML解析模块 2.1.xml.etree.ElementTree模块 2.2.xml.dom.minidom模块 一.什么是XML? XML代表可扩展标记语言.它在外观上类似于HTML,但XML用于数据表示,而HTML用于定义正在使用的数据.XML专门设计用于在客户端和服务器之间来回发送和接收数据.看看下面的例子: 例子: <? xml version ="1.0" encoding ="UTF-8" ?>

  • 详解在Java程序中运用Redis缓存对象的方法

    这段时间一直有人问如何在Redis中缓存Java中的List 集合数据,其实很简单,常用的方式有两种: 1. 利用序列化,把对象序列化成二进制格式,Redis 提供了 相关API方法存储二进制,取数据时再反序列化回来,转换成对象. 2. 利用 Json与java对象之间可以相互转换的方式进行存值和取值. 正面针对这两种方法,特意写了一个工具类,来实现数据的存取功能. 1. 首页在Spring框架中配置 JedisPool 连接池对象,此对象可以创建 Redis的连接 Jedis对象.当然,必须导

  • 详解mpvue小程序中怎么引入iconfont字体图标

    前言 iconfont阿里巴巴矢量图标库是我很喜欢的一个网站,可以下载/在线编辑/上传自己需要的矢量图标,也支持团队协作,那么在mpvue项目中如何引入呢? iconfont阿里巴巴矢量图标库 将图标加入购物车 搜索关键词可以是中文也可以是英文 下载素材 点击网站右上角的购物车图标,此处我们选第三个 ps:添加到项目很有用,可以在线编辑自己喜欢的图标大小样式/重命名/邀请成员等,此处我们选择加入项目并下载代码 文件解压 一般网页中为了兼容性考虑,我们会留下css/ttf/svg/woff/eot

  • 详解解决小程序中webview页面多层history返回问题

    小程序开发中遇到的问题:小程序中嵌套了一个webview页面,webview页面中有静默授权(A1页面静默授权后重定向到A2页面),点小程序原生的返回按钮会返回到A1页面,然后页面就会反复静默授权 预期表现:点小程序原生的返回按钮后返回到小程序上个页面 解决方案:通过history.pushState添加历史记录名目,history.onpopstate监听历史记录条目发生变化时,调用小程序APIwx.navigateBack window.addEventListener('popstate'

  • 详解微信小程序中var、let、const用法与区别

    微信小程序可以使用Javascript的最新ES6标准来开发所以微信小程序中var.let.const用法与区别可以视为Javascript ES6标准中var.let.const用法与区别 let命令 基本用法 ES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. { let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1 上面代码在代码块之中,分

  • 详解将Python程序(.py)转换为Windows可执行文件(.exe)

    python开发者向普通windows用户分享程序,要给程序加图形化的界面(传送门:这可能是最好玩的python GUI入门实例! https://www.jb51.net/article/165763.htm),并要将软件打包为可执行文件(.exe结尾),那如何将.py转为.exe ? 将.py转为.exe 第一步:安装pyinstaller(这里临时调用了国内豆瓣镜像源,这样下载比较快) pip install pyinstaller -i https://pypi.douban.com/s

随机推荐