How to generate TOC using DOM traversal



  • Qt 5.3.0, win7

    Hi
    Am trying to generate an hierarchical TOC of my html docs embedded in my application's resource tree and later to view the contents using QTreeView; the DOM traversal example does that for the whole html document structure; I want this done only for <h1><h2><h3>, it sounds tricky "recursive" as I could only extract one level for now using the following code:

    @
    QStandardItemMode *TOCModel = new QStandardItemMode(this);
    QStandardItem *parentItem = TOCModel->invisibleRootItem();
    QWebFrame *frame = ui->webView->page()->mainFrame();
    QWebElementCollection subtitles = frame->findAllElements("h4");
    foreach (QWebElement element, subtitles) {
    QStandardItem *item = new QStandardItem(element.toPlainText());
    parentItem->appendRow(item);
    }
    ui->treeView->setModel(TOCModel );
    @

    Is there any hints or perhaps sample of how to do that in less painful way?



  • You do need to do DOM traversal. The full working example below does what you want (naively) using the QtXml framework:

    HTML_TOC.pro
    @
    QT += core gui xml

    TARGET = HTML_TOC
    TEMPLATE = app

    SOURCES += main.cpp
    widget.cpp

    HEADERS += widget.h
    @

    widget.h
    @
    #ifndef WIDGET_H
    #define WIDGET_H

    #include <QtGui/QWidget>

    class QStandardItemModel;
    class QTreeView;

    class Widget : public QWidget
    {
    Q_OBJECT

    public:
    Widget(QWidget *parent = 0);
    ~Widget();

    private:
    QStandardItemModel *model;
    QTreeView *treeView;
    };

    #endif // WIDGET_H
    @

    widget.cpp
    @
    #include "widget.h"

    #include <QtGui>
    #include <QtCore>
    #include <QtXml>

    Widget::Widget(QWidget *parent)
    : QWidget(parent)
    {
    QString html=
    "<!DOCTYPE html>\n"
    "<html>"
    " <head>"
    " <title>Document</title>"
    " </head>"
    " <body>"
    " <h1>Document</h1>"
    " <p>Some text.</p>"
    " <h2>Sub Heading Level 2</h2>"
    " <p>Some more text.</p>"
    " <h3>Sub Heading Level 3</h3>"
    " <p>Yet more text.</p>"
    " <h2>Another Sub Heading Level 2</h2>"
    " <p>Some final text.</p>"
    " </body>"
    "</html>";

    QDomDocument document;
    QString errorMsg;
    int errorLine, errorColumn;
    bool ok=document.setContent(html, false, &errorMsg, &errorLine, &errorColumn);
    if(!ok){
        qDebug() << "Parse Failure:" << errorMsg << errorLine << errorColumn;
        return;
    }
    
    model=new QStandardItemModel(this);
    QStandardItem *parentItem=model->invisibleRootItem();
    
    QDomNodeList bodyElements=document.elementsByTagName("body");
    QDomNode body=bodyElements.at(0);
    Q_ASSERT(body.nodeName()=="body");
    
    int headingLevel=1;
    QDomElement heading=body.firstChildElement("h1");
    
    while(!heading.isNull()){
        QStandardItem *item=new QStandardItem(heading.firstChild().nodeValue());
        parentItem->appendRow(item);
    
        QDomElement next=heading.nextSiblingElement(QString("h%1").arg(headingLevel+1));
        if(!next.isNull()) {
            headingLevel+=1;
            parentItem=item;
        }
        else{
            next=heading.nextSiblingElement(QString("h%1").arg(headingLevel));
            if(next.isNull()&&headingLevel>1){
                headingLevel-=1;
                next=heading.nextSiblingElement(QString("h%1").arg(headingLevel));
                parentItem=parentItem->parent();
            }
        }
        heading=next;
    }
    
    treeView=new QTreeView(this);
    treeView->setModel(model);
    
    QVBoxLayout *l=new QVBoxLayout(this);
    l->addWidget(treeView);
    

    }

    Widget::~Widget(){}
    @

    main.cpp
    @
    #include <QtGui/QApplication>
    #include "widget.h"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec&#40;&#41;;
    

    }
    @

    Hope this helps ;o)



  • Hi jazzycamel

    This is generous!
    Thank you very much.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.