QXmlStreamReader: невозможно следить за потоком readNextStartElement()

Мне нужно реализовать синтаксический анализатор xml, который создает и помещает объекты Qt в виджет во время выполнения. Я написал парсер на основе этого. Модуль представляет QWidget, который будет содержать экземпляры QPushButton и QCheckBox. xml — это QXmlStreamReader, как в примере из справочника Qt.

Итак, здесь я пытаюсь разобрать этот очень простой XML-файл:

<somexml version="1.0">
    <module>
        <button label="Send UART" define="BUTTON0" pos="30, 30" size="20, 10">
            <action cmd="sendCom" data="0xAA 0xBB 0xCC"/>
        </button>
        <checkbox label="Send UART" define="CHECKBOX0" pos="250, 30" size="20, 10">
            <action cmd="sendCom" data="test"/>
        </checkbox>
        <button label="Check BIT" define="BUTTON1" pos="140, 30" size="20, 10">
            <action cmd="setDef" data="BUTTON0=1"/>
        </button>   
    </module>
</somexml>

Элемент модуля создаст виджет для хранения флажков и кнопок внутри тегов. Так вот:

void XmlReader::readXml()
{
    while (xml.readNextStartElement())
    {
        if (xml.name() == "module")
        {
            readModule();
        }
    }
}

Я ожидаю прочитать элемент модуля и войти в область readModule, что он и делает. Внутри readModule у меня действительно проблемы со следованием потока синтаксического анализа.

Вот реализация:

void XmlReader::readModule()
{
    Q_ASSERT(xml.isStartElement() && xml.name() == "module");


    while (xml.readNextStartElement())
    {
        if (xml.name() == "button")
        {
            readButton(widget);
        }
        else if (xml.name() == "checkbox")
        {
            readCheckBox(widget);
        }
        else
        {
            xml.skipCurrentElement();
        }
    }
}

Он достигнет только первого элемента button в файле xml и создаст одну кнопку. Отправить UART.

Когда я изменяю реализацию readXml на:

void XmlReader::readXml()
{
    while (xml.readNextStartElement())
    {
        if (xml.name() == "module")
        {
            readModule();
        }
        else if (xml.name() == "button")
        {
            readButton(widget);
        }
        else if (xml.name() == "checkbox")
        {
            readCheckBox(widget);
        }
        else
        { 
            xml.skipCurrentElement();
        }
    }
}

он достигнет первой кнопки и первого флажка. Что мне не хватает?

EDIT: добавлена ​​реализация readButton

void XmlReader::readButton(Widget *widget)
{
    Q_ASSERT(xml.isStartElement() && xml.name() == "button");

    QString label = xml.attributes().value("label").toString();
    QString define = xml.attributes().value("define").toString();

    QString pos = xml.attributes().value("pos").toString();
    QStringList posList = pos.split(",");
    int posX = posList[0].toInt();
    int posY = posList[1].toInt();

    QString size = xml.attributes().value("size").toString();
    QStringList sizeList= size.split(",");
    int sizeX = sizeList[0].toInt();
    int sizeY = sizeList[1].toInt();

    QString cmd, data;

    while (xml.readNextStartElement())
    {
        if (xml.name() == "action") 
        {
            cmd = xml.attributes().value("cmd").toString();
            data = xml.attributes().value("data").toString();
        }
        else
        {
            xml.skipCurrentElement();
        }
    }

    if (cmd == "sendCom")
    {
        widget->createButton(label, define, posX, posY,
                SLOT(sendCom(QString)), data);
    }
    else if (cmd == "setDef")
    {
        widget->createButton(label, define, posX, posY,
                SLOT(setDef(QString)), data);
    }
}

person tobilocker    schedule 26.01.2016    source источник
comment
Как вы реализовали readButton(widget);? Может быть, после того, как readButton xml.readNextStartElement() вернет, падает, потому что он читает «конечный элемент» (например, ‹/button›), и цикл прерывается.   -  person Tony O    schedule 26.01.2016
comment
добавил реализацию   -  person tobilocker    schedule 26.01.2016
comment
Попробуйте добавить xml.readElementText(); после readButton и после readCheckBox. Или xml.skipCurrentElement(); Думаю, что помогут оба.   -  person Tony O    schedule 26.01.2016


Ответы (1)


Вам нужно использовать xml.skipCurrentElement(); после readButton(widget); и readCheckBox(widget);. Без этого xml.readNextStartElement() читает конец элемента и прерывает цикл.

void XmlReader::readModule()
{
    Q_ASSERT(xml.isStartElement() && xml.name() == "module");

    while (xml.readNextStartElement())
    {
        if (xml.name() == "button")
        {
            readButton(widget);
            xml.skipCurrentElement();
        }
        else if (xml.name() == "checkbox")
        {
            readCheckBox(widget);
            xml.skipCurrentElement();
        }
        else
        {
            xml.skipCurrentElement();
        }
    }
}
person Tony O    schedule 26.01.2016
comment
Это работает, но термин skipCurrentElement по-прежнему звучит для меня довольно неинтуитивно. - person tobilocker; 27.01.2016