DOMブックマークアプリケーション
XML Bookmark Exchange Language(XBEL)ファイル用のリーダーを提供します。
DOMブックマークアプリケーションは、QtのDOMベースのXML APIを使用してXMLブックマーク交換言語(XBEL)ファイルを読み込み、解析するリーダーを提供します。QXmlStreamブックマークの例では、この種のファイルを読み込む別の方法が紹介されています。

XbelTreeクラスの定義
XbelTreeクラスは、ファイルシステムへの読み書きを行う関数を備えています。このクラスはQTreeWidget クラスを継承しており、ブックマークを表示するためのモデルを含み、ブックマークの編集を可能にします。
class XbelTree : public QTreeWidget
{
Q_OBJECT
public:
explicit XbelTree(QWidget *parent = nullptr);
bool read(QIODevice *device);
bool write(QIODevice *device) const;
protected:
#if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
void contextMenuEvent(QContextMenuEvent *event) override;
#endif
private slots:
void updateDomElement(const QTreeWidgetItem *item, int column);
private:
void parseFolderElement(const QDomElement &element,
QTreeWidgetItem *parentItem = nullptr);
QTreeWidgetItem *createItem(const QDomElement &element,
QTreeWidgetItem *parentItem = nullptr);
QDomDocument domDocument;
QIcon folderIcon;
QIcon bookmarkIcon;
};XbelTreeクラスの実装
XbelTree のコンストラクタは、その配置先となるQWidget を受け取ります。folderIcon はQIcon::Normalモードに設定されており、ユーザーがアイコンを操作していない場合にのみピクマップが表示されます。QStyle::SP_DirClosedIcon 、QStyle::SP_DirOpenIcon 、およびQStyle::SP_FileIcon は、GUIのスタイルに従った標準的なピクマップに対応しています。
XbelTree::XbelTree(QWidget *parent)
: QTreeWidget(parent)
{
header()->setSectionResizeMode(QHeaderView::Stretch);
setHeaderLabels({tr("Title"), tr("Location")});
folderIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
QIcon::Normal, QIcon::Off);
folderIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon),
QIcon::Normal, QIcon::On);
bookmarkIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
}read() 関数は、QDomDocument::setContent を使用して指定されたQIODevice を開きます。ファイルの開く操作に成功し、最上位のヘッダーが検証されると、クラスの内容がクリアされた後、すべての最上位XMLノードを反復処理し、それぞれに対してparseFolderElement() を呼び出すことで、ファイルの内容が解析されます。
bool XbelTree::read(QIODevice *device)
{
QDomDocument::ParseResult result =
domDocument.setContent(device, QDomDocument::ParseOption::UseNamespaceProcessing);
if (!result) {
QMessageBox::information(window(), tr("DOM Bookmarks"),
tr("Parse error at line %1, column %2:\n%3")
.arg(result.errorLine)
.arg(result.errorColumn)
.arg(result.errorMessage));
return false;
}
QDomElement root = domDocument.documentElement();
if (root.tagName() != "xbel") {
QMessageBox::information(window(), tr("DOM Bookmarks"),
tr("The file is not an XBEL file."));
return false;
} else if (root.hasAttribute(versionAttribute)
&& root.attribute(versionAttribute) != "1.0"_L1) {
QMessageBox::information(window(), tr("DOM Bookmarks"),
tr("The file is not an XBEL version 1.0 "
"file."));
return false;
}
clear();
disconnect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
QDomElement child = root.firstChildElement(folderElement);
while (!child.isNull()) {
parseFolderElement(child);
child = child.nextSiblingElement(folderElement);
}
connect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
return true;
}parseFolderElement() 関数は、さまざまな要素タイプを処理し、要素がサブフォルダである場合は再帰的に自身を呼び出します。
void XbelTree::parseFolderElement(const QDomElement &element,
QTreeWidgetItem *parentItem)
{
QTreeWidgetItem *item = createItem(element, parentItem);
QString title = element.firstChildElement(titleElement).text();
if (title.isEmpty())
title = tr("Folder");
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setIcon(0, folderIcon);
item->setText(0, title);
bool folded = (element.attribute(foldedAttribute) != "no"_L1);
item->setExpanded(!folded);
constexpr char16_t midDot = u'\xB7';
static const QString dots = QString(30, midDot);
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == folderElement) {
parseFolderElement(child, item);
} else if (child.tagName() == bookmarkElement) {
QTreeWidgetItem *childItem = createItem(child, item);
QString title = child.firstChildElement(titleElement).text();
if (title.isEmpty())
title = tr("Folder");
childItem->setFlags(item->flags() | Qt::ItemIsEditable);
childItem->setIcon(0, bookmarkIcon);
childItem->setText(0, title);
childItem->setText(1, child.attribute(hrefAttribute));
} else if (child.tagName() == "separator"_L1) {
QTreeWidgetItem *childItem = createItem(child, item);
childItem->setFlags(item->flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsEditable));
childItem->setText(0, dots);
}
child = child.nextSiblingElement();
}
}write() 関数は、QDomDocument::saveを使用して、domDocumentを指定されたQIODevice に保存します。
bool XbelTree::write(QIODevice *device) const
{
const int IndentSize = 4;
QTextStream out(device);
domDocument.save(out, IndentSize);
return true;
}MainWindowクラスの定義
MainWindow クラスはQMainWindow のサブクラスであり、File メニューとHelp メニューを持っています。
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
public slots:
void open();
void saveAs();
void about();
private:
void createMenus();
XbelTree *xbelTree;
};MainWindowクラスの実装
MainWindow のコンストラクタは、メンバ変数XbelTreeオブジェクトをインスタンス化し、そのヘッダーにQStringList オブジェクト(labels )を設定します。また、このコンストラクタはcreateMenus() を呼び出してメニューを設定します。statusBar() は、「Ready」というメッセージを表示するために使用されます。
MainWindow::MainWindow()
{
xbelTree = new XbelTree;
setCentralWidget(xbelTree);
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("DOM Bookmarks"));
const QSize availableSize = screen()->availableGeometry().size();
resize(availableSize.width() / 2, availableSize.height() / 3);
}createMenus() 関数は、メニューに項目を追加し、キーボードショートカットを設定します。
void MainWindow::createMenus()
{
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
QAction *openAct = fileMenu->addAction(tr("&Open..."), this, &MainWindow::open);
openAct->setShortcuts(QKeySequence::Open);
QAction *saveAsAct = fileMenu->addAction(tr("&Save As..."), this, &MainWindow::saveAs);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
menuBar()->addSeparator();
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
}open() 関数は、QFileDialog を使用してユーザーがXBELファイルを開けるようにします。ファイルが読み込めない場合や構文解析エラーが発生した場合は、fileName およびerrorString とともに警告メッセージが表示されます。成功した場合は、XbelTree::read() を呼び出します。
void MainWindow::open()
{
QFileDialog fileDialog(this, tr("Open Bookmark File"), QDir::currentPath());
fileDialog.setMimeTypeFilters({"application/x-xbel"_L1});
if (fileDialog.exec() != QDialog::Accepted)
return;
const QString fileName = fileDialog.selectedFiles().constFirst();
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("DOM Bookmarks"),
tr("Cannot read file %1:\n%2.")
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
if (xbelTree->read(&file))
statusBar()->showMessage(tr("File loaded"), 2000);
}saveAs() 関数は、QFileDialog を表示し、ユーザーにfileName の入力を求めます。open() 関数と同様に、この関数もファイルへの書き込みができない場合、警告メッセージを表示します。成功した場合は、XbelTree::write() を呼び出します。
void MainWindow::saveAs()
{
QFileDialog fileDialog(this, tr("Save Bookmark File"), QDir::currentPath());
fileDialog.setAcceptMode(QFileDialog::AcceptSave);
fileDialog.setDefaultSuffix("xbel"_L1);
fileDialog.setMimeTypeFilters({"application/x-xbel"_L1});
if (fileDialog.exec() != QDialog::Accepted)
return;
const QString fileName = fileDialog.selectedFiles().constFirst();
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("DOM Bookmarks"),
tr("Cannot write file %1:\n%2.")
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
if (xbelTree->write(&file))
statusBar()->showMessage(tr("File saved"), 2000);
}about() 関数は、例に関する簡単な説明を添えたQMessageBox を表示します。
void MainWindow::about()
{
QMessageBox::about(this, tr("About DOM Bookmarks"),
tr("The <b>DOM Bookmarks</b> example demonstrates how to "
"use Qt's DOM classes to read and write XML "
"documents."));
}XBEL ファイルの詳細については、「XML Bookmark Exchange Language リソースページ」をご覧ください。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.