У меня возникли проблемы с обнаружением пустых элементов с использованием Qt QXmlStreamReader (Qt 4.8.1).
Существует файл XML, который имеет следующий раздел
<Groups Number="4">
<Group Id="0" GroupName="Chambers">
<MemberChannels>4,5,6,7,8,9,10,11</MemberChannels>
<AverageShown>true</AverageShown>
</Group>
<Group Id="1" GroupName="Fluids">
<MemberChannels>0,1,17,18</MemberChannels>
<AverageShown>false</AverageShown>
</Group>
<Group Id="2"/>
<Group Id="3"/>
</Groups>
Как видите, элементы с Id 2 и 3 пусты, кроме атрибута. Атрибут ничего не меняет. Если это не в элементе, проблема все еще возникает.
Это код синтаксического анализа с использованием QXmlStreamReader, я упростил его, поэтому он может не скомпилироваться. Просто у вас есть основная идея.
[...]
QXmlStreamReader* m_poStreamReader = new QXmlStreamReader;
[...]
if(m_poStreamReader->readNextStartElement() && m_poStreamReader->name().toString() == "Group") {
this->parseGroupElement();
}
[...]
bool CTempscanXmlParser::parseGroupElement( void ) {
TGroupElement tElement;
if(m_poStreamReader->isStartElement() && !m_poStreamReader->isEndElement()) { // not empty
TGroupElement tElement = this->readGroupElement();
} else if(m_poStreamReader->isStartElement() && m_poStreamReader->isEndElement()) { // empty
tElement.oGroupName = QString::null;
}
[...]
}
В документации сказано:
Пустые элементы также сообщаются как StartElement, за которыми непосредственно следует EndElement.
Я могу использовать readNext () и до сих пор не получить конечный элемент. Кажется, что парсер может только обнаружить
<tag></tag>
как пустой элемент, но не
<tag/>
Так это только у меня или проблема существует в Qt? И если так, как я могу обнаружить пустые элементы, которые не состоят из 2 отдельных элементов (начало / конец)?
Редактировать:
Итак, Хейтард попросил у меня рабочий пример. Но его ответ привел меня к решению, которое почти ответило на мой вопрос. Поэтому я привел разъясненный пример в своем ответе.
Так что благодаря Хейтарду я понял, что это просто поведение QXmlStreamReader :: readNextStartElement, которое как-то неожиданно. Я ожидал, что это будет просто читать Начните элементы. И изначально я хотел заранее проверить, является ли элемент пустым, а затем решить, что делать с его содержимым. Кажется, что это невозможно. И эта невозможность покрыта документацией, которую я сам цитировал. То есть даже если атомарный элемент пуст, за ним фактически следует начальный элемент, который фактически является конечным элементом. Это плохо, так как вы не можете вернуться в поток.
Основываясь на его ответе, я написал небольшой пример, который разъясняет (извините) и отвечает на мой оригинальный вопрос.
const QString XML_STR = "<Groups Number=\"4\">" \
"<Group Id=\"0\" GroupName=\"Chambers\">" \
"<MemberChannels>4,5,6,7,8,9,10,11</MemberChannels>" \
"<AverageShown>true</AverageShown>" \
"</Group>" \
"<Group Id=\"1\"/>" \
"<Group Id=\"2\"/>" \
"</Groups>";
int main(int /* argc */, char** /* argv[] */)
{
qDebug() << "the way it would have made sense to me:";
{
QXmlStreamReader reader(XML_STR);
while(!reader.atEnd())
{
reader.readNextStartElement();
QString comment = (reader.isEndElement()) ? "is empty" : "has children";
qDebug() << reader.name() << comment;
}
}
qDebug() << "\napproximation to the way it should probably be done:";
{
QXmlStreamReader reader(XML_STR);
bool gotoNext = true;
while(!reader.atEnd())
{
if(gotoNext) {
reader.readNextStartElement();
}
QString output = reader.name().toString();
reader.readNext();
if(reader.isEndElement()) {
output += " is empty";
gotoNext = true;
} else {
output += " has children";
gotoNext = false;
}
qDebug() << output;
}
}
return 0;
}
что приводит к следующему выводу
#they way it would have made sense to me:
"Groups" "has children""Group" "has children""MemberChannels" "has children""MemberChannels" "is empty""AverageShown" "has children""AverageShown" "is empty""Group" "is empty""Group" "has children""Group" "is empty""Group" "has children""Group" "is empty""Groups" "is empty""" "has children"# this has all been plain wrong
#approximation to the way it should probably be done:
"Groups has children""Group has children""MemberChannels has children"" is empty" # ... but not a start element
"AverageShown has children"" is empty""Group has children" # still wrong! this is an end element
"Group is empty""Group is empty""Groups has children" # ditto
Мне все еще не нравится это. Как это работает, мне нужно провести тройную проверку всего, что делает код менее читабельным.
Вы пробежали через это с помощью отладчика?
Я догадываюсь, что у вас есть ошибка в вашем коде. полный и соответствующие части вашего кода помогут исключить вероятность того, что это ошибка Qt (на что, я готов поспорить, это не так).
Этот короткий тест ниже должен подтвердить, что QXmlStreamReader может анализировать пустой элемент:
const QString XML_STR = "<root><node /></root>";
int main(int /* argc */, char* /* argv[] */)
{
qDebug() << "Using readNextStartElement():";
{
QXmlStreamReader reader(XML_STR);
while(!reader.atEnd())
{
reader.readNextStartElement();
qDebug() << reader.name();
}
}
qDebug() << "Using readNext():";
{
QXmlStreamReader reader(XML_STR);
while(!reader.atEnd())
{
reader.readNext();
qDebug() << reader.name();
}
}
return 0;
}
Выход:
Using readNextStartElement():
"root""node""node""root"""Using readNext():
"""root""node""node""root"""