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


Posted in Python onNovember 16, 2015

XML.DOM

需求
有一个表,里面数据量比较大,每天一更新,其字段可以通过xml配置文件进行配置,即,可能每次建表的字段不一样。

上游跑时会根据配置从源文件中提取,到入库这一步需要根据配置进行建表。

解决
写了一个简单的xml,配置需要字段及类型

上游读取到对应的数据

入库这一步,先把原表删除,根据配置建新表

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- 表名 ,数据库名  可灵活配置插入哪个库哪个表 -->
<table name="top_query" db_name="evaluting_sys">
<!-- 非业务主键,自增长,可配名,其他 INTEGER UNSIGNED AUTO_INCREMENT -->
<primary_key>
<name>id</name>
</primary_key>
<!-- 字段开始 -->
<field>
<name>query</name>
<type>varchar(200)</type>
<is_index>false</is_index>
<description>query</description>
</field>
<field>
<name>pv</name>
<type>integer</type>
<is_index>false</is_index>
<description>pv</description>
</field>
<field>
<name>avg_money</name>
<type>integer</type>
<is_index>false</is_index>
<description></description>
</field>
<!-- 字段配置结束 -->
</table>

处理脚本

#!/usr/bin/python
# -*- coding:utf-8 -*-
#author: wklken
#desc: use to read db xml config.
#-----------------------
#2012-02-18 created
#----------------------

import sys,os
from xml.dom import minidom, Node

def read_dbconfig_xml(xml_file_path):
  content = {}

  root = minidom.parse(xml_file_path)
  table = root.getElementsByTagName("table")[0]

  #read dbname and table name.
  table_name = table.getAttribute("name")
  db_name = table.getAttribute("db_name")

  if len(table_name) > 0 and len(db_name) > 0:
    db_sql = "create database if not exists `" + db_name +"`; use " + db_name + ";"
    table_drop_sql = "drop " + table_name + " if exists " + table_name + ";"
    content.update({"db_sql" : db_sql})
    content.update({"table_sql" : table_drop_sql })
  else:
    print "Error:attribute is not define well! db_name=" + db_name + " ;table_name=" + table_name
    sys.exit(1)
  #print table_name, db_name

  table_create_sql = "create table " + table_name +"("

  #read primary cell
  primary_key = table.getElementsByTagName("primary_key")[0]
  primary_key_name = primary_key.getElementsByTagName("name")[0].childNodes[0].nodeValue

  table_create_sql += primary_key_name + " INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,"

  #print primary_key.toxml()
  #read ordernary field
  fields = table.getElementsByTagName("field")
  f_index = 0
  for field in fields:
    f_index += 1
    name = field.getElementsByTagName("name")[0].childNodes[0].nodeValue
    type = field.getElementsByTagName("type")[0].childNodes[0].nodeValue
    table_create_sql += name + " " + type
    if f_index != len(fields):
    table_create_sql += ","
    is_index = field.getElementsByTagName("is_index")[0].childNodes[0].nodeValue

  table_create_sql += ");"
  content.update({"table_create_sql" : table_create_sql})
  #character set latin1 collate latin1_danish_ci;
  print content


if __name__ == "__main__":
read_dbconfig_xml(sys.argv[1])

涉及方法
root = minidom.parse(xml_file_path) 获取dom对象

root.getElementsByTagName("table") 根据tag获取节点列表

table.getAttribute("name") 获取属性

primary_key.getElementsByTagName("name")[0].childNodes[0].nodeValue 获取子节点的值(id 得到id)

SAX
需求
读取xml数据文件,文件较大,需要实时处理插入到数据库

xml文档

<PERSONS>
<person>
  <id>100000</id>
  <sex>男</sex>
  <address>北京,海淀区</address>
  <fansNum>437</fansNum>
  <summary>1989</summary>
  <wbNum>333</wbNum>
  <gzNum>242</gzNum>
  <blog>null</blog>
  <edu>大学</edu>
  <work></work>
  <renZh>1</renZh>
  <brithday>2月14日</brithday>
</person>
</PERSONS>

处理
sax处理时并不会像dom一样可以以类似节点的维度进行读取,它只有 开始标签 内容 结束标签 之分

处理思想是:通过一个handler,对开始标签,内容,结束标签各有一个处理函数

代码及注解
person 处理类

from xml.sax import handler,parseString
class PersonHandler(handler.ContentHandler):
 def __init__(self, db_ops):
  #db op obj
  self.db_ops = db_ops
  #存储一个person的map
  self.person = {}
  #当前的tag
  self.current_tag = ""
  #是否是tag之间的内容 ,目的拿到tag间内容,不受空白的干扰
  self.in_quote = 0
 #开始,清空map
 def startElement(self, name, attr):
  #以person,清空map
  if name == "person":
   self.person = {}
  #记录 状态
  self.current_tag = name
  self.in_quote = 1
 #结束,插入数据库
 def endElement(self, name):
  #以person结尾 代表读取一个person的信息结束
  if name == "person":
   #do something
   in_fields = tuple([ ('"' + self.person.get(i,"") + '"') for i in fields ])
   print in_sql % in_fields
   db_ops.insert( in_sql%(in_fields))
  #处理
  self.in_quote = 0
 def characters(self, content):
  #若是在tag之间的内容,更新到map中
  if self.in_quote:
   self.person.update({self.current_tag: content})

加上入库的完整代码

#!/usr/bin/python
# -*- coding:utf-8 -*-
#parse_person.py
#version : 0.1
#author : wukunliang@163.com
#desc : parse person.xml and out sql


import sys,os
import MySQLdb

reload(sys)
sys.setdefaultencoding('utf-8')

in_sql = "insert into person(id,sex,address,fansNum,summary,wbNum,gzNum,blog,edu,work,renZh,brithday) values(%s, %s, %s, %s, %s, %s,
     %s, %s, %s, %s, %s, %s)"

fields = ("id","sex","address","fansNum","summary","wbNum","gzNum","blog","edu","work","renZh","brithday")

#数据库方法
class Db_Connect:
  def __init__(self, db_host, user, pwd, db_name, charset="utf8", use_unicode = True):
    print "init begin"
    print db_host, user, pwd, db_name, charset , use_unicode
    self.conn = MySQLdb.Connection(db_host, user, pwd, db_name, charset=charset , use_unicode=use_unicode)
    print "init end"

  def insert(self, sql):
    try:
      n = self.conn.cursor().execute(sql)
      return n
    except MySQLdb.Warning, e:
      print "Error: execute sql '",sql,"' failed"

  def close(self):
    self.conn.close()

#person 处理类
from xml.sax import handler,parseString
class PersonHandler(handler.ContentHandler):
  def __init__(self, db_ops):
    #db op obj
    self.db_ops = db_ops
    #存储一个person的map
    self.person = {}
    #当前的tag
    self.current_tag = ""
    #是否是tag之间的内容
    self.in_quote = 0
  #开始,清空map
  def startElement(self, name, attr):
    #以person,清空map
    if name == "person":
     self.person = {}
    #记录 状态
    self.current_tag = name
    self.in_quote = 1
  #结束,插入数据库
  def endElement(self, name):
    #以person结尾 代表读取一个person的信息结束
    if name == "person":
      #do something
      in_fields = tuple([ ('"' + self.person.get(i,"") + '"') for i in fields ])
      print in_sql % in_fields
      db_ops.insert( in_sql%(in_fields))
    #处理
    self.in_quote = 0
  def characters(self, content):
    #若是在tag之间的内容,更新到map中
    if self.in_quote:
      self.person.update({self.current_tag: content})

if __name__ == "__main__":
  f = open("./person.xml")
  #如果源文件gbk 转码   若是utf-8,去掉decode.encode
  db_ops = Db_Connect("127.0.0.1", "root", "root", "test")
  parseString(f.read().decode("gbk").encode("utf-8"), PersonHandler(db_ops))
  f.close()
  db_ops.close()

平时拿python来分析数据,工具脚本还有hadoop streamming,但是用的面和深度实在欠缺 只能说道行还浅,需要多多实践

Python 相关文章推荐
使用python搭建Django应用程序步骤及版本冲突问题解决
Nov 19 Python
Python实现判断一个字符串是否包含子串的方法总结
Nov 21 Python
python实现朴素贝叶斯分类器
Mar 28 Python
深入分析python数据挖掘 Json结构分析
Apr 21 Python
window7下的python2.7版本和python3.5版本的opencv-python安装过程
Oct 24 Python
对tensorflow 中tile函数的使用详解
Feb 07 Python
MxNet预训练模型到Pytorch模型的转换方式
May 25 Python
Python3.9 beta2版本发布了,看看这7个新的PEP都是什么
Jun 10 Python
利用Python如何制作贪吃蛇及AI版贪吃蛇详解
Aug 24 Python
pandas 实现将NaN转换为None
May 14 Python
浅析Django接口版本控制
Jun 26 Python
baselines示例程序train_cartpole.py的ImportError
May 20 Python
Python的Flask开发框架简单上手笔记
Nov 16 #Python
python实现mysql的单引号字符串过滤方法
Nov 14 #Python
浅析Python中signal包的使用
Nov 13 #Python
Python下rrdtool模块的基本使用方法
Nov 13 #Python
简单了解Python下用于监视文件系统的pyinotify包
Nov 13 #Python
Python的pycurl包用法简介
Nov 13 #Python
使用Python下载歌词并嵌入歌曲文件中的实现代码
Nov 13 #Python
You might like
桌面中心(四)数据显示
2006/10/09 PHP
PHP怎样调用MSSQL的存储过程
2006/10/09 PHP
php 获取本机外网/公网IP的代码
2010/05/09 PHP
获取PHP警告错误信息的解决方法
2013/06/03 PHP
php ci框架验证码实例分析
2013/06/26 PHP
php实现parent调用父类的构造方法与被覆写的方法
2015/02/11 PHP
php实现QQ空间获取当前用户的用户名并生成图片
2015/07/25 PHP
PHP基于简单递归函数求一个数阶乘的方法示例
2017/04/26 PHP
jQuery获得内容和属性方法及示例
2013/12/02 Javascript
二叉树先序遍历的非递归算法具体实现
2014/01/09 Javascript
jquery遍历checkbox介绍
2014/02/21 Javascript
nodejs教程之入门
2014/11/21 NodeJs
js确认框confirm()用法实例详解
2016/01/07 Javascript
JQuery点击事件回到页面顶部效果的实现代码
2016/05/24 Javascript
jQuery 自定义下拉框(DropDown)附源码下载
2016/07/22 Javascript
json与jsonp知识小结(推荐)
2016/08/16 Javascript
使用ionic切换页面卡顿的解决方法
2016/12/16 Javascript
JavaScript数据结构之二叉查找树的定义与表示方法
2017/04/12 Javascript
vue elementUI tree树形控件获取父节点ID的实例
2018/09/12 Javascript
Vue.js中该如何自己维护路由跳转记录
2019/05/19 Javascript
手把手教你 CKEDITOR 4 实现Dialog 内嵌 IFrame操作详解
2019/06/18 Javascript
使用p5.js实现动态GIF图片临摹重现
2019/10/23 Javascript
VSCode搭建Vue项目的方法
2020/04/30 Javascript
[43:58]DOTA2上海特级锦标赛C组败者赛 Newbee VS Archon第二局
2016/02/27 DOTA
Python引用(import)文件夹下的py文件的方法
2014/08/26 Python
Python中使用语句导入模块或包的机制研究
2015/03/30 Python
Python自动化部署工具Fabric的简单上手指南
2016/04/19 Python
浅析AST抽象语法树及Python代码实现
2016/06/06 Python
非递归的输出1-N的全排列实例(推荐)
2017/04/11 Python
python中逻辑与或(and、or)和按位与或异或(&amp;、|、^)区别
2020/08/05 Python
Sentry错误日志监控使用方法解析
2020/11/12 Python
欧铁通票官方在线销售网站:Eurail.com
2017/10/14 全球购物
《理想》教学反思
2014/02/17 职场文书
团日活动总结怎么写
2014/06/25 职场文书
专题组织生活会发言材料
2014/10/17 职场文书
分享MySQL常用 内核 Debug 几种常见方法
2022/03/17 MySQL