Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Using QDomNode::firstChildElement() repeatedly feels weird...
Qt 6.11 is out! See what's new in the release blog

Using QDomNode::firstChildElement() repeatedly feels weird...

Scheduled Pinned Locked Moved Solved General and Desktop
6 Posts 4 Posters 2.1k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Bart_Vandewoestyne
    wrote on last edited by
    #1

    For an XML document structure like

    <one>
        <two>
            <three />
        </two>
    </one>
    

    when I need to get the <three /> element, I currently write

    const 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 a QDomNodeList...

    How would you guys do this elegantly?

    kshegunovK 1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Based on the XML you gave elementsByTagName looks like the right choice, you'll have a list of one element for three.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #3

        elementsByTagname is 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 multiple firstChildElements.

        B 1 Reply Last reply
        1
        • B Bart_Vandewoestyne

          For an XML document structure like

          <one>
              <two>
                  <three />
              </two>
          </one>
          

          when I need to get the <three /> element, I currently write

          const 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 a QDomNodeList...

          How would you guys do this elegantly?

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by kshegunov
          #4

          @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()))
              ; // Oops
          

          Obviously 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());
          

          Read and abide by the Qt Code of Conduct

          1 Reply Last reply
          0
          • JonBJ JonB

            elementsByTagname is 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 multiple firstChildElements.

            B Offline
            B Offline
            Bart_Vandewoestyne
            wrote on last edited by
            #5

            @JNBarchan said in Using QDomNode::firstChildElement() repeatedly feels weird...:

            elementsByTagname is 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 multiple firstChildElements.

            OK, thanks. That confirms what I was thinking :-)

            1 Reply Last reply
            0
            • JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #6

              @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 QDomDocument versus some kind of QXmlDocument (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 QXmlQuery for 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", QXmlQuery gives you access to XSL/XSLT stylesheets, which can be really useful/simple for transforming XML for output.

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved