Using QDomNode::firstChildElement() repeatedly feels weird...
-
For an XML document structure like
<one> <two> <three /> </two> </one>when I need to get the
<three />element, I currently writeconst auto three = doc .firstChildElement("one").firstChildElement("two").firstChildElement("three");but this feels weird. Often, I have wondered if there isn't a shorter way to do this with a single command, something like
const auto three = doc.someUnknownFunction("three");I don't think
elementsByTagName()is what I want, as that returns aQDomNodeList...How would you guys do this elegantly?
-
Hi,
Based on the XML you gave
elementsByTagNamelooks like the right choice, you'll have a list of one element forthree. -
For an XML document structure like
<one> <two> <three /> </two> </one>when I need to get the
<three />element, I currently writeconst auto three = doc .firstChildElement("one").firstChildElement("two").firstChildElement("three");but this feels weird. Often, I have wondered if there isn't a shorter way to do this with a single command, something like
const auto three = doc.someUnknownFunction("three");I don't think
elementsByTagName()is what I want, as that returns aQDomNodeList...How would you guys do this elegantly?
@Bart_Vandewoestyne said in Using QDomNode::firstChildElement() repeatedly feels weird...:
How would you guys do this elegantly?
By not doing it. ;)
What I'd do is to create my document in C++ in an object-oriented fashion - each element is represented by a specific class all of which derive from a specific interface. For example I'd have something along:class MyCoolFormatElement { public: virtual bool load(const QDomElement &) = 0; }; class MySecondElement : public MyCoolFormatElement { public: bool load(const QDomElement & element) override { // Do something for this element to extract the data, e.g. textData = element.text(); } private: QString textData; //< Or whatever it contains }; class MyFirstElement : public MyCoolFormatElement { public: bool load(const QDomElement & element) override { // Do something for this element to extract it's own private data (for example values from attributes) // ... // Pass on to the child element we expect (there's none, then we have a default value set in it's constructor) QDomNodeList tagList = element.elementsByTagName("two"); if (tagList.count() == 0) return false; secondElement.load(tagList.at(0).toElement()); } private: MySecondElement secondElement; };And you'd load the data from the root element of the document:
QDomDocument document; MyFirstElement myCoolDocumentFormat; if (!myCoolDocumentFormat.load(document.documentElement())) ; // OopsObviously there's a lot of possible variability, but in my mind it definitely beats the naive approach.
PS. To fully fluff it up, one should in principle keep one string for the tag name (initialized in the constructor) in the element class itself and use that instead of hardcoding the string in the parent's load. E.g:
QDomNodeList tagList = element.elementsByTagName(secondElement.name()); -
elementsByTagnameis the shortest/fastest code if you don't care about where the<three />s occur in the structure. If you want to ensure it's<one><two><three>you do have to do it via multiplefirstChildElements.@JNBarchan said in Using QDomNode::firstChildElement() repeatedly feels weird...:
elementsByTagnameis the shortest/fastest code if you don't care about where the<three />s occur in the structure. If you want to ensure it's<one><two><three>you do have to do it via multiplefirstChildElements.OK, thanks. That confirms what I was thinking :-)
-
@Bart_Vandewoestyne said in Using QDomNode::firstChildElement() repeatedly feels weird...:
How would you guys do this elegantly?
I am a beginner at Qt, so I don't know what the relationship is between how you get a
QDomDocumentversus some kind ofQXmlDocument(which in itself does not seem to exist).However, in case you were not aware, the normal/simplest/shortest way of doing this kind of query is via XPath/XQuery, and I see Qt has
QXmlQueryfor this (http://doc.qt.io/qt-5/qxmlquery.html#details).Then your search for the node would be like:
QXmlQuery query; query.setQuery("/one/two/three");The point being, XPath/XQuery (http://doc.qt.io/qt-5/xquery-introduction.html) lets you specify your queries in a string and it does the tree descent for you, there's no code for you to write. It has advanced features for all sorts of queries, e.g. including the ability to search by attributes as well as node names/types, which can be lot simpler/clearer than writing explicit code.
As an extra "goodie",
QXmlQuerygives you access to XSL/XSLT stylesheets, which can be really useful/simple for transforming XML for output.