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.
-
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. ["Thetext()
function operates recursively to find the text (since not all elements contain text)."] Note that for what you are doing you need to work fromQDomNode
s, notQDomElement
s. -
@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. ["Thetext()
function operates recursively to find the text (since not all elements contain text)."] Note that for what you are doing you need to work fromQDomNode
s, notQDomElement
s.@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.
-
@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 wroteNote that for what you are doing you need to work from
QDomNode
s, notQDomElement
s.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 aQDomElement
. If the node is not an element the returned object will benull
.All
QDomElement
s areQDomNode
s, but not allQDomNode
s areQDomElement
s, 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
-
@SPlatten
That's why I wroteNote that for what you are doing you need to work from
QDomNode
s, notQDomElement
s.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 aQDomElement
. If the node is not an element the returned object will benull
.All
QDomElement
s areQDomNode
s, but not allQDomNode
s areQDomElement
s, 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
-
@SPlatten
That's why I wroteNote that for what you are doing you need to work from
QDomNode
s, notQDomElement
s.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 aQDomElement
. If the node is not an element the returned object will benull
.All
QDomElement
s areQDomNode
s, but not allQDomNode
s areQDomElement
s, 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 , 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 ?
-
@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 theQDomNode::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); } } } }
-
@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.
-
@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.