- # parsexml.py
- # 本例子参考自python联机文档,做了适当改动和添加
- import xml.parsers.expat
- # 控制打印缩进
- level = 0
- # 获取某节点名称及属性值集合
- def start_element(name, attrs):
- global level
- print ' '*level, 'Start element:', name, attrs
- level = level + 1
- # 获取某节点结束名称
- def end_element(name):
- global level
- level = level - 1
- print ' '*level, 'End element:', name
- # 获取某节点中间的值
- def char_data(data):
- if(data == '/n'):
- return
- if(data.isspace()):
- return
- global level
- print ' '*level, 'Character data:', data
- p = xml.parsers.expat.ParserCreate()
- p.StartElementHandler = start_element
- p.EndElementHandler = end_element
- p.CharacterDataHandler = char_data
- p.returns_unicode = False
- f = file('sample.xml')
- p.ParseFile(f)
- f.close()
测试用例:
- xml version="1.0"?>
- <contacts id="bluecrystal">
- <item name="keen" fff="ddd">
- <telephone type="phone">222222222 telephone>
- <telephone type="mobile">134567890 telephone>
- item>
- <item name="bcm">
- <telephone type="phone">11111111 telephone>
- <telephone type="mobile">15909878909 telephone>
- item>
- contacts>
测试结果:
- Start element: contacts {'id': 'bluecrystal'}
- Start element: item {'fff': 'ddd', 'name': 'keen'}
- Start element: telephone {'type': 'phone'}
- Character data: 222222222
- End element: telephone
- Start element: telephone {'type': 'mobile'}
- Character data: 134567890
- End element: telephone
- End element: item
- Start element: item {'name': 'bcm'}
- Start element: telephone {'type': 'phone'}
- Character data: 11111111
- End element: telephone
- Start element: telephone {'type': 'mobile'}
- Character data: 15909878909
- End element: telephone
- End element: item
- End element: contacts
转贴请注明出处http://blog.csdn.net/porcupinefinal
网上关于xml文件解析的例子多如牛毛,用python解析的也不少,在百度输入python xml就会出来不少结果。我也是从这些例子和文章中学的,所以会有类似的地方,当然我也会加入自己的一些体会。
《dive into python》第五章对这一部分有较详尽的讲解,如果你不喜欢看英文的话,可到这个网站:http://www.chinesepython.org/pythonfoundry/limodoupydoc/dive/html/toc.html查阅。
下边开始我们的xml解析之旅:
处理xml有两种方法:
FIRST:SAX—Simple API for XML。它的工作方式是,一次读出一点XML,对发现的每个元素调用一个方法。SAX是 XML 语法分析器的公用语法分析器接口。它允许应用程序作者编写使用 XML 语法分析器的应用程序,但是它却独立于所使用的语法分析器。(将它看作 XML 的 JDBC。)(Lars Marius Garshol,SAX for Python)
功能:基本上是一个 XML 文档的顺序处理器。应用程序员将定义一个 handler 类,而不是语法分析器类,该 handler 类能注册到任何所使用的语法分析器中。必须定义 4 个 SAX 接口(每个接口都有几个方法):DocumentHandler、DTDHandler、EntityResolver 和 ErrorHandler。创建语法分析器除非被覆盖,否则它还连接默认接口。
SECOND:DOM—Document Object Model。它的工作方式是,一次读出整个XML文档,通过将本地的Python类链接到一个树型结构中,生成文档的一个内部表示。
这篇文章里我主要用的是SAX这种方法(在dive into python一书中用的是DOM这种方式,我将在下一篇文章python与xml之更新篇中用这种方法举例如何增加、更新及删除xml文件中的某个节点。)我之所以选择这种方法是因为关于用DOM来解析xml的文章实在太多,没有什么从新写的必要,网上也有人说用DOM解析较大的xml文件时效率较低的问题(自己没有测试过,有人说是5M的文件要解析20分钟。。。是够慢的),所以我选择了用SAX来解析xml。
示例:(该示例转载自ibm上可爱的python系列)
import string
import xml.sax
from xml.sax.handler import *
classQuotationHandler(ContentHandler):
"""Crude extractor for quotations.dtd compliant XML document"""
def __init__(self):
self.in_quote = 0
self.thisquote = ''
def startDocument(self):
print '--- Begin Document ---'
def startElement(self, name, attrs):
if name == 'quotation':
print 'QUOTATION:'
self.in_quote = 1
else:
self.thisquote = self.thisquote + '{'
def endElement(self, name):
if name == 'quotation':
print string.join(string.split(self.thisquote[:230]))+'...',
print '('+str(len(self.thisquote))+' bytes)/n'
self.thisquote = ''
self.in_quote = 0
else:
self.thisquote = self.thisquote + '}'
def characters(self, ch):
if self.in_quote:
self.thisquote = self.thisquote + ch
if __name__ == '__main__':
parser = xml.sax.make_parser()
handler = QuotationHandler()
parser.setContentHandler(handler)
parser.parse("sample.xml")
要点:
<!--[if !supportLists]-->1、 <!--[endif]-->注意黑体加粗部分,首先继承ContentHandler,构造自己的handler;
<!--[if !supportLists]-->2、 <!--[endif]-->剩下的startElement、endElement、characters三个接口必须实现,startElement和endElement主要用于解析形如<school>北理</school>的结构,当处理器进入<school>时将in_quote置为1,在characters中将“北理”这个值赋于self.thisquote然后在endElement中可通过self.thisquote获得“北理”这一值;
<!--[if !supportLists]-->3、 <!--[endif]-->形如<class id=”09120016” />或<class id=”09120016”></class>的解析在startElement中进行,通过attrsattrs.get('id', None)获得“09120016”这一值。(在这个示例里没有,如有不明白的可以发email给我porcupine2004@126.com);
<!--[if !supportLists]-->4、 <!--[endif]-->parse() 方法处理整个流或字符串,所以不必为语法分析器创建循环;
<!--[if !supportLists]-->5、 <!--[endif]-->parse() 同样能灵活地接收一个文件名、一个文件对象,或是众多的类文件对象(一些具有 .read() 方式)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/porcupinefinal/archive/2006/03/19/629383.aspx
///
首先:xml文件(tree.xml)内容如下:
<?xml version="1.0" encoding="gb2312"?>
<treeview>
<tree id="p1">
<text>山东省</text>
<target>_blank</target>
<title>省份</title>
<link></link>
<tree id="p1-1">
<text>威海市</text>
<target>_blank</target>
<title>城市</title>
<link></link>
</tree>
<tree id="p1-2">
<text>烟台市</text>
<target>_blank</target>
<title>城市</title>
<link></link>
<node id="p1-2-1">
<text>长夼村</text>
<target>_blank</target>
<title>乡镇</title>
<link>http://www.baidu.com/</link>
</node>
</tree>
<node id="p1-3">
<text>富镇</text>
<target>_blank</target>
<title>乡镇</title>
<link>http://www.baidu.com/</link>
</node>
</tree>
<tree id="p2">
<text>河北省</text>
<target>_blank</target>
<title>省份</title>
<link></link>
<tree id="p2-1">
<text>泊头市</text>
<target>_blank</target>
<title>城市</title>
<link></link>
<node id="p2-1-1">
<text>郊河</text>
<target>_blank</target>
<title>乡镇</title>
<link>http://www.baidu.com/</link>
</node>
</tree>
<tree id="p2-2">
<text>石家庄</text>
<target>_blank</target>
<title>城市</title>
<link></link>
</tree>
</tree>
<tree id="p3">
<text>浙江省</text>
<target>_blank</target>
<title>省份</title>
<link></link>
<tree id="p3-1">
<text>杭州市</text>
<target>_blank</target>
<title>城市</title>
<link></link>
<node id="p3-1-1">
<text>某镇</text>
<target>_blank</target>
<title>乡镇</title>
<link>http://www.baidu.com/</link>
</node>
</tree>
<tree id="p3-2">
<text>温州市</text>
<target>_blank</target>
<title>城市</title>
<link></link>
<node id="p3-2-1">
<text>某镇</text>
<target>_blank</target>
<title>乡镇</title>
<link>http://www.baidu.com/</link>
</node>
</tree>
</tree>
</treeview>
//
然后:javascript函数实现:(文件名称:tree.htm)
<script Language="JavaScript">
var HTML = "";
var space = "";
var blank = " ";
function getSubject()
{
var xmlDoc;
if(window.ActiveXObject)
{
//获得操作的xml文件的对象
xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
xmlDoc.async = false;
xmlDoc.load("tree.xml");
if(xmlDoc == null)
{
alert('您的浏览器不支持xml文件读取,于是本页面禁止您的操作,推荐使用IE5.0以上可以解决此问题!');
window.location.href='/Index.aspx';
return;
}
}
//解析xml文件,判断是否出错
if(xmlDoc.parseError.errorCode != 0)
{
alert(xmlDoc.parseError.reason);
return;
}
//获得根接点
var nodes = xmlDoc.documentElement.childNodes;
//得到根接点下共有子接点个数,并循环
for(var i=0; i<nodes.length; i++)
{
//如果接点名为 tree
if(nodes(i).nodeName == "tree")
{
readTree(nodes(i));
}
//如果接点名为 node
else if(nodes(i).nodeName == "node")
{
readNode(nodes(i));
}
}
//删除对象
delete(xmlDoc);
//显示HTML
window.show.innerHTML = HTML;
return;
}
//读Tree节点
function readTree(cI)
{
var nodes = cI.childNodes;
var menuHTML = space;
menuHTML += blank;
//得到超级链接
menuHTML += "<a href='";
//如果该节点的连接属性不为空,则连接
if(cI.selectNodes("link")(0).text != "")
{
menuHTML += cI.selectNodes("link")(0).text;
}
//否则为空链接
else
{
menuHTML += "#";
}
//目标
if(cI.selectNodes("target")(0).text != "")
{
menuHTML += " target='"+cI.selectNodes("target")(0).text;
menuHTML += "'";
}
//点击菜单事件,调用divshow(vid)函数
menuHTML += " οnclick=javascript:divshow('"+cI.getAttribute("id")+"');";
//得到节点标题
menuHTML += " title='";
menuHTML += cI.selectNodes("title")(0).text;
//结束
menuHTML += "'>";
//得到节点的正文
menuHTML += cI.selectNodes("text")(0).text;
menuHTML += "</a><br>/n";
//将menuHTML设置添加到HTML字符串
HTML += menuHTML;
//得到该节点的属性值<span
HTML += "<div id='"+cI.getAttribute("id")+"' style='display:none'>/n";
for(var i=0; i<nodes.length; i++)
{
var tempImg = "";
tempImg += blank;
if(nodes(i).nodeName == "tree")
{
space += tempImg;
readTree(nodes(i));
space = "";
}
else if(nodes(i).nodeName == "node")
{
space += tempImg;
readNode(nodes(i));
}
}
HTML += "</div>/n";
return;
}
//读Node节点
function readNode(cI)
{
var nodeHTML = space;
nodeHTML += blank;
//设置超级链接
nodeHTML += "<a href='";
//得到连接地址
nodeHTML += cI.selectNodes("link")(0).text;
//目标
if(cI.selectNodes("target")(0).text != "")
nodeHTML += "' target='"+cI.selectNodes("target")(0).text;
//得到节点标题
nodeHTML += "' title='";
nodeHTML += cI.selectNodes("title")(0).text;
//结束
nodeHTML += "'>";
//得到节点的正文
nodeHTML += cI.selectNodes("text")(0).text;
nodeHTML += "</a><br>/n";
HTML += nodeHTML;
//HTML += "<div id='"+cI.getAttribute("id")+"'>";
space = "";
return;
}
//操作对象的显示还是隐藏效果
function divshow(vid)
{
if(document.all[vid].style.display == "none")
{
document.all[vid].style.display = "block";
}
else
{
document.all[vid].style.display = "none";
}
return;
}
</script>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>JS_XML</title>
<style type="text/css">
<!--
body
{
margin-left: 0px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
font-size: 9pt;
}
A
{
text-decoration:none;
font-family: "宋体";
font-size: 9pt;
COLOR:#000000;
}
-->
</style>
</head>
<body bgcolor="#EEEEEE" leftmargin="0" topmargin="0">
<div id=show></div>
</body>
<script>
getSubject()
</script>
</html>
//
运行,要在同一个路径下!