Извлечение значений дочерних узлов с помощью QXmlItem в качестве фокуса QXmlQuery - PullRequest
7 голосов
/ 17 октября 2011

Я пытался получить текстовые значения узла из этого XML-файла:

<code>  <!DOCTYPE structure>
  <data>
   <x>
    <id>1</id>
    <nam>tytuł</nam>
    <tab>21</tab>
    <ind>5</ind>
    <pre>TY
C.TY 2 Автор 21 5
FO
C.FO 3 hasło korporatywne 21 5
FN
функция C.Fn

Что я хочу сделать, это выбрать каждый узел и его дочерние элементы и преобразовать его в QMap. У меня нет проблем с извлечением одного элемента, но когда дело доходит до извлечения дочерних элементов путем установки результата QXmlQuery в качестве фокуса, QString, который я оцениваю, запрос дочернего узла пуст. Я использую этот кусок кода:

QXmlResultItems results;
QFile structure("./structure.xml"); // xml file, as described earlier
structure.open(QFile::ReadOnly);

QXmlQuery query;
query.setFocus(&structure);
query.setQuery("data/x");
query.evaluateTo(&results);

QXmlItem next = results.next();
while(!next.isNull()) {
    qDebug() << next.toNodeModelIndex().stringValue(); // everything's fine. It prints contents of <x>'s child nodes
    QXmlQuery childQuery;
    QString r;
    childQuery.setFocus(next);
    childQuery.setQuery("./nam/text()"); // already tested: "/nam/text()", "/nam/string()", "x/nam/string()", "data/x/nam/string()" etc... still no luck.
    childQuery.evaluateTo(&r);
    qDebug() << r; // prints \n but it should print content of <nam> node.

    next = results.next();
}

Программное обеспечение, которое я использую: Qt 4.7.2 SDK непосредственно с веб-сайта Qt, QtCreator 2.3.1 для Windows и Linux (без каких-либо различий в данном конкретном случае результаты совпадают). Я хочу быть уверен, что это проблема моего недостатка знаний, а не ошибки программного обеспечения, пожалуйста, помогите

Ответы [ 4 ]

8 голосов
/ 25 ноября 2014

К сожалению, из документации Qt неясно, что в случаях, когда вы хотите использовать перегрузку QXmlQuery::setFocus(const QXmlItem& item) для запроса дочерних узлов, вы должны создать соответствующие QXmlQuery объекты, используя конструктор QXmlQuery(const QXmlNamePool& np), чтобы они использовали один и тот же QXmlNamePool объект. Проще говоря, связывает запросов друг с другом.

Учитывая это, ваш пример должен выглядеть следующим образом:

QFile structure("./structure.xml");
structure.open(QFile::ReadOnly);

QXmlQuery query;
query.setFocus(&structure);
query.setQuery("data/x");

QXmlResultItems results;
query.evaluateTo(&results);

QXmlQuery childQuery(query.namePool());
while (!results.next().isNull()) {
    childQuery.setFocus(results.current());
    childQuery.setQuery("nam/text()");
    QString r;
    childQuery.evaluateTo(&r);
    qDebug() << r;
}

Более того, вы можете пойти дальше и повторно использовать исходный QXmlQuery объект:

QFile structure("./structure.xml");
structure.open(QFile::ReadOnly);

QXmlQuery query;
query.setFocus(&structure);
query.setQuery("data/x");

QXmlResultItems results;
query.evaluateTo(&results);

while (!results.next().isNull()) {
    query.setFocus(results.current());
    query.setQuery("nam/text()");
    QString r;
    query.evaluateTo(&r);
    qDebug() << r;
}
1 голос
/ 04 марта 2012

Вместо использования evaluateTo( QString * ) используйте версию QStringList. Это должно работать.

0 голосов
/ 28 февраля 2014

У меня была такая же проблема, и решение состояло в том, чтобы query и childQuery были точно такими же. Вы можете переписать свой код как:

while(!next.isNull()) {
    qDebug() << next.toNodeModelIndex().stringValue();
    QString r;
    query.setFocus(next);
    query.setQuery("./nam/text()");
    query.evaluateTo(&r);
    qDebug() << r;

    next = results.next();
}

если childQuery должен быть в другой процедуре, вы должны передать его по ссылке.

0 голосов
/ 17 октября 2011

Должно работать так:

QDomDocument doc("structure");
QFile file("structure.xml");
if( !file.open( IO_ReadOnly ) )
  return -1;
if( !doc.setContent( &file ) )
{
  file.close();
  return -2;
}
file.close();

QDomElement root = doc.documentElement();
if( root.tagName() != "data" )
  return -3;

QDomNode n = root.firstChild();
while( !n.isNull() )
{
  QDomElement e = n.toElement();
  if( !e.isNull() )
  {
    if( e.tagName() == "x" )
    {
      QMessageBox::information( 0, "X", e.attribute("id", "")+ "\n" + e.attribute("nam", "" ) + "\n" + e.attribute("tab", ""));
    }
  }

  n = n.nextSibling();
}

Код создает окно сообщения для каждого x (на этой машине нет qt, поэтому не можете его проверить прямо сейчас)

...