May 8, 2012

fluca1978 fluca1978
Lab Rat
529 posts

XML DOM empty

 

Hi all,
it must be a stupid error but I cannot see it:

  1.   QDomDocument xmlDocument;
  2.   QDomProcessingInstruction procInstr = xmlDocument.createProcessingInstruction( "xml",
  3.               "version='1.0' encoding='UTF-8'");
  4.   xmlDocument.appendChild( procInstr );
  5.   QDomElement rolesElement = xmlDocument.createElement( Role::XML_TAG_ROLES );
  6.   xmlDocument.appendChild( rolesElement );
  7.  
  8.  
  9.   QList<Role>::const_iterator roleIterator;
  10.   for( roleIterator = roles.constBegin(); roleIterator != roles.constEnd(); roleIterator++ ){
  11.     const Role& currentRole = *roleIterator;
  12.     QDomElement currentRoleElement = xmlDocument.createElement( Role::XML_TAG_ROLE );
  13.     rolesElement.appendChild( currentRoleElement );
  14.     QDomElement roleIDElement = xmlDocument.createElement( Role::XML_TAG_ROLEID );
  15.     QDomText roleIDText       = xmlDocument.createTextNode( currentRole.id() );
  16.     roleIDElement.appendChild( roleIDText );
  17.     currentRoleElement.appendChild( roleIDElement );
  18.   }

The above XML should create a dump of a custom object Role, and the iteration is working fine, but the end result is an empty XML document with only the processing instruction. It seems to me that all elements are parented right, but I guess it is not. Any suggestion?

9 replies

May 8, 2012

fluca1978 fluca1978
Lab Rat
529 posts

I must be doing something wrong with the parenting of elements, since it seem that only the first element I add to the document is always printed. I’ve tied to remove the processing instruction and then the rolesElement is placed and so on. But I cannot see where the error is….

May 8, 2012

DerManu DerManu
Lab Rat
509 posts

You’re trying to put multiple elements on the level of the root node.

  • Create your processing instruction and add it to the document (like you’re doing already).
  • Create a root element and add it to the document

All further elements must be added not to the document, but to the root element (or below). You can retrieve the root element (the one you’ve created previously) via xmlDocument.documentElement().

i.e you’re trying this:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <element1>
  3. <element2>

when you should do:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <myRootElement>
  3.   <element1>
  4.   <element2>
  5. </myRootElement>

May 9, 2012

fluca1978 fluca1978
Lab Rat
529 posts

DerManu wrote:

All further elements must be added not to the document, but to the root element (or below). You can retrieve the root element (the one you’ve created previously) via xmlDocument.documentElement().

Uhm..sorry, I still don’t get it. I’ve rewritten the code in order to make it clear what is the root element and I’ve removed the processing instruction since at the moment I don’t need it:

  1. QDomElement rootElement = xmlDocument.createElement( Role::XML_TAG_ROLES );
  2.   rootElement.setAttribute( "count", roles.size() );
  3.  
  4.   // iterate on each role
  5.   QList<Role>::const_iterator roleIterator;
  6.   for( roleIterator = roles.constBegin(); roleIterator != roles.constEnd(); roleIterator++ ){
  7.     const Role& currentRole = *roleIterator;
  8.    
  9.     QDomElement currentRoleElement = xmlDocument.createElement( Role::XML_TAG_ROLE );
  10.     QDomElement roleIDElement = xmlDocument.createElement( Role::XML_TAG_ROLEID );
  11.     QDomText roleIDText       = xmlDocument.createTextNode( currentRole.id() );
  12.     roleIDElement.appendChild( roleIDText );
  13.     currentRoleElement.appendChild( roleIDElement );
  14.     rootElement.appendChild( currentRoleElement );
  15.    
  16.   }
  17.  
  18.   xmlDocument.appendChild( rootElement );

So each child element “currentRoleElement” is actually appended to the root element and the latter to the document. I don’t see where I’m trying to add all elements as root elements of the document.
The hierarchy should be that:

  1. rootElement
  2.       currentRoleElement
  3.            roleIDElement
  4.                roleIDText

May 9, 2012

DerManu DerManu
Lab Rat
509 posts

Sorry, it seems I’ve overlooked something in your code, I thought you were adding more than one element directly to the document instead of the root node.

However, this works for me:

  1.   QDomDocument xmlDocument;
  2.   QDomElement rootElement = xmlDocument.createElement("root");
  3.   rootElement.setAttribute( "count", 5 );
  4.   QDomElement currentRoleElement = xmlDocument.createElement("subelement");
  5.   QDomElement roleIDElement = xmlDocument.createElement("subelement");
  6.   QDomText roleIDText       = xmlDocument.createTextNode("subelement");
  7.   roleIDElement.appendChild( roleIDText );
  8.   currentRoleElement.appendChild( roleIDElement );
  9.   rootElement.appendChild( currentRoleElement );
  10.   xmlDocument.appendChild( rootElement );
  11.   QFile file("./test.xml");
  12.   file.open(QFile::WriteOnly|QFile::Truncate);
  13.   QTextStream stream(&file);
  14.   xmlDocument.save(stream, 2);

it produces as expected

  1. <root count="5">
  2.   <subelement>
  3.     <subelement>subelement</subelement>
  4.   </subelement>
  5. </root>

So my guess is there’s something wrong with your “Role” mechanism.

May 10, 2012

fluca1978 fluca1978
Lab Rat
529 posts

I found a possible problem when creating the text node, that seem to break the tree.
If I do the following:

  1. QDomText roleIDText       = xmlDocument.createTextNode(  currentRole.id() );

no node is created at all.
If I do for instance
  1. QDomText roleIDText       = xmlDocument.createTextNode( "Hello" +   currentRole.id() );

the node is created with both the string “Hello” concat with the id() result.
If I do:
  1. QDomText roleIDText       = xmlDocument.createTextNode( "" +   currentRole.id() );

nothing is printed out.
The id member function is defined as follows:
  1. const QString& id() const;

Any idea?

May 10, 2012

fluca1978 fluca1978
Lab Rat
529 posts

An other update, that solves my problem but leaves me with a doubt.
The following is the way I was testing the output document, thru which I report the above problems:

  1. qdebug() << "XML Document " << xmlDocument.toString( 5 );

and the following is a way that prints out the document into a file that works:

  1.   QFile file( "/home/luca/tmp/roles.xml");
  2.   file.open(QFile::WriteOnly|QFile::Truncate);
  3.   QTextStream stream( &file );
  4.   xmlDocument.save( stream, 2);
  5.  

So seems to me that the document is suffering some way of “flushing” when the toString is called?

May 10, 2012

DerManu DerManu
Lab Rat
509 posts

That sure is a bit strange. I’m not aware of such buffering making toString and save behave differently, and it doesn’t happen when I test it.

What does currentRole.id() typically contain? Invalid tag characters? Numbers only? In this case, the XML becomes invalid, so when your InvalidDataPolicy (see QDomImplementation::setInvalidDataPolicy) is DropInvalidCharacters or ReturnNullNode, you might get an empty XML document. However, this would cause some debug output along the lines of “Calling appendChild() on a null node does nothing.”

May 10, 2012

fluca1978 fluca1978
Lab Rat
529 posts
DerManu wrote:
T What does currentRole.id() typically contain? Invalid tag characters?

Plain text, no makrup signs (e.g., dev, doc). I’m investigating more to see if I find the cause.

May 10, 2012

DerManu DerManu
Lab Rat
509 posts

I’ve just looked through the code of qdom.cpp [qt.gitorious.org] and there are no signs of such buffering. Both QDomDocument::save and toString internally call the save functions recursively on the document nodes. In fact, toString just creates a QTextStream on the returned string and writes its content with save itself. So this definetly isn’t the cause.

 
  ‹‹ How to config ActiveX controls and COM object in qt 4.7.4      Problem with vertical alignment in QTextTableFormat ››

You must log in to post a reply. Not a member yet? Register here!