简体   繁体   English

如何将xml文件拖放到Qtableview中并同时解析xml

[英]How to drag a xml file and drop it in Qtableview and parse the xml at the same time

I am trying to drag an XML file in QtableView or QtableWidget and parse the file at the same time and display it in different columns in QtableView. 我试图在QtableView或QtableWidget中拖动XML文件并同时解析该文件,并将其显示在QtableView的不同列中。

I have gone through many examples but not sure where to begin with , are there any tutorial or example , I need this to be done in PyQt5. 我已经看过许多示例,但是不确定从哪里开始,是否有任何教程或示例,我需要在PyQt5中完成。

I am doing this for the first time and not sure , how to start this. 我是第一次这样做,不确定如何开始。

one very simple examples of XML file that i have is: each layer name is the first columns and then the subtags are the corresponding properties of the same. 我拥有的XML文件的一个非常简单的示例是:每个图层名称是第一列,然后子标记是相同的相应属性。

<xtech>
  <Layer id="0" name="EM_UPKG">
    <SourceLayer>NoSource</SourceLayer>
    <Color>
      <R>255</R>
      <G>255</G>
      <B>0</B>
    </Color>
    <Offset>
      <value>114.215</value>
      <dependent>EM_AlN</dependent>
      <placement>Top</placement>
    </Offset>
    <Thickness>
      <value>50</value>
      <dependent>-1</dependent>
    </Thickness>
    <Material>air</Material>
    <Port>NO</Port>
    <Resistivity>0</Resistivity>
    <Transparency>0.8</Transparency>
    <Sheet_Priority>0</Sheet_Priority>
  </Layer>
  <Layer id="1" name="EM_UP">
    <SourceLayer>NoSource</SourceLayer>
    <Color>
      <R>255</R>
      <G>128</G>
      <B>0</B>
    </Color>
    <Offset>
      <value>164.215</value>
      <dependent>EM_UVIA</dependent>
      <placement>Top</placement>
    </Offset>
    <Thickness>
      <value>40</value>
      <dependent>-1</dependent>
    </Thickness>
    <Material>copper</Material>
    <Port>NO</Port>
    <Resistivity>0</Resistivity>
    <Transparency>0</Transparency>
    <Sheet_Priority>0</Sheet_Priority>
  </Layer>
  <Layer id="2" name="EM_UVIA">
    <SourceLayer>NoSource</SourceLayer>
    <Color>
      <R>128</R>
      <G>128</G>
      <B>0</B>
    </Color>
    <Offset>
      <value>114.215</value>
      <dependent>EM_AlN</dependent>
      <placement>Top</placement>
    </Offset>
    <Thickness>
      <value>50</value>
      <dependent>-1</dependent>
    </Thickness>
    <Material>copper</Material>
    <Port>NO</Port>
    <Resistivity>0</Resistivity>
    <Transparency>0</Transparency>
    <Sheet_Priority>0</Sheet_Priority>
  </Layer>
  <Layer id="3" name="EM_PKG">
    <SourceLayer>NoSource</SourceLayer>
    <Color>
      <R>255</R>
      <G>255</G>
      <B>0</B>
    </Color>
    <Offset>
      <value>114.215</value>
      <dependent>EM_AlN</dependent>
      <placement>Top</placement>
    </Offset>
    <Thickness>
      <value>20</value>
      <dependent>-1</dependent>
    </Thickness>
    <Material>air</Material>
    <Port>NO</Port>
    <Resistivity>0</Resistivity>
    <Transparency>0.8</Transparency>
    <Sheet_Priority>0</Sheet_Priority>
  </Layer>
  <Layer id="4" name="EM_PL">
    <SourceLayer>NoSource</SourceLayer>
    <Color>
      <R>255</R>
      <G>128</G>
      <B>0</B>
    </Color>
    <Offset>
      <value>114.215</value>
      <dependent>EM_AlN</dependent>
      <placement>Top</placement>
    </Offset>
    <Thickness>
      <value>95</value>
      <dependent>-1</dependent>
    </Thickness>
    <Material>copper</Material>
    <Port>NO</Port>
    <Resistivity>0</Resistivity>
    <Transparency>0</Transparency>
    <Sheet_Priority>0</Sheet_Priority>
  </Layer>
  <Mesh_Operations>
    <Model_Resolution>60</Model_Resolution>
    <Surface_Approximation>0.5</Surface_Approximation>
  </Mesh_Operations>
  <Port_Processing>
    <Use_Delta>True</Use_Delta>
    <hport_delta>5</hport_delta>
  </Port_Processing>
</xtech>

columns should be displayed as: 列应显示为:

TargetLayer, Color, Offset, Thickness, MAterial, Port, Sheet Resistivity, Transparency, Priority and Source Layer TargetLayer,颜色,偏移,厚度,材料,端口,薄层电阻率,透明度,优先级和源图层

So i wrote the code below to implement drag and drop , now i have to look into how to parse the XML file. 因此,我在下面编写了实现拖放的代码,现在我必须研究如何解析XML文件。

    def __init__(self,parent=None):
    super().__init__()
    self.ui = Ui_MainWindowEtechEditor()
    self.ui.setupUi(self)
    self.setAcceptDrops(True)

    self.ui.pushButton.clicked.connect(self.opecolorEditor)

def opecolorEditor(self):
    color = QColorDialog(self)
    color.setSizeGripEnabled(True)
    color.layout().setSizeConstraint(QLayout.SetNoConstraint)
    color.show()


def dragEnterEvent(self, e):
    if e.mimeData().hasUrls:
        e.accept()
    else:
        e.ignore()

def dragMoveEvent(self, e):
    if e.mimeData().hasUrls:
        e.accept()
    else:
        e.ignore()

def dropEvent(self, e, event=None):
    if e.mimeData().hasUrls():
        e.setDropAction(QtCore.Qt.CopyAction)
        e.accept()

        drop_list = []
        for url in e.mimeData().urls():
            fName = (str(url.toLocalFile()))
            print("path ", fName)

        self.loadExtechfile(fName)

    else:
        e.ignore()

Qt provides QXmlStreamReader , an Xml parser. Qt提供了XXml解析器QXmlStreamReader
The parser reads one element at a time, keeping the current element type and contents, so the only problem is to understand how to keep track of nested elements, as long as the source is well formed. 解析器一次读取一个元素,并保留当前元素的类型和内容,因此唯一的问题是,只要源格式正确,就应该了解如何跟踪嵌套元素。

readNext() returns the element type ("token") of the xml element (which is accessible through tokenType() also). readNext()返回xml元素的元素类型(“令牌”)(也可以通过tokenType()访问)。
The most important token types are StartElement and EndElement , you can use QXmlStreamReader.attributes().value(attrName) to read the attributes of a StartElement, and xml.readElementText() for its contents, which might be its text contents or even the raw text of child elements as long as QXmlStreamReader.IncludeChildElements is provided as last argument. 最重要的标记类型是StartElementEndElement ,您可以使用QXmlStreamReader.attributes().value(attrName)读取StartElement的属性,并使用xml.readElementText()获取其内容,该内容可能是其文本内容,甚至可能是只要最后一个参数提供QXmlStreamReader.IncludeChildElements ,子元素的原始文本。

Columns = ('Target Layer', 'Color', 'Offset', 'Thickness', 'Material', 
    'Port', 'Resistivity', 'Transparency', 'Sheet_Priority', 'SourceLayer')
SimpleFields = ('SourceLayer', 'Material', 'Resistivity', 'Port', 
    'Transparency', 'Sheet_Priority')

class Table(QtWidgets.QTableView):
    def __init__(self, *args, **kwargs):
        QtWidgets.QTableView.__init__(self, *args, **kwargs)
        self.setAcceptDrops(True)
        model = QtGui.QStandardItemModel(0, len(Columns))
        model.setHorizontalHeaderLabels(Columns)
        self.setModel(model)

    def dragEnterEvent(self, e):
        # be careful, as you forgot the parenthesis of hasUrls()!
        if e.mimeData().hasUrls() and any(u.isLocalFile() for u in e.mimeData().urls()):
            e.accept()
        else:
            e.ignore()

# ...

    def dropEvent(self, e):
        f = QtCore.QFile(e.mimeData().urls()[0].toLocalFile())
        if not f.open(f.ReadOnly):
            return
        xml = QtCore.QXmlStreamReader(f)
        valid = False
        currentLayer = None
        while not xml.atEnd():
            if xml.readNext() == xml.StartElement:
                # track the first start element and ensure that it's of
                # the right type, otherwise ignore the file
                if not valid:
                    if xml.name() != 'xtech':
                        break
                    valid = True
                    continue
                if xml.name() == 'Layer':
                    # if a currentLayer exists, we assume it's finished,
                    # so we can process it and add its items
                    if currentLayer:
                        self.addLayer(currentLayer)
                    currentLayer = {'Target Layer': xml.attributes().value('name')}
                elif xml.name() in SimpleFields:
                    currentLayer[xml.name()] = xml.readElementText()
                elif xml.name() == 'Color':
                    currentLayer['Color'] = color = QtGui.QColor()
                    # this is a "nested" field, read its contents until
                    # it's reached the end element;
                    while xml.readNext():
                        if xml.tokenType() == xml.EndElement and xml.name() == 'Color':
                            break
                        elif xml.name() == 'R':
                            color.setRed(int(xml.readElementText()))
                        elif xml.name() == 'G':
                            color.setGreen(int(xml.readElementText()))
                        elif xml.name() == 'B':
                            color.setBlue(int(xml.readElementText()))
                # use the same logic for all other nested fields.
        f.close()

    def addLayer(self, layer):
        # create an empty "row" that can be filled with items in the correct
        # order, and that will leave empty cells if some fields do not exist
        row = [None] * len(Columns)
        for field, value in layer.items():
            item = QtGui.QStandardItem()
            if isinstance(value, QtGui.QColor):
                item.setBackground(value)
            else:
                item.setData(value, QtCore.Qt.DisplayRole)
            row[Columns.index(field)] = item
        self.model().appendRow(row)

Some care is necessary about letter cases when parsing elements, you should probably use xml.name().lower() for comparisons against field names. 解析元素时,对于字母大小写需要xml.name().lower() ,您可能应该使用xml.name().lower()与字段名称进行比较。

After struglling for few hours i found another parser xml.etree.ElementTree and implemented the parser code like below which works like a charm. 挣扎了几个小时后,我找到了另一个解析器xml.etree.ElementTree并实现了如下的解析器代码,它的工作原理像一个魅力。

    def loadExtechfile(self,fName):
    print("load file from  ", fName)
    tree = ET.parse(fName)
    root = tree.getroot()

    for layer in root.findall('Layer'):
        layerName =layer.get('name')
        sourceLayer = layer.find('SourceLayer').text

        for color in layer.findall('Color'):
            r = color.find('R').text
            g = color.find('G').text
            b = color.find('B').text

        combinedRGB = r+","+g+","+b

        for offset in layer.findall('Offset'):
            value = offset.find('value').text
            dep = offset.find('dependent').text
            plc = offset.find('placement').text

        if dep == "-1" and plc == "None":
            combinedOffset = value
        else:
            combinedOffset = value + "(= " + dep + " [" + plc + "])"

        for thickness in layer.findall('Thickness'):
            valueT = thickness.find('value').text
            depT = thickness.find('dependent').text

        if depT != "-1":
            combinedThickness = valueT + "(=" + depT + ")"
        else:
            combinedThickness = valueT
        material = layer.find('Material').text
        port = layer.find('Port').text
        res = layer.find('Resistivity').text
        trans = layer.find('Transparency').text
        sheetPrio = layer.find('Sheet_Priority').text
        #print(layerName,r,g,b,sourceLayer,material,port,res,trans,sheetPrio)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM