将 QXmlStreamReader 实例传递给类

Posted

技术标签:

【中文标题】将 QXmlStreamReader 实例传递给类【英文标题】:Pass QXmlStreamReader Instance to Class 【发布时间】:2014-07-16 23:19:34 【问题描述】:

我正在尝试使用 QXmlStreamReader 读取 XML 文档。当我尝试将指向读者的指针传递给其他类时,我遇到了问题。我在一个类中创建了一个阅读器实例。该类读取 XML,直到遇到定义新类的块。我创建了新类的实例,然后调用该类中的一个函数来继续读取特定于它的 XML。例如:

void SF_UnitClass::ReadModes()

    Q_ASSERT(XML.isStartElement() && XML.name() == MODES);
    NumModes = XML.attributes().value(COUNT).toInt();            
    while (XML.readNextStartElement())                                          
    
        if (XML.name() == MODE)                                            
                                                                              
            ModeClass* pMode = new ModeClass(this);                          
            ModeList += XML.attributes().value(ID).toString();                
            pMode->ReadXML(&XML);                                              
                                                                              
            
        
        else                                                                    
        
            XML.raiseError(QObject::tr("Something other than Mode block encountered in Modes block"));
        
    


void ModeClass::ReadXML(QXmlStreamReader* pXML)                                 
                                                                               
    Q_ASSERT(pXML->isStartElement() && pXML->name() == MODE);                   
    while (pXML->readNextStartElement())                                        
                                                                               
        int nameIndex = ModeList.indexOf(pXML->name().toString());            
        if(nameIndex != -1)                                                     
                                                                               
            switch(nameIndex)                                                   
                                                                               
                case 0:                                                         
                                                                               
    qDebug() << "Mode: Receivers";                                              
                    NumReceivers = pXML->readElementText().toInt();             
                    break;                                                      
                                                                               
                case 1:                                                         
                                                                               
    qDebug() << "Mode: Channels";                                               
                    ReadChannels(pXML);                                         
                    break;                                                      
                                                                               
                case 2:                                                         
                                                                               
    qDebug() << "Mode: Servos";                                                 
                    ReadServos(pXML);                                           
                    break;                                                      
                                                                               
                                                                               
                                                                               
        else                                                                    
                                                                               
    qDebug() << "Mode: Error " << name;                                         
            pXML->raiseError(QObject::tr("Unrecognized keyword for Mode"));     
                                                                               
                                                                               
                                                                               

void ModeClass::ReadChannels(QXmlStreamReader* pXML)                            
                                                                               
    Q_ASSERT(pXML->isStartElement() && pXML->name() == CHANNELS);               
    NumChannels = pXML->attributes().value(COUNT).toInt();                      
    while (pXML->readNextStartElement())                                        
                                                                               
        if (pXML->name() == CHANNEL)                                            
                                                                               
    qDebug() << "Mode: Read Channel";                                           
            ChannelClass* pChannel = new ChannelClass(this);                    
            pChannel->ReadXML(pXML);                                            
                                                                               
        else                                                                    
                                                                               
            pXML->raiseError(QObject::tr("Something other than Channel block enc
                                                                               
                                                                               
                                                                               

void ModeClass::ReadServos(QXmlStreamReader* pXML)                              
                                                                               
    Q_ASSERT(pXML->isStartElement() && pXML->name() == SERVOS);                 
    NumServos = pXML->attributes().value(COUNT).toInt();                        
    while (pXML->readNextStartElement())                                        
                                                                               
        if (pXML->name() == SERVO)                                              
                                                                               
    qDebug() << "Mode: Read Servo";                                             
            ServoClass* pServo = new ServoClass(this);                          
            pServo->ReadXML(pXML);                                              
                                                                               
        else                                                                    
                                                                               
    qDebug() << "Servos: raiseError";                                           
            pXML->raiseError(QObject::tr("Something other than Servo block encou
                                                                               
                                                                               
    qDebug() << "Mode: Read Servos Exit";                                       
                                                                               

void ChannelClass::ReadXML(QXmlStreamReader* pXML)                              
                                                                               
    Q_ASSERT(pXML->isStartElement() && pXML->name() == CHANNEL);                
    ChannelNumber = pXML->attributes().value(ID).toInt();                       
    while (pXML->readNextStartElement())                                        
                                                                               
        int nameIndex = ChannelList.indexOf(pXML->name().toString());           
        if(nameIndex != -1)                                                     
                                                                               
            switch(nameIndex)                                                   
                                                                               
                case 0:                                                         
                                                                               
                    UserName = pXML->readElementText();                         
                    break;                                                      
                                                                               
                case 1:                                                         
                                                                               
                    EndPointHold = String2Bool(pXML->readElementText());        
                    break;                                                      
                                                                               
                case 2:                                                         
                                                                               
                    ServoPriority = String2Bool(pXML->readElementText());       
                    break;                                                      
                                                                               
                                                                               
                                                                               
        else                                                                    
                                                                               
            pXML->raiseError(QObject::tr("Unrecognized keyword for Channel"));  
                                                                               
                                                                               
                                                                               

void ServoClass::ReadXML(QXmlStreamReader* pXML)                                
                                                                               
    Q_ASSERT(pXML->isStartElement() && pXML->name() == SERVO);                  
    ServoNumber = pXML->attributes().value(ID).toInt();                         
    while (pXML->readNextStartElement())                                        
                                                                               
        int nameIndex = ServoList.indexOf(pXML->name().toString());             
    qDebug() << "Servo: NameIndex: " << nameIndex;                              

        if(nameIndex != -1)                                                     
                                                                               
            switch(nameIndex)                                                   
                                                                               
                case 0:                                                         
                                                                               
                    Offset = pXML->readElementText().toInt();                   
                    break;                                                      
                                                                               
                case 1:                                                         
                                                                               
                    PosFactor = pXML->readElementText().toInt();                
                    break;                                                      
                                                                               
                case 2:                                                         
                                                                               
                    NegFactor = pXML->readElementText().toInt();                
                    break;                                                      
                                                                               
                case 3:                                                         
                                                                               
                    SecServo = pXML->readElementText().toInt();                 
                    break;                                                      
                                                                               
                case 4:                                                         
                                                                               
                    Unit = pXML->readElementText().toInt();                     
                    break;                                                      
                                                                               
                case 5:                                                         
                                                                               
                    Ser1 = pXML->readElementText().toInt();                     
                    break;                                                      
                                                                               
                case 6:                                                         
                                                                               
                    Ser2 = pXML->readElementText().toInt();                     
                    break;                                                      
                                                                               
                case 7:                                                         
                                                                               
                    Ser3 = pXML->readElementText().toInt();                     
                    break;                                                      
                                                                               
                                                                               
                                                                               
        else                                                                    
                                                                               
    qDebug() << "Servo: raiseError";                                            
            pXML->raiseError(QObject::tr("Unrecognized keyword for Servo block")
                                                                               
                                                                               
    qDebug() << "Servo: Exit ";                                                 
                                                                               

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<SmartFlyUnit version="1.0">
    <UnitName>PowerExpander Eq10E</UnitName>
    <UnitCode>PE-5</UnitCode>
    <UnitID>1</UnitID>
    <MinRev>1.0</MinRev>
    <MaxRev>1.9</MaxRev>
    <Servos>36</Servos>
    <Outputs>32</Outputs>
    <UnitMode>Chan</UnitMode>
    <Modes Count="2">
        <Mode ID="Chan">
            <Receivers>1</Receivers>
            <Channels Count="10">
                <Channel ID="0">
                    <UserName></UserName>
                    <EndPtHold>Off</EndPtHold>
                    <ServoPri>Off</ServoPri>
                </Channel>
                <Channel ID="1">
                    <UserName></UserName>
                    <EndPtHold>Off</EndPtHold>
                    <ServoPri>Off</ServoPri>
                </Channel>
            </Channels>
            <Servos Count="36">
                <Servo ID="0">
                    <Offset>0</Offset>
                    <PosFact>1.0000</PosFact>
                    <NegFact>1.0000</NegFact>
                    <Reverse>Off</Reverse>
                    <SecServo>0xFF</SecServo>
                    <Unit>0xFF</Unit>
                    <Ser1>0xFF</Ser1>
                    <Ser2>0xFF</Ser2>
                    <Ser3>0xFF</Ser3>
                </Servo>
                <Servo ID="1">
                    <Offset>0</Offset>
                    <PosFact>1.0000</PosFact>
                    <NegFact>1.0000</NegFact>
                    <Reverse>Off</Reverse>
                    <SecServo>0xFF</SecServo>
                    <Unit>0xFF</Unit>
                    <Ser1>0xFF</Ser1>
                    <Ser2>0xFF</Ser2>
                    <Ser3>0xFF</Ser3>
                </Servo>
            </Servos>
        </Mode>
    </Modes>
    <MCUs Count="1">
        <MCU ID="0">
            <FileName>/PE-5/PE-5_M0_1_00.sffw</FileName>
        </MCU>
    </MCUs>
    <FPGAs Count="1">
        <FPGA ID="0">
            <Configs Count="2">
                <Config ID="0">
                    <FileName>/PE-5/PE-5_F0C0_1_00.sffw</FileName>
                </Config>
                <Config ID="1">
                    <FileName>/PE-5/PE-5_F0C1_1_00.sffw</FileName>
                </Config>
            </Configs>
        </FPGA>
    </FPGAs>
</SmartFlyUnit>

我添加了 ModeClass 用来识别通道和伺服模块的代码。我还添加了 ChannelClass 和 ServoClass 的代码。最后,我添加了我的 XML 文件的编辑版本,但足以显示问题。这个 XML 可以很好地读入我的 TreeWidget 代码(未显示)。当我将它读入上面的代码时发生的情况是所有通道都被正确读取,然后它读取第一个伺服块并一直返回到主 ModeClass 循环,而不是读取 ModeClass::ReadServos 中的下一个伺服。我知道这是很多代码,但它似乎是显示问题的唯一方法。谢谢,

【问题讨论】:

你需要发布 pMode->ReadXML 的正文 好的,在我正在阅读的代码和 XML 中添加了更多内容。 【参考方案1】:

Qt 文档说:

读取直到当前元素中的下一个开始元素。退货 当到达起始元素时为真。当结束元素是 达到,或者发生错误时,返回false。

所以当你遇到起始元素时,使用readNextStartElement() 会在你找到的元素内部搜索

<xml>
</xml>
<xml>
</xml>

这里会发生什么:

    readNextStartElement() 将在第一个 &lt;xml&gt; 节点上停止 readNextStartElement() 将返回 false,因为它发现 &lt;/xml&gt;

在稍微修改的例子中:

<xml>
  <child>
  </child>
</xml>
<xml>
</xml>
    readNextStartElement() 将在第一个 &lt;xml&gt; 节点上停止 readNextStartElement() 将在 &lt;child&gt; 节点上停止 readNextStartElement() 将返回 false,因为 &lt;child&gt; 节点内没有 xml 节点

请问你应该怎么做?

在您到达您感兴趣的节点并阅读您需要的所有信息后,您必须调用skipCurrentElement(),以便QXmlStreamReader 将转到当前元素的末尾

所以稍微修改一下第一个示例:

<xml>
</xml>
<xml>
</xml>
    readNextStartElement() 将在第一个 &lt;xml&gt; 节点上停止 skipCurrentElement() 将在第一个 &lt;xml&gt; 节点关闭时停止 readNextStartElement() 将在第二个 &lt;xml&gt; 节点停止

【讨论】:

我明白你在说什么,但我正在阅读整个文件并且应该识别所有节点。没有什么我想跳过的。我正在从 XML 构建一个数据库。我发布了更多代码和一个简短的 XML 文件。我希望添加对有效和无效的更好的描述。谢谢。 当然,您不想跳过任何内容。您是否尝试使用调试器来查看您的解析代码到底在哪里停止?在SF_UnitClass::ReadModes() 中设置断点并逐步进行 由于某种原因,我在调试器上遇到了问题。我设置了一个断点,当我到达那里时,如果我跳过它会给我一个错误,说它不能插入断点 -422 并停止调试。调试器必须配置错误,但我不知道如何修复它。如果我只是运行程序没有错误,它只是没有按照我的意愿去做。这就是我使用调试语句的原因。 好吧,我觉得自己很笨。这一切正常,但在我的开关中,我错过了一个案例,所以阅读变得不按顺序。我需要 switch 中的默认值来警告我该块有一个不在 switch 语句中的元素,然后调用 skipCurrentElement()。感谢您的帮助,您的示例确实帮助我意识到我所缺少的。 很高兴我可以指导您找到解决方案,而不是在盘子上给出它:)

以上是关于将 QXmlStreamReader 实例传递给类的主要内容,如果未能解决你的问题,请参考以下文章

使用通知传递字符串,然后传递给类

c# 将变量传递给类

PyQt5:如何将变量传递给类?

如何将对象数据类型传递给类或函数?

传递给类构造函数的 C++ 字符串 - 链接器错误

Kivy 将变量传递给类中的函数