1

我有一个这样的 XML 文档

<root>
 <stuff>
   <data foo="bar">
     <name>barf</name>
     <value>123</value>
   </data>
   <!-- ... --->
 </stuff>
</root>

并希望通过树递归以从中获取所有信息,例如

data bar
 name barf
 value 123

但是,DomElement::text()也返回子元素的文本内容,即data元素的“barf 123”

我发现一些相当紧凑的代码可以通过 DOM 进行递归:

void MyClass::TraverseXmlNode(const QDomNode& node)
{
    QDomNode domNode = node.firstChild();
    QDomElement domElement;
    while(!(domNode.isNull())) 
    {
        if(domNode.isElement()) 
        {
            domElement = domNode.toElement();
            if(!(domElement.isNull()))
            {
                qDebug() << __FUNCTION__ << "" << domElement.tagName() << domElement.text();
            }
        }
        TraverseXmlNode(domNode);
        domNode = domNode.nextSibling();
    }
}
4

2 回答 2

3

The solution is very simple: do not output an element's text. You want to look for text nodes instead:

void MyClass::TraverseXmlNode(const QDomNode& node)
{
  QDomNode domNode = node.firstChild();
  QDomElement domElement;
  QDomText domText;

  static int level = 0;

  level++;

  while(!(domNode.isNull())) 
  {
    if(domNode.isElement()) 
    {
      domElement = domNode.toElement();
      if(!(domElement.isNull()))
      {
        qDebug() << __FUNCTION__ << "isElement" << level << QString(level, ' ').toLocal8Bit().constData() << domElement.tagName().toLocal8Bit().constData();

        QDomNamedNodeMap nma = domElement.attributes();
        int l = nma.length();
        for(  int i=0; i < l; i++ )
        {
          QDomAttr tempa = nma.item(i).toAttr();
          qDebug() << __FUNCTION__ << "isElement"  << level << QString(level, ' ').toLocal8Bit().constData() << "attribute" << i << tempa.name().toLocal8Bit().constData() << tempa.value().toLocal8Bit().constData();
        }
      }
    }

    if(domNode.isText())
    {
      domText = domNode.toText();
      if(!domText.isNull())
      {
        qDebug() << __FUNCTION__ << "isText   " << level << QString(level, ' ').toLocal8Bit().constData() << domText.data().toLocal8Bit().constData();
      }
    }

    TraverseXmlNode(domNode);
    domNode = domNode.nextSibling();
  }

  level--;
}
于 2013-04-09T07:46:46.033 回答
0

对于那些在这里寻找紧凑代码来迭代 a 的人QDomDocument

void recurseQDomNode(QDomNode node, int depth, const std::function<void (QDomNode&, int depth)>& perNodeAction)
{
    QDomNodeList paths = node.childNodes();
    perNodeAction(node, depth);
    for (int i = 0; i < paths.count(); ++i) {
        recurseQDomNode(paths.at(i), depth + 1, perNodeAction);
    }
}

还有一个解决问题的例子

int main(int argc, char *argv[])
{
    QDomDocument doc;
    doc.setContent(QString(R"(<root>
 <stuff>
   <data foo="bar">
     <name>barf</name>
     <value>123</value>
   </data>
   <!-- ... --->
 </stuff>
</root>
)"));

    recurseQDomNode(doc.documentElement().firstChild(), 0, [](QDomNode& node, int depth)
    {
        if (node.isElement()) {
            QString output(depth, ' ');

            auto element = node.toElement();
            output += element.tagName();

            // Add attribute values to the line
            auto attributeMap = element.attributes();
            for(int i = 0; i < attributeMap.count(); ++i) {
                auto attribute = attributeMap.item(i).toAttr();
                output += " " + attribute.value();
            }

            // Add element string content to the line
            if (element.firstChild().isText()) {
                output += " " + element.firstChild().toText().data();
            }

            qDebug() << output;
        }
    });

    return 0;
}

输出:

"stuff"
" data bar"
"  name barf"
"  value 123"
于 2021-04-16T13:46:32.990 回答