Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QDomElement, how to get these?



  • I have written code to extract the attributes and nodes from an XML document, now I want to add support for nodes that may contain comments, scripts or text.

    I thought the nodeType would identify these, however it doesn't, how do I extract these items?

    I tried using the text function, but it returns not only the content between the node being checked but everything in the document.



  • @SPlatten
    You must switch on the QDomNode::NodeType QDomNode::nodeType() const, which returns one the types in enum QDomNode::NodeType, to do your parsing correctly.

    I have a feeling you are calling QString QDomElement::text() const. This is a "convenience" function which generates the textual content of any QDomElement regardless of its real type, and is not suitable for your purposes. ["The text() function operates recursively to find the text (since not all elements contain text)."] Note that for what you are doing you need to work from QDomNodes, not QDomElements.



  • @JonB , I am doing exactly that in my function, I've single stepped through the function and I don't see any type other than QDomNode::ElementNode.

    Here is my code:

    QDomElement objElement = objXML.documentElement();
    QJsonObject objResponse;
    asTree(objElement, objResponse);
    

    The asTree function is called recursively:

    void clsModXML::asTree(QDomElement& robjElement, QJsonObject& robjResult) {
        QDomNode::NodeType eNodeType = robjElement.nodeType();
    
        if ( eNodeType != QDomNode::ElementNode ) {
    //I have a breakpoint here and it never gets here!
            return;
        }
        QDomNamedNodeMap mpAttr = robjElement.attributes();
        QJsonObject objAttr;
        for( int i=0; i<mpAttr.size(); i++ ) {
            QDomNode item(mpAttr.item(i));
            eNodeType = item.nodeType();
    
            if ( eNodeType != QDomNode::AttributeNode ) {
                continue;
            }
            objAttr.insert(item.nodeName(), item.nodeValue());
        }
        if ( objAttr.isEmpty() != true ) {
            robjResult.insert(clsModXML::mscszAttrs, objAttr);
        }
        robjResult.insert(clsModXML::mscszNode, robjElement.nodeName());
    
        if ( robjElement.hasChildNodes() == true ) {
        //Process any child nodes
            int intChildren = robjElement.childNodes().size();
            QDomNodeList lstChildNodes = robjElement.childNodes();
            for( int c=0; c<intChildren; c++ ) {
                QDomElement objChildEl(lstChildNodes.item(c).toElement());
                QJsonObject objJsonChild;
                asTree(objChildEl, objJsonChild);
    
                if ( objJsonChild.isEmpty() != true ) {
                    QJsonObject::const_iterator citChildren = robjResult.find(clsModXML::mscszChildren);
                    QJsonArray aryChildren;
    
                    if ( citChildren != robjResult.end() ) {
        //An array is already present get the array
                        aryChildren = citChildren->toArray();
                    }
        //Add the new chilren to the array
                    aryChildren.append(objJsonChild);
        //Update the result
                    robjResult.insert(clsModXML::mscszChildren, aryChildren);
                }
            }
        }
    }
    

    My XML that I'm using to test:

    <?xml version="1.0" encoding="utf-8"?>
    <form title="Test form">
    	<simon>Hello World</simon>
    	<susan><!--
    	var Hello = 123;
    	// --></susan>
           <lewis><![CDATA[
    	alert("hello");
    	// ]]></lewis>
    	<entry label="First name:" cols="24" maxlength="24" accept="alpha_only" eol="true"/>
    	<entry label="Surnname:" cols="24" maxlength="24" accept="alpha_only" eol="true"/>
    	<entry label="Sex:" eol="true">
    		<option value="Male"/>
    		<option value="Female"/>
    	</entry>
    	<entry label="Address:" maxlength="256" accept="alpha_numeric" cols="56" rows="5" eol="true"/>
    </form>
    

    I would expect several different types to be encountered as the node simon contains just text, susan contains a comment and lewis contains script.



  • @SPlatten
    That's why I wrote

    Note that for what you are doing you need to work from QDomNodes, not QDomElements.

    I'm not going to follow your code, but both of these look wrong to me:

    void clsModXML::asTree(QDomElement& robjElement
    QDomElement objChildEl(lstChildNodes.item(c).toElement());

    https://doc.qt.io/qt-5/qdomnode.html#toElement

    Converts a QDomNode into a QDomElement. If the node is not an element the returned object will be null.

    All QDomElements are QDomNodes, but not all QDomNodes are QDomElements, e.g. comments.

    Since you want to visit/deal with all node types, you will need to visit/deal with at QDomNode level.

    qDebug() << lstChildNodes.item(c).nodeType();
    qDebug() << lstChildNodes.item(c).isElement();    // this will be `false` for some nodes
    


  • @JonB , thank you, I'll check it out.



  • @JonB , ok, done that...questions, again this is the sample XML:

    <?xml version="1.0" encoding="utf-8"?>
        <form title="Test form">
    	<simon>
    		Hello World
    	</simon>
    	<susan><!--
    		var Hello = 123;
    		// -->
    	</susan>
    	<lewis><![CDATA[
    		alert("hello");
    		// ]]>
    	</lewis>
    	<entry label="First name:" cols="24" maxlength="24" accept="alpha_only" eol="true"/>
    	<entry label="Surnname:" cols="24" maxlength="24" accept="alpha_only" eol="true"/>
    	<entry label="Sex:" eol="true">
    		<option value="Male"/>
    		<option value="Female"/>
    	</entry>
    	<entry label="Address:" maxlength="256" accept="alpha_numeric" cols="56" rows="5" eol="true"/>
    </form>
    

    Why is the content of simon, susan and lewis of type BaseNode ?



  • @SPlatten
    I don't know, and I don't know whether that might depend on how you write your code. I think you have to look at e.g. susan's child nodes (not child elements) to meet the QDomNode::CommentNode?



  • @JonB, I don't get it either as far as I can see thats perfectly valid JavaScript in the susan node. But it gives the same type for all of those nodes.

    Modified code:

    void clsModXML::asTree(QDomNode& robjNode, QJsonObject& robjResult) {
        QDomNode::NodeType eNodeType = robjNode.nodeType();
    
        if ( eNodeType != QDomNode::ElementNode ) {
            return;
        }
        QDomNamedNodeMap mpAttr = robjNode.attributes();
        QJsonObject objAttr;
        for( int i=0; i<mpAttr.size(); i++ ) {
            QDomNode item(mpAttr.item(i));
            eNodeType = item.nodeType();
    
            if ( eNodeType == QDomNode::AttributeNode ) {
                objAttr.insert(item.nodeName(), item.nodeValue());
            }
        }
        if ( objAttr.isEmpty() != true ) {
            robjResult.insert(clsModXML::mscszAttrs, objAttr);
        }
        robjResult.insert(clsModXML::mscszNode, robjNode.nodeName());
    
        if ( robjNode.hasChildNodes() == true ) {
        //Process any child nodes
            int intChildren = robjNode.childNodes().size();
            QDomNodeList lstChildNodes = robjNode.childNodes();
            for( int c=0; c<intChildren; c++ ) {
                QDomNode objChildNode(lstChildNodes.item(c).toElement());
                QJsonObject objJsonChild;
                asTree(objChildNode, objJsonChild);
    
                if ( objJsonChild.isEmpty() != true ) {
                    QJsonObject::const_iterator citChildren = robjResult.find(clsModXML::mscszChildren);
                    QJsonArray aryChildren;
    
                    if ( citChildren != robjResult.end() ) {
        //An array is already present get the array
                        aryChildren = citChildren->toArray();
                    }
        //Add the new chilren to the array
                    aryChildren.append(objJsonChild);
        //Update the result
                    robjResult.insert(clsModXML::mscszChildren, aryChildren);
                }
            }
        }
    }
    
    


  • @SPlatten said in QDomElement, how to get these?:

    QDomNode objChildNode(lstChildNodes.item(c).toElement());

    As I said earlier, what is this doing? I expect to see recursion on all child nodes, not just elements. No, I'm not following your logic, I'm just making an observation.



  • @JonB , well spotted, thank you!


Log in to reply