python 学习笔记(11)XML文件

来源:互联网 发布:财汇金融数据库 编辑:程序博客网 时间:2024/06/07 22:37

 

声明:本文系本人学习python3总结,如有侵权等,请及时告知;

                       欢迎转载:请保留 http://blog.csdn.net/kevinx_xu/article/details/8919332

XML 是一种描述层次结构化数据的通用方法。XML文档包含由起始和结束标签(tag)分隔的一个或多个元素(element)

一、XML 文档解析

         1XML文档中的第一个元素叫做根元素(root element)。并且每份XML文档只能有一个根元素。

         <root>

         </root>

         2、元素可以有其属性(attribute),它们是一些名字‐值(namevalue)对。属性由空格分隔列举在元素的起始标签中。一个元素中属性名不能重复。属性值必须用引号包围起来。单引号、双引号都是可以。

         <root  lang = Chinese>

                   <sublang = 'English' id = 'id1'>

                   </sub>

         </root>

         3、每个元素都其独立的属性集。如果元素有多个属性,书写的顺序并不重要。元素的属性是一个无序的键‐值对集,跟Python中的列表对象一样。另外,元素中属性的个数是没有限制的。

         4、元素可以有其文本内容(text content)  

         5、如果某一元素既没有文本内容,也没有子元素,它也叫做空元素。  即只有一个根元素;

         6、表达空元素有一种简洁的方法。通过在起始标签的尾部添加/字符,我们可以省略结束标签。

         <root/>

         7、像Python函数可以在不同的模块(modules)中声明一样,也可以在不同的名字空间(namespace)中声明XML元素。XML文档的名字空间通常看起来像URL。我们可以通过声明xmlnsxmlnamespace)来定义默认名字空间。名字空间声明跟元素属性看起来很相似,但是它们的作用是不一样的。

        名字空间声明不仅会作用于当前声明它的元素,还会影响到该元素的所有子元素。

         8、也可以通过xmlns:prefix声明来定义一个名字空间并取其名为prefix。然后该名字空间中的每个元素都必须显式地使用这个前缀(prefix)来声明。

         9、对于XML解析器而言,名字空间 + 元素名 = XML标识。前缀只是用来引用名字空间的,所以对于解析器来说,这些前缀名其实无关紧要的。名字空间相同,元素名相同,属性(或者没有属性)相同,每个元素的文本内容相同,则XML文档相同

         10、在根元素之前,字符编码信息可以出现在XML文档的第一行。(这里存在一个两难的局面(catch22),直观上来说,解析XML文档需要这些编码信息。

         <?xml version='1.0' encoding='utf8'?> 

二、XML文档解析

         在有一些XML文档中,元素的排列顺序是有意义的,但是Atom feed中不需要这样做。  

         ython可以使用几种不同的方式解析XML文档。它包含了DOSAX解析器,但是我们焦点将放在另外一个叫做ElemenMtTree的库上边。  \

        

         1、导入XML解析工具

         importxml.etree.ElementTree as etree

         导入xml.etree.ElementTree重命名为etree

         或者使用fromxml.etree import ElementTree

       2、调用解析方法进行解析

                   a_tree= etree.parse('example.xml')

                   parse()函数是ElementTree库的主要入口,它使用文件名或者流对象作为参数。parse()函数会立即解析完整个文档。如果内存资源紧张,也可以增量式地解析XML文档  3.  parse()函数会返回一个能代表整篇文档的对象。这不是根元素。要获得根元素的引用可以调用getroot()方法。  

         3、获取根元素

                   a_root= a_tree.getroot()

                   调用后,会返回根元素的入口地址给a_root;

                 XML 元素由名字空间和标签名(也称作本地名(local name))组成。

                   ElementTree使用{namespace}localname来表达XML元素。

         4、元素即列表

                   ElementTree API中,元素的行为就像列表一样。列表中的项即该元素的子元素。

                   1)根元素

                            或如根元素信息

                            >>>a_root.tag

                            根元素的“长度”即子元素的个数。

                            >>>lena_root

                   2)每一个entry元素都有其子元素,但是并没有包括在这个root列表中。这些子元素本可以包括在entry元素的列表中,但是确实不属于feed的子元素。但是,无论这些元素嵌套的层次有多深,总是有办法定位到它们的。

         5、属性即字典

                  XML 不只是元素的集合;每一个元素还有其属性集。一旦获取了某个元素的引用,我们可以像操作Python的字典一样轻松获取到其属性。  

                  1a_root.attrib是一个代表元素属性的字典

                  2a_root[n].attrib将元素划分为列表,去列表中的属性字典;

         6、XML文档中查找结点

                   1  findfall()方法查找匹配特定格式的子元素。

                   2)每个元素  包括根元素及其子元素  都有findall()方法。

                   3find()方法用来返回第一个匹配到的元素。当我们认为只会有一个匹配,或者有多个匹配但我们只关心第一个的时候,这个方法是很有用的。

                   4find()方法非常容易被误解。在布尔上下文中,如果ElementTree元素对象不包含子元素,其值则会被认为是False(即如果len(element)等于0)。这就意味着if element.find('...')并非在测试是否find()方法找到了匹配项;这条语句是在测试匹配到的元素是否包含子元素!想要测试find()方法是否返回了一个元素,则需使用if element.find('...') is not None

 

·,ElementTreefindall()方法是其一个非常强大的特性,但是它的查询语言却让人有些出乎意料。官方描述它为“有限的XPath支持。”XPath是一种用于查询XML文档的W3C

准。对于基础地查询来说,ElementTreeXPath语法上足够相似,但是如果已经会XPath的话,它们之间的差异可能会使你感到不快。

 

三、深入LXML 对XML 文件解析

         1、导入lxml

                   >>> from lxml import etree 

         2、特点

                   1)  导入lxml 以后,可以发现它与内置的ElementTree库提供相同的API  

                   2)  parse()函数:与ElementTree相同。  

                   3)  getroot()方法:相同。  

                   4)  findall()方法:完全相同。  

3、查询语句

                头部的 // 表示“搜索的范围为整个文档(而不只是根元素的子元素)”。{http://www.w3.org/2005/Atom}表示“仅搜索 Atom名字空间。” *表示“任何本地名称的元素。”而 [@href]表示“具备 href属性。”

4. lxml 还集成了对任意 XPath 1.0表达式的支持。

>>> import lxml.etree

>>> tree =lxml.etree.parse('examples/feed.xml')

>>> NSMAP = {'atom':'http://www.w3.org/2005/Atom'}                   

>>> entries =tree.xpath("//atom:category[@term='accessibility']/..", 

...    namespaces=NSMAP)

>>> entries                                                           

[<Element{http://www.w3.org/2005/Atom}entry at e2b630>]

>>> entry = entries[0]

>>> entry.xpath('./atom:title/text()',namespaces=NSMAP)              

['Accessibility is a harsh mistress']

     要对名字空间中的元素执行XPath查询,必须先定义一个名字空间前缀映射。它只不过是一个 Python字典对象。

     这是一条 XPath查询请求。该 XPath表达式用于搜索category元素(在 Atom名字空间),且该元素包含有值为 accessibility term属性。但实际上那并不是查询结果。请注意查询字符串的尾端;是否注意到了 /..这个部分?它的意思是:“然后返回所找到的 category元素的父元素。”所以这条 XPath查询语句会找到所有包含 <category term='accessibility'>子元素的 entry

     xpath() 函数返回一个ElementTree 对象列表。该文档中,只有一个 entry带有 category元素,且该 category元素的 term属性值为 accessibility

     XPath 表达式并不总是返回元素列表。技术上说,经解析的 xml 文档其 dom并不包含元素;它只包含节点(nodes)。根据类型的不同,结点可能是元素、属性,甚至是文本内容。XPath查询的结果是结点的列表。本次查询返回一个文本节点的列表:当前元素(./)的子元素——title 元素的文本内容 (text())

四、生成XML

         Python xml的支持不只限于解析已有文档。还可以用于从零开始创建 xml文档。

           Element类实例化创建一个新元素。将元素的名字(名字空间 +本地名)作为第一个参数。

             将属性名和值构成的字典对象传递给attrib参数,可以向新创建的元素添加属性。请注意,属性名应该使用标准的 ElementTree格式——{namespace}localname

           任何时候都可以使用 ElementTree tostring()函数将任意元素(还有它的子元素)序列化。

        ElementTree用于序列化命名空间 xml元素方法技术上来说是最精确的,但却不是最理想的。

         ④内置的 ElementTree库没有对序列化时名字空间内的元素提供细粒度控制,但是 lxml 有这样的功能。

 

5、用lxml 创建xml文件

     定义一个用于名字空间映射的字典对象。其值为名字空间;字典中的键即为所需要的前缀。使用 None作为前缀来定义默认的名字空间。

     在创建元素的时候,给lxml专有的 nsmap参数传值,而 lxml会考虑我们所定义的名字空间前缀。

     加上属性。可以使用set()方法随时给元素添加所需属性。该方法接受两个参数:采用标准 ElementTree格式的属性名及该属性的值。(该方法并非 lxml 所特有的。该示例中,只有 nsmap参数是 lxml特有的,它用于控制序列化输出时名字空间的前缀。)

6、xml 文件创建子元素

     要给已有元素创建子元素,需要实例化 SubElement类。它只要求两个参数,父元素(即该样例中的(new_feed)和子元素的名字。由于子元素会从父元素那儿继承名字空间的映射关系,此处无须要再声明名字空间前缀。

     也可以传入一个属性字典。字典的键即属性名;值为属性的值。

     要设定元素的文本内容,只需要设定其 .text属性。

  包含了小于号(<)或者&符号的内容在序列化的时候需要进行转义。lxml会自动处理转义。

     pretty_print=True向结束标签及不好汉任何文本内容的起始标签之后面添加换行。从技术角度来说,为了增加输出结果的可读性,lxml添加了“不重要的空白”。

xmlwitch,它也是用来生成xml的另一个第三方类库。它大量地使用了with语句来提高所生成 xml代码的可读性。

7、解析缺损的 XML

     lxml.etree.XMLParser类实例化,创建一个自定义的解析器。它可以接收多个不同的具名参数。recover参数。如果设置为 True xml解析器会尽力“恢复”编排良好性错误。

     如果要用自定义解析器来处理xml文档,必须将 parser对象当做第二个参数传递给 parse()函数。请注意, lxml没有因为那个未定义的实体而抛出异常。

     解析器会通过日志记录所遇到的编排良好性错误。(无论它是否设置为恢复错误,它总是会这么做。)

     由于不知道如何处理该未定义的实体,解析器只会默默地将其丢弃。

  必须强调的是,这种“可恢复”的 xml解析器无法保证互换性。另一个不同的解析器可能就会认为实体来自 html,并将其替换。,两种处理方法都不正确。正确的行为(根据 xml规范)应该是终止解析操作。如果已经决定不遵循规范,你得自己负责。

原创粉丝点击