专业的JAVA编程教程与资源

网站首页 > java教程 正文

实战PyQt5: 127-处理XML文档(xml是什么文件格式)

temp10 2024-11-10 11:33:47 java教程 9 ℃ 0 评论

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

QDomDocment简介

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

实战PyQt5: 127-处理XML文档(xml是什么文件格式)

解析后的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进行文件操作


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

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表