加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

【原创】基于PyQt5的XML文件的保存和加载

(2017-01-15 10:24:29)
标签:

pyqt5

python

分类: PyQt5
本文基于PyQt对XML文件进行保存和加载,保存为xml依然使用QTextStream的方式,但解析XML文件则通过两种方式:DOM和SAX。两者的区别是前者适合编辑文档结构,后者采用递归工作方式,适用于XML文档的搜索和处理。
下例通过QTextStream将不同类型的数据保存为XML格式如下:
然后通过DOM和SAX方式讲内容解析出来。

from PyQt5.QtCore import QFile, QFileInfo, QIODevice,QTextStream
from PyQt5.QtXml import (QDomDocument, QDomNode, QXmlDefaultHandler,
                         QXmlInputSource, QXmlSimpleReader)


import datetime
CODEC = "UTF-8"

NEWPARA = chr(0x2029)
NEWLINE = chr(0x2028)
def encodedNewlines(text):
    return text.replace("\n\n", NEWPARA).replace("\n", NEWLINE)

def decodedNewlines(text):
    return text.replace(NEWPARA, "\n\n").replace(NEWLINE, "\n")

class Movie(object):
    UNKNOWNYEAR = 1890
    UNKNOWNMINUTES = 0
    def __init__(self, title=None, year=UNKNOWNYEAR,
                 minutes=UNKNOWNMINUTES, acquired=None, notes=None):
        self.title = title
        self.year = year
        self.minutes = minutes
        self.acquired = (acquired if acquired is not None
                                  else datetime.date.today())
        self.notes = notes
class MovieContainer(object):
   
    def __init__(self,fname,movies):
        self.__fname = fname
        self.__movies = movies       

    def exportXml(self, fname):
        error = None
        fh = None
        try:
            fh = QFile(fname)
            if not fh.open(QIODevice.WriteOnly):
                raise IOError(str(fh.errorString()))
            stream = QTextStream(fh)
            stream.setCodec(CODEC)
http://s9/mw690/003ytqMFzy781zHMDtmc8&690

            if movie.notes:
                stream << "\n" << encodedNewlines(movie.notes)
            stream << "\n\n\n"
            stream << "\n"
        except EnvironmentError as e:
            error = "Failed to export: {0}".format(e)
        finally:
            if fh is not None:
                fh.close()
            if error is not None:
                print(error)
            print("Exported 1 movie records to {0}".format(
                    QFileInfo(fname).fileName()))


    def importDOM(self, fname):
        dom = QDomDocument()
        error = None
        fh = None
        try:
            fh = QFile(fname)
            if not fh.open(QIODevice.ReadOnly):
                raise IOError(str(fh.errorString()))
            if not dom.setContent(fh):
                raise ValueError("could not parse XML")
        except (IOError, OSError, ValueError) as e:
            error = "Failed to import: {0}".format(e)
        finally:
            if fh is not None:
                fh.close()
            if error is not None:
                print(error)
        try:
            self.populateFromDOM(dom)
        except ValueError as e:
            print("Failed to import: {0}".format(e))
        self.__fname = ""
        print("Imported 1 movie records from {0}".format(
                    QFileInfo(fname).fileName()))


    def populateFromDOM(self, dom):
        root = dom.documentElement()
        if root.tagName() != "MOVIES":
            raise ValueError("not a Movies XML file")
        node = root.firstChild()
        while not node.isNull():
            if node.toElement().tagName() == "MOVIE":
                self.readMovieNode(node.toElement())
            node = node.nextSibling()


    def readMovieNode(self, element):
        def getText(node):
            child = node.firstChild()
            text = ""
            while not child.isNull():
                if child.nodeType() == QDomNode.TextNode:
                    text += child.toText().data()
                child = child.nextSibling()
            return text.strip()

        year = int(element.attribute("YEAR"))
        minutes = int(element.attribute("MINUTES"))
        ymd = element.attribute("ACQUIRED").split("-")
        if len(ymd) != 3:
            raise ValueError("invalid acquired date {0}".format(
                    str(element.attribute("ACQUIRED"))))
        acquired = datetime.date(int(ymd[0]), int(ymd[1]),
                                int(ymd[2]))
        title = notes = None
        node = element.firstChild()
        while title is None or notes is None:
            if node.isNull():
                raise ValueError("missing title or notes")
            if node.toElement().tagName() == "TITLE":
                title = getText(node)
            elif node.toElement().tagName() == "NOTES":
                notes = getText(node)
            node = node.nextSibling()
        if not title:
            raise ValueError("missing title")
        print(title, year, minutes, acquired,decodedNewlines(notes))


    def importSAX(self, fname):
       
        error = None
        fh = None
        try:
            handler = SaxMovieHandler(self)
            parser = QXmlSimpleReader()
            parser.setContentHandler(handler)
            parser.setErrorHandler(handler)
            fh = QFile(fname)
            input = QXmlInputSource(fh)
            if not parser.parse(input):
                raise ValueError(handler.error)
        except (IOError, OSError, ValueError) as e:
            error = "Failed to import: {0}".format(e)
        finally:
            if fh is not None:
                fh.close()
            if error is not None:
                print(error)
            self.__fname = ""
            print("Imported 1 movie records from {0}".format( QFileInfo(fname).fileName()))
  
class SaxMovieHandler(QXmlDefaultHandler):

    def __init__(self, movies):
        super(SaxMovieHandler, self).__init__()
        self.movies = movies
        self.text = ""
        self.error = None


    def clear(self):
        self.year = None
        self.minutes = None
        self.acquired = None
        self.title = None
        self.notes = None


    def startElement(self, namespaceURI, localName, qName, attributes):
        if qName == "MOVIE":
            self.clear()
            self.year = int(attributes.value("YEAR"))
            self.minutes = int(attributes.value("MINUTES"))
            ymd = attributes.value("ACQUIRED").split("-")
            if len(ymd) != 3:
                raise ValueError("invalid acquired date {0}".format(
                        str(attributes.value("ACQUIRED"))))
            self.acquired = datetime.date(int(ymd[0]),
                    int(ymd[1]), int(ymd[2]))
        elif qName in ("TITLE", "NOTES"):
            self.text = ""
        return True


    def characters(self, text):
        self.text += text
        return True


    def endElement(self, namespaceURI, localName, qName):
        if qName == "MOVIE":
            if (self.year is None or self.minutes is None or
                self.acquired is None or self.title is None or
                self.notes is None or not self.title):
                raise ValueError("incomplete movie record")
            print(self.title, self.year,
                    self.minutes, self.acquired,
                    decodedNewlines(self.notes))
           
        elif qName == "TITLE":
            self.title = self.text.strip()
        elif qName == "NOTES":
            self.notes = self.text.strip()
        return True


    def fatalError(self, exception):
        self.error = "parse error at line {0} column {1}: {2}".format(
                exception.lineNumber(), exception.columnNumber(),
                exception.message())
        return False





if __name__ == "__main__":
                        
    textdata=[["God save world",1989,45,None,"HELLO WORLD"]]
    fname="/home/yrd/work/movie.xml"
    for data in textdata:
        movie=Movie(data[0],data[1],data[2],data[3],data[4])
        moviecontainer=MovieContainer(fname, movie)
        moviecontainer.exportXml(fname)
        moviecontainer.importDOM(fname)
        moviecontainer.importSAX(fname)
   

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有