首页 > 编程 > Python > 正文

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

2020-01-04 17:57:24
字体:
来源:转载
供稿:网友

这篇文章主要介绍了Python通过DOM和SAX方式解析XML的应用实例分享,针对这两种解析方式Python都有相关的模块可供使用,需要的朋友可以参考下

XML.DOM

需求

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

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

解决

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

上游读取到对应的数据

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

XML文件

 

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <!-- 表名 ,数据库名 可灵活配置插入哪个库哪个表 --> 
  3. <table name="top_query" db_name="evaluting_sys"
  4. <!-- 非业务主键,自增长,可配名,其他 INTEGER UNSIGNED AUTO_INCREMENT --> 
  5. <primary_key> 
  6. <name>id</name> 
  7. </primary_key> 
  8. <!-- 字段开始 --> 
  9. <field> 
  10. <name>query</name> 
  11. <type>varchar(200)</type> 
  12. <is_index>false</is_index> 
  13. <description>query</description> 
  14. </field> 
  15. <field> 
  16. <name>pv</name> 
  17. <type>integer</type> 
  18. <is_index>false</is_index> 
  19. <description>pv</description> 
  20. </field> 
  21. <field> 
  22. <name>avg_money</name> 
  23. <type>integer</type> 
  24. <is_index>false</is_index> 
  25. <description></description> 
  26. </field> 
  27. <!-- 字段配置结束 --> 
  28. </table> 

处理脚本

 

 
  1. #!/usr/bin/python 
  2. # -*- coding:utf-8 -*- 
  3. #author: wklken 
  4. #desc: use to read db xml config. 
  5. #----------------------- 
  6. #2012-02-18 created 
  7. #---------------------- 
  8.  
  9. import sys,os 
  10. from xml.dom import minidom, Node 
  11.  
  12. def read_dbconfig_xml(xml_file_path): 
  13. content = {} 
  14.  
  15. root = minidom.parse(xml_file_path) 
  16. table = root.getElementsByTagName("table")[0] 
  17.  
  18. #read dbname and table name. 
  19. table_name = table.getAttribute("name"
  20. db_name = table.getAttribute("db_name"
  21.  
  22. if len(table_name) > 0 and len(db_name) > 0: 
  23. db_sql = "create database if not exists `" + db_name +"`; use " + db_name + ";" 
  24. table_drop_sql = "drop " + table_name + " if exists " + table_name + ";" 
  25. content.update({"db_sql" : db_sql}) 
  26. content.update({"table_sql" : table_drop_sql }) 
  27. else
  28. print "Error:attribute is not define well! db_name=" + db_name + " ;table_name=" + table_name 
  29. sys.exit(1) 
  30. #print table_name, db_name 
  31.  
  32. table_create_sql = "create table " + table_name +"(" 
  33.  
  34. #read primary cell 
  35. primary_key = table.getElementsByTagName("primary_key")[0] 
  36. primary_key_name = primary_key.getElementsByTagName("name")[0].childNodes[0].nodeValue 
  37.  
  38. table_create_sql += primary_key_name + " INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY," 
  39.  
  40. #print primary_key.toxml() 
  41. #read ordernary field 
  42. fields = table.getElementsByTagName("field"
  43. f_index = 0 
  44. for field in fields: 
  45. f_index += 1 
  46. name = field.getElementsByTagName("name")[0].childNodes[0].nodeValue 
  47. type = field.getElementsByTagName("type")[0].childNodes[0].nodeValue 
  48. table_create_sql += name + " " + type 
  49. if f_index != len(fields): 
  50. table_create_sql += "," 
  51. is_index = field.getElementsByTagName("is_index")[0].childNodes[0].nodeValue 
  52.  
  53. table_create_sql += ");" 
  54. content.update({"table_create_sql" : table_create_sql}) 
  55. #character set latin1 collate latin1_danish_ci; 
  56. print content 
  57.  
  58.  
  59. if __name__ == "__main__"
  60. 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文档

 

 
  1. <PERSONS> 
  2. <person> 
  3. <id>100000</id> 
  4. <sex>男</sex> 
  5. <address>北京,海淀区</address> 
  6. <fansNum>437</fansNum> 
  7. <summary>1989</summary> 
  8. <wbNum>333</wbNum> 
  9. <gzNum>242</gzNum> 
  10. <blog>null</blog> 
  11. <edu>大学</edu> 
  12. <work></work> 
  13. <renZh>1</renZh> 
  14. <brithday>2月14日</brithday> 
  15. </person> 
  16. </PERSONS> 

处理

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

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

代码及注解

person 处理类

 

 
  1. from xml.sax import handler,parseString 
  2. class PersonHandler(handler.ContentHandler): 
  3. def __init__(self, db_ops): 
  4. #db op obj 
  5. self.db_ops = db_ops 
  6. #存储一个person的map 
  7. self.person = {} 
  8. #当前的tag 
  9. self.current_tag = "" 
  10. #是否是tag之间的内容 ,目的拿到tag间内容,不受空白的干扰 
  11. self.in_quote = 0 
  12. #开始,清空map 
  13. def startElement(self, name, attr): 
  14. #以person,清空map 
  15. if name == "person"
  16. self.person = {} 
  17. #记录 状态 
  18. self.current_tag = name 
  19. self.in_quote = 1 
  20. #结束,插入数据库 
  21. def endElement(self, name): 
  22. #以person结尾 代表读取一个person的信息结束 
  23. if name == "person"
  24. #do something 
  25. in_fields = tuple([ ('"' + self.person.get(i,"") + '"') for i in fields ]) 
  26. print in_sql % in_fields 
  27. db_ops.insert( in_sql%(in_fields)) 
  28. #处理 
  29. self.in_quote = 0 
  30. def characters(self, content): 
  31. #若是在tag之间的内容,更新到map中 
  32. if self.in_quote: 
  33. self.person.update({self.current_tag: content}) 

加上入库的完整代码

 

 
  1. #!/usr/bin/python 
  2. # -*- coding:utf-8 -*- 
  3. #parse_person.py 
  4. #version : 0.1 
  5. #author : wukunliang@163.com 
  6. #desc : parse person.xml and out sql 
  7.  
  8.  
  9. import sys,os 
  10. import MySQLdb 
  11.  
  12. reload(sys) 
  13. sys.setdefaultencoding('utf-8'
  14.  
  15. in_sql = "insert into person(id,sex,address,fansNum,summary,wbNum,gzNum,blog,edu,work,renZh,brithday) values(%s, %s, %s, %s, %s, %s, 
  16. %s, %s, %s, %s, %s, %s)" 
  17.  
  18. fields = ("id","sex","address","fansNum","summary","wbNum","gzNum","blog","edu","work","renZh","brithday"
  19.  
  20. #数据库方法 
  21. class Db_Connect: 
  22. def __init__(self, db_host, user, pwd, db_name, charset="utf8", use_unicode = True): 
  23. print "init begin" 
  24. print db_host, user, pwd, db_name, charset , use_unicode 
  25. self.conn = MySQLdb.Connection(db_host, user, pwd, db_name, charset=charset , use_unicode=use_unicode) 
  26. print "init end" 
  27.  
  28. def insert(self, sql): 
  29. try
  30. n = self.conn.cursor().execute(sql) 
  31. return n 
  32. except MySQLdb.Warning, e: 
  33. print "Error: execute sql '",sql,"' failed" 
  34.  
  35. def close(self): 
  36. self.conn.close() 
  37.  
  38. #person 处理类 
  39. from xml.sax import handler,parseString 
  40. class PersonHandler(handler.ContentHandler): 
  41. def __init__(self, db_ops): 
  42. #db op obj 
  43. self.db_ops = db_ops 
  44. #存储一个person的map 
  45. self.person = {} 
  46. #当前的tag 
  47. self.current_tag = "" 
  48. #是否是tag之间的内容 
  49. self.in_quote = 0 
  50. #开始,清空map 
  51. def startElement(self, name, attr): 
  52. #以person,清空map 
  53. if name == "person"
  54. self.person = {} 
  55. #记录 状态 
  56. self.current_tag = name 
  57. self.in_quote = 1 
  58. #结束,插入数据库 
  59. def endElement(self, name): 
  60. #以person结尾 代表读取一个person的信息结束 
  61. if name == "person"
  62. #do something 
  63. in_fields = tuple([ ('"' + self.person.get(i,"") + '"') for i in fields ]) 
  64. print in_sql % in_fields 
  65. db_ops.insert( in_sql%(in_fields)) 
  66. #处理 
  67. self.in_quote = 0 
  68. def characters(self, content): 
  69. #若是在tag之间的内容,更新到map中 
  70. if self.in_quote: 
  71. self.person.update({self.current_tag: content}) 
  72.  
  73. if __name__ == "__main__"
  74. f = open("./person.xml"
  75. #如果源文件gbk 转码 若是utf-8,去掉decode.encode 
  76. db_ops = Db_Connect("127.0.0.1""root""root""test"
  77. parseString(f.read().decode("gbk").encode("utf-8"), PersonHandler(db_ops)) 
  78. f.close() 
  79. db_ops.close() 

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表