百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

实战PyQt5: 127-处理XML文档

xsobi 2024-11-24 23:34 1 浏览

XML文档的简单和易扩展属性使其可以很方便地在任何程序中读/写数据。 比如在QT开发中,其常见的ui,qrc 后缀的文件都是一种XML格式的文档。QT提供类 QDomDocument来处理XML文档。

QDomDocment简介

QDomDOcument类代表整个XML文档。从概念上讲,它是文档树的根,并提供对文档的访问。由于元素(elment), 文本节点(text node), 注释(comment),处理指令(processing instruction)等都包含在XML文档内,因此QDomDocument类中也包含了创建这里对象的函数。QDomDocument创建的节点对象都具有ownerDocument()函数,该函数将它们与其上下文(context)中创建的文档相关联。

解析后的XML文档在内部由对象数来表示,可以使用各种QDom类访问这些对象。所有的QDom类仅引用内部树中的对象。一旦引用它们的最后一个QDom对象或者QDomDocument本身被删除时,DOM树中的内部对象将被删除。

注意:如果XML文档很大时,则Dom数可能会占用大量内存,在这种情况下,建议使用QXmlStreamreader或QXmlQuery类来处理这类XML文档。

使用QDom类通常按如下方式使用:

doc = QDomDocument('mydoc')
file = QFile('mydoc.xml')
if not file.open(QIOdevice.Readonly):
         return
if not doc.setContent(file):
         file.close()
         return
file.close()
 
#打印最外层元素的直接联系的子元素的所有元素的名称
docElem = doc.documentElement()
node = docElem.firstChild()
while not node.isNull():
         elem = node.toElement()  #尝试将节点转换成元素
         if no elem.isNull():
                   print(elem.tagName()
         node = node.nextSibling()
 
#在文档的末尾添加一个新元素
elem = doc.createElement('img')
elem.setAttribute('src', 'myimage.png')
docElem.appendChild(elem)

下面的代码使用DOM创建XML文档:

doc = QDomDocument('myXML')
root = doc.createElement('myXML')
doc.appendChild(root)
 
tag = doc.createElement('Greeting')
root.appendChild(tag)
 
txt = doc.createTextNode('Hello World')
tag.appendChild(txt)
 
xml = doc.toString()

QDocument常用函数:

  • toString(self): 将已解析的文档转回其文本表示方式。
  • setContent(self, ...): 将指定的文本设置为XML文档内容,函数会尝试检测XML规范要求的文档编码。
  • nodeType(self): 返回DocumentNode。
  • documentElement(self): 返回文档的根元素。
  • elementById(self, elementId): 返回其ID等于elementId的元素。如果未找到具有ID的元素,则此函数返回None。
  • elementsByTagName(self, tagname): 返回一个QDomNodeList,其中包含名称为tagname的文档中的所有元素。节点列表的顺序是在元素树的预遍历中遇到它们的顺序。
  • createElement(self, tagname): 创建一个名为tagname的新元素,可以将其插入DOM树。
  • createTextNode(self, value): 为可插入文档树的字符串value创建文本节点。
  • createComment(self, value): 为插入文档中的字符串value创建新注释。
  • createAttribute(self, name): 创建一个名为name的新属性,可以将其插入元素属性中。

QDOM的一些常用类

除了QDomDocument以外,还有一些经常使用的DOM类:

  • QDomNode: DOM树中所有节点的基类。
  • QDomElement: 表示DOM树中的一个元素。
  • QDomText: 表示已解析的XML文档中的文本数据。
  • QXmlStreamReader: 提供了一个快速解析器,用于通过简单的流API读取格式正确的XML。
  • QXmlQuery: 编译并执行以XQuery语言编写的查询。QXmlQuery通常用于查询XML数据,但它也可以查询已建模为XML的非XML数据。

测试

使用QTreeView按树的方式来显示QDomDocument解析的XML文件,完整代码如下:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QFile, QIODevice, QModelIndex, QAbstractItemModel
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction,
                             QFileDialog, QTreeView)
from PyQt5.QtXml import QDomDocument
 
class DomItem(object):
    def __init__(self, node, row, parent=None):
        self.domNode = node
        #记录条目在其父条目中的位置
        self.rowNumber = row
        self.parentItem = parent
        self.childItems = {}
        
    def node(self):
        return self.domNode
    
    def parent(self):
        return self.parentItem
    
    def child(self, i):
        if i in self.childItems:
            return self.childItems[i]
        
        if i >= 0 and i < self.domNode.childNodes().count():
            childNode = self.domNode.childNodes().item(i)
            childItem = DomItem(childNode, i, self)
            self.childItems[i] = childItem
            return childItem
        
        return None
    
    def row(self):
        return self.rowNumber
    
class DomModel(QAbstractItemModel):
    def __init__(self, doucment, parent=None):
        super(DomModel, self).__init__(parent)
        self.domDocument = doucment
        self.rootItem = DomItem(self.domDocument, 0)
        
    #列数
    def columnCount(self, parent):
        return 3
    
    #设置数据
    def data(self, index, role):
        if not index.isValid():
            return None
        
        if role != Qt.DisplayRole:
            return None
        
        item = index.internalPointer()
        
        node = item.node()
        attributes = []
        attributeMap = node.attributes()
        
        if index.column() == 0:
            return node.nodeName()
        
        elif index.column() == 1:
            for i in range(0, attributeMap.count()):
                attribute = attributeMap.item(i)
                attributes.append(attribute.nodeName() + '="' +  attribute.nodeValue() + '"')
            return ' '.join(attributes)
        
        elif index.column() == 2:
            value = node.nodeValue()
            if value is None:
                return ''
            
            return ' '.join(node.nodeValue().split('\n'))
        
        return None
    
    def flags(self, index):
        if not index.isValid():
            return Qt.NoItemFlags
        
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable
    
    #设置表头各部分的标题信息
    def headerData(self, section, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            if section == 0:
                return '名字'
            
            if section == 1:
                return '属性'
            
            if section == 2:
                return '值'
            
        return None
    
    #索引
    def index(self, row, column, parent):
        if not self.hasIndex(row, column, parent):
            return QModelIndex()
        
        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()
            
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QModelIndex()
    
    #父项   
    def parent(self, child):
        if not child.isValid():
            return QModelIndex()
        
        childItem = child.internalPointer()
        parentItem = childItem.parent()
        
        if not parentItem or parentItem == self.rootItem:
            return QModelIndex()
        
        return self.createIndex(parentItem.row(), 0, parentItem)
    
    #行数
    def rowCount(self, parent):
        if parent.column() > 0:
            return 0
        
        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()
            
        return parentItem.node().childNodes().count()
 
class DemoDomDocument(QMainWindow):
    def __init__(self, parent=None):
        super(DemoDomDocument, self).__init__(parent)   
        
         # 设置窗口标题
        self.setWindowTitle('实战Qt for Python: XML文档处理演示')      
        # 设置窗口大小
        self.resize(480, 360)
      
        self.initUi()
        
    def initUi(self):
        self.initMenuBar()
         
        self.xmlPath = ''
        self.model = DomModel(QDomDocument(), self)
        self.view = QTreeView(self)
        self.view.setModel(self.model)
        
        self.setCentralWidget(self.view)

    def initMenuBar(self):
        menuBar = self.menuBar() 
        menuFile = menuBar.addMenu('文件(&F)')
        
        menuFile.addAction('打开文件(&F)...', self.openFile, 'Ctrl+O')
        menuFile.addAction('退出(&X)',  QApplication.instance().quit, 'Ctrl+Q')
    
    def openFile(self):
        path,_ = QFileDialog.getOpenFileName(self, 'OpenFile', self.xmlPath,
                                             'XML files (*.xml);;HTML files (*.html);;'
                                             'SVG files (*.svg);;User Interface files (*.ui)')
        if path:
            f = QFile(path)
            if f.open(QIODevice.ReadOnly):
                document = QDomDocument()
                if document.setContent(f):
                    newModel = DomModel(document, self)
                    self.view.setModel(newModel)
                    self.model = newModel
                    self.xmlPath = path
                    
            f.close()
        
          
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = DemoDomDocument()
    window.show()
    sys.exit(app.exec())   

运行结果如下图:

本文知识点

  • QDomDocument代表整个XML文档。
  • 使用QDomDocument解析XML文档。
  • 使用QTreeView显示XML。

前一篇: 实战PyQt5: 126-使用QFile进行文件操作


请多多关注,评论,收藏,点赞,和转发。

相关推荐

js向对象中添加元素(对象,数组) js对象里面添加元素

一、添加一个元素对象名["属性名"]=值(值:可以是一个值,可以是一个对象,也可以是一个数组)这样添加进去的元素,就是一个值或对象或数组...

JS小技巧,如何去重对象数组?(一)

大家好,关于数组对象去重的业务场景,想必大家都遇到过类似的需求吧,这对这样的需求你是怎么做的呢。下面我就先和大家分享下如果是基于对象的1个属性是怎么去重实现的。方法一:使用.filter()和....

「C/C++」之数组、vector对象和array对象的比较

数组学习过C语言的,对数组应该都不会陌生,于是这里就不再对数组进行展开介绍。模板类vector模板类vector类似于string,也是一种动态数组。能够在运行阶段设置vector对象的长度,可以在末...

如何用sessionStorage保存对象和数组

背景:在工作中,我将[{},{}]对象数组形式,存储到sessionStorage,然后ta变成了我看不懂的形式,然后我想取之用之,发现不可能了~记录这次深刻的教训。$clickCouponIndex...

JavaScript Array 对象 javascript的array对象

Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...

JavaScript中的数组Array(对象) js array数组

1:数组Array:-数组也是一个对象-数组也是用来存储数据的-和object不同,数组中可以存储一组有序的数据,-数组中存储的数据我们称其为元素(element)-数组中的每一个元素都有一...

数组和对象方法&amp;数组去重 数组去重的5种方法前端

列举一下JavaScript数组和对象有哪些原生方法?数组:arr.concat(arr1,arr2,arrn);--合并两个或多个数组。此方法不会修改原有数组,而是返回一个新数组...

C++ 类如何定义对象数组?初始化数组?linux C++第43讲

对象数组学过C语言的读者对数组的概念应该很熟悉了。数组的元素可以是int类型的变量,例如int...

ElasticSearch第六篇:复合数据类型-数组,对象

在ElasticSearch中,使用JSON结构来存储数据,一个Key/Value对是JSON的一个字段,而Value可以是基础数据类型,也可以是数组,文档(也叫对象),或文档数组,因此,每个JSON...

第58条:区分数组对象和类数组对象

示例设想有两个不同类的API。第一个是位向量:有序的位集合varbits=newBitVector;bits.enable(4);bits.enable([1,3,8,17]);b...

八皇后问题解法(Common Lisp实现)

如何才能在一张国际象棋的棋盘上摆上八个皇后而不致使她们互相威胁呢?这个著名的问题可以方便地通过一种树搜索方法来解决。首先,我们需要写一个函数来判断棋盘上的两个皇后是否互相威协。在国际象棋中,皇后可以沿...

visual lisp修改颜色的模板函数 怎么更改visual studio的配色

(defunBF-yansemokuai(tuyuanyanse/ss)...

用中望CAD加载LISP程序技巧 中望cad2015怎么加载燕秀

1、首先请加载lisp程序,加载方法如下:在菜单栏选择工具——加载应用程序——添加,选择lisp程序然后加载,然后选择添加到启动组。2、然后是添加自定义栏以及图标,方法如下(以...

图的深度优先搜索和广度优先搜索(Common Lisp实现)

为了便于描述,本文中的图指的是下图所示的无向图。搜索指:搜索从S到F的一条路径。若存在,则以表的形式返回路径;若不存在,则返回nil。...

两个有助于理解Common Lisp宏的例子

在Lisp中,函数和数据具有相同的形式。这是Lisp语言的一个重大特色。一个Lisp函数可以分析另一个Lisp函数;甚至可以和另一个Lisp函数组成一个整体,并加以利用。Lisp的宏,是实现上述特色的...