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 中的列表解析和生成表达式
Mar 10 Python
动态规划之矩阵连乘问题Python实现方法
Nov 27 Python
python3正则提取字符串里的中文实例
Jan 31 Python
python交易记录链的实现过程详解
Jul 03 Python
Python爬虫 scrapy框架爬取某招聘网存入mongodb解析
Jul 31 Python
详解pandas DataFrame的查询方法(loc,iloc,at,iat,ix的用法和区别)
Aug 02 Python
Python实现点云投影到平面显示
Jan 18 Python
浅谈图像处理中掩膜(mask)的意义
Feb 19 Python
Python 去除字符串中指定字符串
Mar 05 Python
python使用matplotlib:subplot绘制多个子图的示例
Sep 24 Python
python实现跨年表白神器--你值得拥有
Jan 04 Python
Python如何使用logging为Flask增加logid
Mar 30 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
php include和require的区别深入解析
2013/06/17 PHP
初识ThinkPHP控制器
2016/04/07 PHP
Laravel学习教程之View模块详解
2017/09/18 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
2017/12/26 PHP
PHP dirname功能及原理实例解析
2020/10/28 PHP
制作高质量的JQuery Plugin 插件的方法
2010/04/20 Javascript
JS获取地址栏参数的小例子
2013/08/23 Javascript
jQuery中has()方法用法实例
2015/01/06 Javascript
举例简介AngularJS的内部语言环境
2015/06/17 Javascript
Vue绑定内联样式问题
2018/10/17 Javascript
微信小程序顶部导航栏可滑动并选中放大
2019/12/05 Javascript
vue 获取url参数、get参数返回数组的操作
2020/11/12 Javascript
JavaScript构造函数原理及实现流程解析
2020/11/19 Javascript
Python ORM框架SQLAlchemy学习笔记之安装和简单查询实例
2014/06/10 Python
python pip安装包出现:Failed building wheel for xxx错误的解决
2019/12/25 Python
Python实现自动访问网页的例子
2020/02/21 Python
Jupyter notebook运行Spark+Scala教程
2020/04/10 Python
解决更改AUTH_USER_MODEL后出现的问题
2020/05/14 Python
Python 使用Opencv实现目标检测与识别的示例代码
2020/09/08 Python
pandas按照列的值排序(某一列或者多列)
2020/12/13 Python
HTML5中的nav标签学习笔记
2016/06/24 HTML / CSS
利用Node实现HTML5离线存储的方法
2020/10/16 HTML / CSS
John Hardy官方网站:手工设计首饰的奢侈品牌
2017/07/05 全球购物
澳洲小众品牌的集合网站:BNKR
2018/02/23 全球购物
卡骆驰德国官方网站:Crocs德国
2019/03/29 全球购物
意大利时尚奢侈品店:D’Aniello Boutique
2021/01/19 全球购物
CAD制图人员的自荐信
2014/02/07 职场文书
数控专业毕业生自荐信范文
2014/03/04 职场文书
党支部书记四风问题整改措施
2014/09/24 职场文书
公证书格式
2015/01/23 职场文书
质量保证书格式
2015/02/27 职场文书
预备党员自我评价范文
2015/03/04 职场文书
2015年物业管理工作总结
2015/04/23 职场文书
2019年度行政文员工作计划范本!
2019/07/04 职场文书
某某店铺的开业庆典主持词范本
2019/11/25 职场文书
《好妈妈胜过好老师》:每个孩子的优秀都是有源头的
2020/01/03 职场文书