[ fromfile: xml-dom.xml id: domtreewalking ]
Qt provides full read/write access to trees of XML data.
Nodes can be navigated through an interface which is similar to, but slightly different from the QObject interface.
Under the surface, SAX performs the parsing, and DOM defines a content handler that creates the tree of objects in memory.
All client code needs to do is call setContent()
, which causes the input to be parsed and the tree to be generated.
Example 15.8. src/xml/domwalker/main.cpp
[ . . . . ] int main(int argc, char **argv) { QApplication app(argc, argv); QString filename; if (argc < 2) { cout << "Usage: " << argv[0] << " filename.xml" << endl; filename = "samplefile.xml"; } else { filename = argv[1]; } QFile f(filename); QString errorMsg; int errorLine, errorColumn; QDomDocument doc("SlackerDoc"); bool result = doc.setContent(&f, &errorMsg, &errorLine, &errorColumn); QDomNode before = doc.cloneNode(true); Slacker slack(doc); QDomNode after = slack.transform(); cout << QString("Before: ") << before << endl; cout << QString("After: ") << after << endl; QWidget * view = twinview(before, after); view->show(); app.exec(); delete view; } [ . . . . ]
<include src="src/xml/domwalker/main.cpp" href="src/xml/domwalker/main.cpp" id="domwalkermain" allfiles="true" mode="cpp"/>
Example 15.8 transforms an XML document in-place. After the tree is manipulated, it is serialized to a QTextStream where it becomes savable and parsable again. Figure 15.4 shows the main classes used in this example.
Slacker
is derived from DomWalker
, an application specialized for walking through DOM trees.
Example 15.9. src/xml/domwalker/domwalker.cpp
[ . . . . ] QDomDocument DomWalker::transform() { walkTree(m_Doc); return m_Doc; } QDomNode DomWalker::walkTree(QDomNode current) { QDomNodeList dnl = current.childNodes(); for (int i=dnl.count()-1; i >=0; --i) walkTree(dnl.item(i)); if (current.nodeType() == QDomNode::ElementNode) { QDomElement ce = current.toElement(); return visit(ce); } return current; } [ . . . . ]
<include src="src/xml/domwalker/domwalker.cpp" href="src/xml/domwalker/domwalker.cpp" id="domwalkercpp" mode="cpp"/>
The walkTree()
method, defined in Example 15.9, contains no pointers or typecasts.
The QDom(Node|Element|Document|Attribute)
types are smart-pointers.
We "downcast" from QDomNode to QDomElement, or QDomXXX
, using QDomNode::toElement()
or toXXX()
conversion functions.
Tip | |
---|---|
When traversing a tree, it is possible to use only the QDomNode interface, but "casting down" to QDomElement adds some convenient functions for dealing with the element as a whole, with its attributes (which are QDomNode child objects themselves). |
Even though in this example QDomNode/QDomElement objects are being passed and returned by value, it is still possible to change the underlying DOM objects through the temporary copies. Through interface trickery, QDom objects look and feel like Java-style references, and hold pointers inside, rather than actual data.
Slacker
defines how to transform documents from one XML format to another.
It is an extension of DomWalker
and overrides just one method, visit()
.
Defined in Example 15.10, this method has a special rule for each kind of element.
Example 15.10. src/xml/domwalker/slacker.cpp
[ . . . . ] QDomElement Slacker::visit(QDomElement element) { QString name = element.tagName(); QString cvalue = element.attribute("c", QString()) ; if (cvalue != QString()) { element.setAttribute("condition", cvalue); element.setAttribute("c", QString()); } [ . . . . ] if (name == "b") { element.setAttribute("role", "strong"); element.setTagName("emphasis"); return element; } if (name == "li") { QDomNode parent = element.parentNode(); QDomElement listitem = createElement("listitem"); parent.replaceChild(listitem, element); element.setTagName("para"); listitem.appendChild(element); return listitem; } [ . . . . ]
<include src="src/xml/domwalker/slacker.cpp" href="src/xml/domwalker/slacker.cpp" id="slackercpp" mode="cpp"/>
When run, this example pops up a window like Figure 15.5, with two tree views shown side-by-side, letting us inspect the XML documents before and after the transformation.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |