• python 处理xml 笔记


    文档模型:用以描述词汇和文档结构,定义文档中将要出现的数据元素,元素之间的关系,以及元素的数量等

    实现文档模型的方法:模式 和 DTD (document type definition 文档类型定义)

    1 文档模型的用途

    文档模型用于在处理文档之前,验证它的内容是否符合标准。

    DTD是文档类型定义,表示文档模型的最原始的方法

    在文件顶部声明后插入一行:<!DOCTYPE config SYSTEM "library.dtd"> library.dtd是系统上的DTD路径

    DTD中元素频率和元素分组操作符

    ?指定0个或者1个前面出现的元素。

    + 指定一个或者多个前面出现的元素

    ,指定一列元素必须 以此特定的顺序出现 (title,author+)意味着书必须有一个标题,随后是一个或者多个作者,必须以该顺序出现

    (list) 将元素组织在一起。应用于圆括号后的运算符适用于组中的所有元素。(author,editor)+的含义是一篇文档可能有多个作者与多个编辑。

    !或 运算符。该运算符允许在多个选项之间选择 (author|editor)允许一本书有一个作者或者一个编辑,但是不能同时具有两者

    * 指定前面的元素或组出现0 次或多次。(book,CD)*允许图书馆中有任意数目的书或者CD 或者什么都没有,是空的。

    3 XPath 是在xml文档中描述位置和节点集合的语言。xpath表达式包含对某个节点必须匹配的模式的描述。模式要么相对于一个上下文节点,要么由文档的根节点绝对定义。绝对路径以斜杠开始。路径的每一步之间由斜杠分隔开。

    路径中的每一步包含3个部分:描述移动方向的轴,沿着该轴选择节点的测试,还有可选的谓词,它是节点必须满足的boolean 型测试。

    如:ancestor-or-self::book[1]其中ancestor-or-self是轴,book是节点测试,[1]是谓词,指定选择满足所有其他条件的第一个节点。

    节点测试既可以是一个函数,也可以是一个节点名称 book/node()将返回选择的书节点下的所有子节点,不管它们是文本还是元素。

    @ 指定属性轴,这是attribute::的缩写

    * 指定当前节点的所有子节点

    //指定当前节点的所有后代节点 :descendant-or-self::*//的缩写。如果在xpath开头使用,它将匹配文档中任意地方的元素。

    4 html是xml 的子集 

    为了解析一个html文档,必须创建一个从HTMLParser继承而来的类,并实现必要的方法

    使用feed方法向解析器提供数据。可以每次提供一行数据,或者一次提供所有数据。

    from html.parser import HTMLParser
    class HeadingParser(HTMLParser):
    inHeading=False
    def handle_starttag(self,tag,attrs):#开始标签
    if tag=="h1":
    self.inHeading=True
    print("found a heading 1")
    def handle_data(self,data):#处理标签内容
    if self.inHeading:
    print(data)
    def handle_endtag(self,tag): #结束标签
    if tag=="h1":
    self.inHeading=False
    hParser=HeadingParser()
    file=open("headings.html","r")
    html=file.read()
    file.close()
    hParser.feed(html)

    5 在解析xml时,可以 选择两种不同类型的解析器:SAX和DOM

    SAX代表XML的简单API它是基于流的事件驱动的解析器。这些事件称作 文档事件,在元素开始之处、元素结尾处、遇到文本节点或者遇到一个注释时都有可能发生。

    当用SAX解析文档时,文档以期出现的顺序被读入和解析。解析器以数据流的方式打开该文件或者其他数据源如url,之后无论何时遇到任何元素都将引发事件。操作文档不够高效。对于文档转换,应该选择SAX,因为事件驱动的模型速度很快。

    DOM的核心在于文档对象,它是XML文档基于树的表示形式。树中的元素称作节点对象,节点拥有属性、子节点、文本 等,它们以对象的形式存储在树中。能在内存中存储整个文档,并且以树的形式操作和搜索其中的元素。文档大时预先处理时间长,处理后快。

    python中解析器:xml.sax 和xml.dom.minidom

    xml.dom.minidom 中parse方法解析文档树 返回一个Document对象。文本存储于节点的data属性

    parse()函数可以引用一个文件名称或一个打开的文件对象

    from xml.dom.minidom import parse, parseString
    
    dom1 = parse('c:\temp\mydata.xml')  # parse an XML file by name
    
    datasource = open('c:\temp\mydata.xml')
    dom2 = parse(datasource)  # parse an open file
    
    dom3 = parseString('<myxml>Some data<empty/> some more data</myxml>')
    

    appendChild方法可以创建节点的结构

    节点的方法 insertBefor(newChild,refChild)可以在节点的子节点列表中的任意位置插入新的子节点

    方法replaceChild(newChild,oldChild)可以将一个子节点替换为别一个子节点

    删除节点 首先需要得到要删除的节点的引用,随后再调用 removeChild(childNode)方法。删除后,调用unlink()方法强制对被删除的节点及它可能连接的子节点进行垃圾回收,xml.dom中不可用。

    xml.dom.minidom方法:toprettyxml,它接收两个可选参数:一个是缩进字符串,一个是换行符。如果没有指定参数值,这两个参数分别默认为tabulator 和 。该方法将DOM 打印为包含良好缩进的XML

    <?xml version="1.0"?>
    <lib:library
    xmlns:lib="http://server.domain.tld/NameSpaces/Library">
    <lib:book>
    <lib:title>Sandman volumn</lib:title>
    <lib:author>Neil Gaiman</lib:author>
    </lib:book>
    <lib:book>
    <lib:title>Good omens</lib:title>
    <lib:author>Neil Gamain</lib:author>
    <lib:author>Terry Pratchett</lib:author>
    </lib:book>
    <lib:book>
    <lib:title>"Repent,harlequin!" said the man</lib:title>
    <lib:author>Harlan Ellison</lib:author>
    </lib:book>
    </lib:library>

    以上的xml 保存在文件里去掉命名空间可以使用以下代码操作

    import os
    from xml.dom.minidom import parse
    import xml.dom.minidom
    def printLibrary(library):
    books=myLibrary.getElementsByTagName("book")
    for book in books:
    print("*******book******")
    print("Title:%s"%book.getElementsByTagName("title")[0].childNodes[0].data)
    for author in book.getElementsByTagName("author"):
    print("author:%s"%author.childNodes[0].data)
    # open an xml file and parse it into a dom
    myDoc=parse(r'E:pythonscriptch15library.xml')
    myLibrary=myDoc.getElementsByTagName("library")[0]
    #get all the book elements in the library
    books=myLibrary.getElementsByTagName("book")

    #Insert a new book in the library
    newBook=myDoc.createElement("book")
    newBookTitle=myDoc.createElement("title")
    titleText=myDoc.createTextNode("Beginning Python")
    newBookTitle.appendChild(titleText)
    newBook.appendChild(newBookTitle)
    newBookAuthor=myDoc.createElement("author")
    authorName=myDoc.createTextNode("Peter Norton,et al")
    newBookAuthor.appendChild(authorName)
    newBook.appendChild(newBookAuthor)
    myLibrary.appendChild(newBook)
    print("--------added a new book!")
    #printLibrary(myLibrary)
    #remove a book from the library
    #find ellison book
    for book in myLibrary.getElementsByTagName("book"):
    for author in book.getElementsByTagName("author"):
    if author.childNodes[0].data.find("Ellison")>=0:
    print(author.childNodes[0].data)
    removedBook=myLibrary.removeChild(book)
    removedBook.unlink()
    print("------------removed a book.")
    #printLibrary(myLibrary)
    print(myDoc.toprettyxml())
    #write back to the library file
    lib=open(r"E:pythonscriptch15library.xml","w")
    lib.write(myDoc.toprettyxml(" "))
    lib.close()# 这里是个方法,如果没有 这个方法 则不能写入数据,文件一直被占用

    使用sax 解析:

    #!/usr/bin/python
    from xml.sax import make_parser
    from xml.sax.handler import ContentHandler
    #begin bookHandler
    class bookHandler(ContentHandler):
    inAuthor=False
    inTitle=False
    def startElement(self,name,attributes):
    if name=="book":
    print("********book*********")
    if name=="title":
    self.inTitle=True
    print("Title:",)
    if name=="author":
    self.inAuthor=True
    print("Author:",)
    def endElement(self,name):
    if name=="title":
    self.inTitle=False
    if name=="author":
    self.inAuthor=False
    def characters(self,content):
    if self.inTitle or self.inAuthor:
    print(content)
    #end bookHandler
    parser=make_parser()
    parser.setContentHandler(bookHandler())
    parser.parse("library.xml")

    解析器xml.sax使用Handler对象解析文档过程中发生的事件。Handler可能是ContentHandler/DTDHandler /EntityResolver/ErrorHandler一个sax应用程序必须实现符合这些接口的处理程序类,并为解析器设置处理程序

    接口ContentHandler包含了被文件事件触发的方法,例如元素和字符数据的开始和结束等。在解析字符数据时,解析器可以选择将结果作为一整块数据返回,或者作为若干小的以空白分隔的数据块返回,所以在处理一块文本的过程中需要反复调用characters方法。

    make_parser方法创建一个新的解析器对象并将它返回。

    6 lxml 使用cmd.exe pip install lxml 安装lxml

    lxml是python利用libxml2 和libxslt库的快速、丰富特性的唯一绑定,并且它通过一个简单的api允许处理HTML /xml

    包lxml使用了略作修改的ElementTreeAPI 

    导入lxml:import lxml  

    from lxml import etree

    元素类:元素是ElementTreeAPI的主要容器对象,提供了xml树功能的核心,它们拥有属性并且包含文本.

    元素类遵守标准的xml树层次,因此既能支持父元素也能支持子元素。

    >>> import lxml
    >>> from lxml import etree

    >>> author=etree.Element("Horror") #创建新的元素类author,并赋予一个标签名称:Horror
    >>> print(author.tag)
    Horror

    >>> writer1=etree.SubElement(author,"NeilGaiman")# 一个元素的子元素 创建一个新的子元素 ,它的标签是NeilGaiman,父元素是author
    >>> writer2=etree.SubElement(author,"StephenKing")
    >>> writer3=etree.SubElement(author,"CliveBarker")
    >>> print(etree.tostring(author))
    b'<Horror><NeilGaiman/><StephenKing/><CliveBarker/></Horror>'
    >>> writer=author[0] #元素类也是列表,可以使用列表函数
    >>> print(writer.tag)
    NeilGaiman
    >>> for writer in author:
    print(writer.tag)


    NeilGaiman
    StephenKing
    CliveBarker

    元素可以包含属性,描述元素。

    >>> author=etree.Element("author",audience="Adult")
    >>> print(author.get("audience")) 
    Adult

    get()方法可以从元素中提取数据,set()方法设置属性或都添加属性

    >>> author.set("testpro","protect")

    >>> etree.tostring(author)
    b'<author audience="Adult" type="fiction" bestseller="Yes" testpro="protect"/>'

    还可以向元素中添加文本

    >>> html=etree.Element("html")
    >>> body=etree.SubElement(html,"body")
    >>> h1=etree.SubElement(body,"h1")
    >>> h1.text="Introduction"

    >>> paragraph=etree.SubElement(body,"p")
    >>> paragraph.text="here is some text representing our paragraph"

    >>> etree.tostring(html)
    b'<html><body><h1>Introduction</h1><p>here is some text representing our paragraph</p></body></html>'

    打印元素的文本:

    >>> etree.tostring(paragraph,method="text")
    b'here is some text representing our paragraph'

     lxml解析函数:

    fromstring()

    >>> sentence="<info>here is a sentence</info>"
    >>> info=etree.fromstring(sentence)
    >>> print(info.tag)
    info
    >>> print(info.text)
    here is a sentence

    XML()

    >>> info=etree.XML("<info>here is a sentence</info>")
    >>> print(info.tag)
    info

    >>> print(info.text)
    here is a sentence
    >>> etree.tostring(info)
    b'<info>here is a sentence</info>'

    >>> import io
    >>> newsentence=io.StringIO("<info>This is another sentence</info>")
    >>> somesentence=etree.parse(newsentence)
    >>> etree.tostring(somesentence)
    b'<info>This is another sentence</info>'

    >>> printit=somesentence.getroot()
    >>> print(printit.tag)
    info
    >>> print(printit.text)
    This is another sentence

    dom解析xml

    import xml.dom.minidom
    from xml.dom.minidom import parse
    dom1=parse(r'E:pythonscriptch15config.xml')
    myconfig=dom1.getElementsByTagName("config")[0]
    dire=myconfig.getElementsByTagName("utilitydirectory")[0]
    print(dire.childNodes[0].data)
    uti=myconfig.getElementsByTagName("utility")[0]
    print(uti.childNodes[0].data)
    mode1=myconfig.getElementsByTagName("mode")[0]
    print(mode1.childNodes[0].data)

    #!/usr/bin/python
    from xml.sax import make_parser
    from xml.sax.handler import ContentHandler

    class configHandler(ContentHandler):
    isUtilDir=False
    isUtil=False
    isMode=False
    def startElement(self,name,attributes):
    if name=="utilitydirectory":
    self.isUtilDir=True
    print("------------utility directory-----",)
    if name=="utility":
    self.isUtil=True
    print("--------------utility----------",)
    if name=="mode":
    self.isMode=True
    print("---------------mode--------------",)
    def endElement(self,name):
    if name=="utilitydirectory":
    isUtilDir=False
    if name=="utility":
    isUtil=False
    if name=="mode":
    isMode=False

    def characters(self,content):
    if self.isUtilDir or self.isUtil or self.isMode:
    print(content)

    parser=make_parser()
    parser.setContentHandler(configHandler())
    parser.parse(r"E:pythonscriptch15config.xml")

  • 相关阅读:
    C++11之function模板和bind函数适配器
    C++11之右值引用(三):使用C++11编写string类以及“异常安全”的=运算符
    C++11之右值引用(二):右值引用与移动语义
    C++11之右值引用(一):从左值右值到右值引用
    C++Singleton的DCLP(双重锁)实现以及性能测评
    信息熵
    ip访问网站和localhost访问网站中top使用
    方差与协方差
    js获取file控件的完整路径(上传图片预览)
    对线性回归,logistic回归和一般回归
  • 原文地址:https://www.cnblogs.com/caojuansh/p/11699594.html
Copyright © 2020-2023  润新知