Невозможно разделить xml элементов одного узла QDomDocument () и добавить элементы в модель DOM с помощью pyqt5 - PullRequest
0 голосов
/ 21 января 2020

У меня есть этот код, который работает до сих пор, чтобы иметь прямое древовидное представление файла xml:

from PyQt5.QtCore import QAbstractItemModel, QFile, QIODevice, QModelIndex, Qt
from PyQt5.QtWidgets import QApplication, QFileDialog, QMainWindow, QTreeView
from PyQt5.QtXml import QDomDocument, QDomElement


class DomItem(object):
    def __init__(self, node, row, parent=None):
        self.domNode = node
        # Record the item's location within its parent.
        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 0 <= 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, document, parent=None):
        super(DomModel, self).__init__(parent)

        self.domDocument = document

        self.rootItem = DomItem(self.domDocument, 0)

    def columnCount(self, parent):
    # return 3
        return 2

    def data(self, index, role):
        if not index.isValid():
            return None

        if role != Qt.DisplayRole:
            return None

        item = index.internalPointer()

        node = item.node()

        if index.column() == 0:
            # print(node.nodeName())
            if node.nodeName() != '#text':
                return node.nodeName()
            else:
                return None

        if index.column() == 1:
            value = node.nodeValue()
            if value is None:
                 return ''

            else:
                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 "Category"

            if section == 1:
                return "Name"

        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 MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

    self.fileMenu = self.menuBar().addMenu("&File")
    self.fileMenu.addAction("&Open...", self.openFile, "Ctrl+O")
    self.fileMenu.addAction("E&xit", self.close, "Ctrl+Q")

    self.xmlPath = ""
    self.model = DomModel(QDomDocument(), self)
    self.view = QTreeView(self)
    self.view.setModel(self.model)

    self.setCentralWidget(self.view)
    self.setWindowTitle("Simple DOM Model")

    def openFile(self, filePath):
        if filePath:
            f = QFile(filePath)
            if f.open(QIODevice.ReadOnly):
                document = QDomDocument()
                if document.setContent(f):
                    newModel = DomModel(document, self)
                    self.view.setModel(newModel)
                    self.view.expandAll()
                    self.model = newModel
                    self.xmlPath = filePath

                f.close()


if __name__ == '__main__':
    import sys

     app = QApplication(sys.argv)
     window = MainWindow()
     window.resize(640, 480)
     window.show()
     window.openFile('your file full path')
     sys.exit(app.exec_())

Файл xml:

<repoCoordinates>
  <name>repostructuretrials</name>
  <branches>master</branches>
  <submodules>
    <submodule_0>
      <name>gameengine</name>
      <branches>*master,remotes/origin/develop,remotes/origin/feature/NormalMappingAndTextureCombination,remotes/origin/feature/light,remotes/origin/feature/particleEmitter,remotes/origin/master</branches>
    </submodule_0>
    <submodule_1>
      <name>GraphicEngineOpenGLBasics</name>
      <branches>feature/shadows,*master,remotes/origin/develop,remotes/origin/feature/billboards,remotes/origin/feature/shadows,remotes/origin/master</branches>
    </submodule_1>
  </submodules>
</repoCoordinates>

И я получаю это: enter image description here

Код большой, но не очень сложный. Моя проблема в том, что я хочу, чтобы каждое имя ветви было отдельным элементом в древовидной модели, и все значения, разделенные запятыми, являются единственным уникальным элементом для модели. Я попытался проанализировать xml и поиграть с классом QDomElement(), пытаясь добавить дочерние элементы к моим узлам, чтобы иметь возможность выбирать каждую из ветвей отдельно.

Я хотел бы разделить все имена ветвей на "," и добавить эти узлы в мой DOM.

Любая помощь по этому вопросу будет мне очень признательна, а также любые советы по справиться с этим, если класс QDomDocument не лучший способ.

Большое спасибо

1 Ответ

1 голос
/ 21 января 2020

Это очень простая c попытка, с помощью которой может достичь того, что вы ищете.

Что он делает, это создает дочерних элементов, когда узел обнаруживает, что его имя является "ветвями" ", так что модель элемента может видеть их как фактические дочерние узлы. Дети создаются вручную путем написания собственного индекса на родительском childItems dict, чтобы модель могла перемещаться между родителями.

Имейте в виду, что этот подход далек от совершенства: например, модель и относительный DOM не защищен от записи (у меня нет такого опыта работы с модулем Qt Xml).

class DomItem(object):
    # ...
    def child(self, i):
        if i in self.childItems:
            return self.childItems[i]

        if 0 <= i < self.domNode.childNodes().count():
            childNode = self.domNode.childNodes().item(i)
            childItem = DomItem(childNode, i, self)
            self.childItems[i] = childItem
            if childNode.nodeName() == 'branches':
                # based on your example xml there should be only one child entry
                # for each "branches" node, but, just in case, let's cycle amongst
                # every possible child node
                subChildNodes = childNode.childNodes()
                childIndex = 0
                for c in range(subChildNodes.count()):
                    subChild = subChildNodes.at(c)
                    for tag in subChild.nodeValue().split(','):
                        branch = childNode.ownerDocument().createElement(tag)
                        childNode.appendChild(branch)
                        branchItem = DomItem(branch, childIndex, childItem)
                        childItem.childItems[childIndex] = branchItem
                        childIndex += 1
            return childItem

        return None
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...