DOM 북마크 애플리케이션
XML 북마크 교환 언어(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 북마크 교환 언어(XBEL) 리소스 페이지를 참조하십시오.
© 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.