15.3.1.  DOM Tree Walking

[ fromfile: xml-dom.xml id: domtreewalking ]

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);             1
    QDomNode before = doc.cloneNode(true);      2
    Slacker slack(doc);                         3
    QDomNode after = slack.transform();         4
    cout << QString("Before: ") << before << endl;
    cout << QString("After: ") << after << endl;
    QWidget * view = twinview(before, after);   5
    view->show();
    app.exec();
    delete view;
}
[ . . . . ]

1

Parse the file into a DOM tree, and store tree in empty doc.

2

Deep copy.

3

Send the tree to slack.

4

Start the visitation.

5

Create a pair of QTreeView objects separated by slider, using the QDomDocuments as models.


Figure 15.4.  Domwalker and Slacker

Domwalker and Slacker

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();             1
    for (int i=dnl.count()-1; i >=0; --i)
        walkTree(dnl.item(i));
    if (current.nodeType() == QDomNode::ElementNode) {   2
       QDomElement ce = current.toElement();             3
       return visit(ce);
    }
    return current;
}
[ . . . . ]

1

First process children recursively.

2

Only process elements, leaving other nodes unchanged.

3

Instead of a typecast.


[Tip]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).

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()) {                  1
        element.setAttribute("condition", cvalue);
        element.setAttribute("c", QString());
    }
    [ . . . . ]
    if (name == "b") {
        element.setAttribute("role", "strong");
        element.setTagName("emphasis");
        return element;
    }
    if (name == "li") {                         2
        QDomNode parent = element.parentNode();
        QDomElement listitem = createElement("listitem");
        parent.replaceChild(listitem, element); 3
        element.setTagName("para");             4
        listitem.appendChild(element);
        return listitem;
    }
    [ . . . . ]

1

Modifying attributes - any c= becomes condition=

2

This transformation is more interesting because we replace <li> text </li> with <listitem><para> text </para></listitem>.

3

Remove the li tag, put a listitem in its place.

4

Modify tag name in-place.


Figure 15.5.  XML Tree Views

XML Tree Views