#include "parsebridge.h" #include #include #include using namespace bridge; class Impl_NovelParseException : public Config::ParseException { private: QString title_s, reason_s; public: Impl_NovelParseException(const QString &t, const QString &r) { this->title_s = t; this->reason_s = r; } // ParseException interface public: virtual QString reason() const override { return reason_s; } virtual QString title() const override { return reason_s; } }; ParseBridge::ParseBridge() : chains_model(new QStandardItemModel), volumes_model(new QStandardItemModel), errors_model(new QStandardItemModel) {} ParseBridge::~ParseBridge() { delete chains_model; delete volumes_model; delete errors_model; for (auto it : docs_store) delete it; docs_store.clear(); } QString ParseBridge::novelName() const { return name_store; } QStandardItemModel *ParseBridge::volumesPresentModel() const { return volumes_model; } void bridge::ParseBridge::load(const QString &data_path) { // clear cache this->doc_ins.clear(); chains_model->clear(); volumes_model->clear(); errors_model->clear(); for (auto it : docs_store) delete it; docs_store.clear(); // 重新载入小说编译结果 QFileInfo target_xml(data_path); if (!target_xml.exists()) throw new Impl_NovelParseException("小说解析过程错", "指定路径数据文件不存在:" + data_path); QFile data_in(target_xml.canonicalFilePath()); if (!data_in.open(QIODevice::ReadOnly | QIODevice::Text)) throw new Impl_NovelParseException("小说解析过程错", "指定数据文件无法打开:" + target_xml.canonicalFilePath()); QString err_msg; int col, row; if (!this->doc_ins.setContent(&data_in, &err_msg, &row, &col)) { throw new Impl_NovelParseException("小说解析过程我", QString("数据文件格式错:%3").arg(row).arg(col).arg(err_msg)); } // 载入语法节点 auto root = doc_ins.documentElement(); name_store = root.attribute("name", "空白小说名称"); auto childnodes = root.childNodes(); for (auto idx = 0; idx < childnodes.size(); ++idx) { auto child = childnodes.at(idx); if (child.isElement()) { auto elm_inst = child.toElement(); if (elm_inst.tagName() == "doc") { load_document(elm_inst, this->docs_store); } } } } void ParseBridge::load_document(const QDomElement &pdoc, std::vector node_sets) { auto doc_name = pdoc.attribute("name", "未命名文档名"); auto file_path = pdoc.attribute("file"); auto doc_ins = new DocumentInst(doc_name, file_path); node_sets.push_back(doc_ins); // 载入解析错误 auto errors = pdoc.elementsByTagName("error"); for (auto idx = 0; idx < errors.size(); ++idx) { auto e_elm = errors.at(idx).toElement(); load_errors(errorsPresentModel(), e_elm, doc_ins); } auto children = pdoc.childNodes(); for (auto idx = 0; idx < children.size(); ++idx) { auto node = children.at(idx); if (node.isElement()) { load_element(node.toElement(), doc_ins); } } } void ParseBridge::load_element(const QDomElement &telm, DocumentInst *pinst, QStandardItem *pitem) { if (telm.tagName() == "story") load_story(chainsPresentModel(), telm, pinst); else if (telm.tagName() == "text") load_desc(telm, static_cast(pitem)); else if (telm.tagName() == "fragment") load_fragment(telm, pitem); else if (telm.tagName() == "frag-refer") load_frag_refer(telm, pitem); else if (telm.tagName() == "volume") load_volumes(volumesPresentModel(), telm, pinst); else if (telm.tagName() == "article") load_article(telm, pitem); else throw new Impl_NovelParseException("小说解析结果载入错", "位置tagName:" + telm.tagName()); } void ParseBridge::load_errors(QStandardItemModel *anchor, const QDomElement &error_elm, DocumentInst *pinst) { auto pos_value = error_elm.attribute("pos"); auto message = error_elm.attribute("message"); QRegExp exp0("(\\d+)"); auto index = exp0.indexIn(pos_value); auto row = exp0.cap(1).toInt(); exp0.indexIn(pos_value, index + exp0.cap(1).length()); auto col = exp0.cap(1).toInt(); auto perror = new ParseException(pinst); perror->load(message, row, col); QList inst_row; inst_row << perror; inst_row << new SupplyItem(perror); inst_row << new SupplyItem(perror); inst_row << new SupplyItem(perror); anchor->appendRow(inst_row); } #define PEAK_POSITION(e) \ auto start_pos = (e).attribute("start-pos"); \ auto end_pos = (e).attribute("end-pos"); \ QRegExp exp("(\\d+)"); \ auto xidx = exp.indexIn(start_pos); \ auto start_row = exp.cap(1).toInt(); \ exp.indexIn(start_pos, xidx + exp.cap(1).length()); \ auto start_col = exp.cap(1).toInt(); \ xidx = exp.indexIn(end_pos); \ auto end_row = exp.cap(1).toInt(); \ exp.indexIn(start_pos, xidx + exp.cap(1).length()); \ auto end_col = exp.cap(1).toInt(); void ParseBridge::load_story(QStandardItemModel *model, const QDomElement &chain_elm, DocumentInst *pinst) { auto name = chain_elm.attribute("name"); auto index = chain_elm.attribute("sort"); auto story = new StorychainInst(pinst, name); model->appendRow(story); story->indexSet(index.toInt()); PEAK_POSITION(chain_elm); story->loadPos(start_row, start_col, end_row, end_col); auto children = chain_elm.childNodes(); for (auto idx = 0; idx < children.size(); ++idx) { auto node = children.at(idx); if (node.isElement()) { load_element(node.toElement(), nullptr, story); } } } void ParseBridge::load_desc(const QDomElement &desc_elm, ContentNode *pitem) { auto content = desc_elm.attribute("content"); pitem->append(content); } void ParseBridge::load_fragment(const QDomElement &frag_elm, QStandardItem *pinst) { auto name = frag_elm.attribute("name"); auto logic_index = frag_elm.attribute("logic-index"); PEAK_POSITION(frag_elm); auto frag_inst = new StoryfragmentInst(name); pinst->appendRow(frag_inst); frag_inst->setLogicIndex(logic_index.toInt()); frag_inst->loadPos(start_row, start_col, end_row, end_col); auto children = frag_elm.childNodes(); for (auto idx = 0; idx < children.size(); ++idx) { auto node = children.at(idx); if (node.isElement()) { load_element(node.toElement(), nullptr, frag_inst); } } } void ParseBridge::load_frag_refer(const QDomElement &refer_elm, QStandardItem *pitem) { auto story = refer_elm.attribute("story-ref"); auto frag = refer_elm.attribute("fragment-ref"); PEAK_POSITION(refer_elm); auto item = locate_node(chainsPresentModel(), QStringList() << story << frag); auto refer_inst = new StoryfragmentRefer(static_cast(item)); pitem->appendRow(refer_inst); refer_inst->appointStory(story); refer_inst->appointFragment(frag); refer_inst->loadPos(start_row, start_col, end_row, end_col); auto children = refer_elm.childNodes(); for (auto idx = 0; idx < children.size(); ++idx) { auto node = children.at(idx); if (node.isElement()) { load_element(node.toElement(), nullptr, refer_inst); } } } void ParseBridge::load_volumes(QStandardItemModel *model, const QDomElement &volume_elm, DocumentInst *pinst) { auto name = volume_elm.attribute("content"); PEAK_POSITION(volume_elm); auto volume = new StoryvolumeInst(pinst, name); model->appendRow(volume); volume->loadPos(start_row, start_col, end_row, end_col); auto children = volume_elm.childNodes(); for (auto idx = 0; idx < children.size(); ++idx) { auto node = children.at(idx); if (node.isElement()) { load_element(node.toElement(), nullptr, volume); } } } void ParseBridge::load_article(const QDomElement &article_elm, QStandardItem *pitem) { auto name = article_elm.attribute("content"); PEAK_POSITION(article_elm); auto article = new StoryarticleInst(name); pitem->appendRow(article); article->loadPos(start_row, start_col, end_row, end_col); auto children = article_elm.childNodes(); for (auto idx = 0; idx < children.size(); ++idx) { auto node = children.at(idx); if (node.isElement()) { load_element(node.toElement(), nullptr, article); } } } QStandardItem *ParseBridge::locate_node(QStandardItemModel *model, const QStringList path) { QStandardItem *current_item = nullptr; for (auto &n : path) { if (!current_item) { for (auto idx = 0; idx < model->rowCount(); ++idx) { if (model->item(idx)->text() == n) current_item = model->item(idx); } } else { for (auto idx = 0; idx < current_item->rowCount(); ++idx) { if (current_item->child(idx)->text() == n) { current_item = current_item->child(idx); } } } } return current_item; } ParseException::ParseException(DocumentInst *pinst) : key_store(std::make_tuple(pinst, "尚未载入异常信息", 0, 0)) { setText(std::get<1>(key_store)); } void ParseException::load(const QString &message, int row, int col) { this->key_store = std::make_tuple(std::get<0>(key_store), message, row, col); setText(std::get<1>(key_store)); } const DocumentInst *ParseException::doc() const { return std::get<0>(key_store); } QString ParseException::message() const { return std::get<1>(key_store); } int ParseException::row() const { return std::get<2>(key_store); } int ParseException::col() const { return std::get<3>(key_store); } QString ParseException::operator[](int index) { switch (index) { case 0: return message(); case 1: return QString("%1").arg(row()); case 2: return QString("%1").arg(col()); case 3: return QString("%1").arg(doc()->name()); default: return "超出索引范围"; } } DocumentInst::DocumentInst(const QString &name, const QString &path) : n(name), p(path) {} QString DocumentInst::name() const { return n; } QString DocumentInst::path() const { return p; } StorychainInst::StorychainInst(DocumentInst *pinst, const QString &name) : ContentNode(name), pinst_store(pinst) {} void StorychainInst::indexSet(int sort) { this->sort_store = sort; } int StorychainInst::sortIndex() const { return sort_store; } ContentNode::ContentNode(const QString &name) { setText(name); name_store = name; } std::tuple SyntaxNode::startPos() const { return this->start; } std::tuple SyntaxNode::endPos() const { return this->end; } void SyntaxNode::loadPos(int start_r, int start_c, int end_r, int end_c) { this->start = std::make_tuple(start_r, start_c); this->end = std::make_tuple(end_r, end_c); } void ContentNode::append(const QString §ion) { this->desc_sections += section + "\n"; } QString ContentNode::desc() const { return desc_sections; } void ContentNode::clear() { desc_sections = ""; } DocumentInst *StorychainInst::doc() const { return pinst_store; } QString StorychainInst::operator[](int index) { switch (index) { case 0: return text(); case 1: return QString("%1").arg(sortIndex()); case 2: return desc(); default: return "超出索引范围"; } } StoryfragmentInst::StoryfragmentInst(const QString &name) : ContentNode(name) {} int StoryfragmentInst::logicIndex() const { return sort_store; } void StoryfragmentInst::setLogicIndex(int index) { this->sort_store = index; } QString StoryfragmentInst::operator[](int index) { switch (index) { case 0: return text(); case 1: return QString("%1").arg(logicIndex()); case 2: return desc(); default: return "超出有效索引范围"; } } QString StoryfragmentRefer::storyRef() const { return this->story; } void StoryfragmentRefer::appointStory(const QString &ref) { this->story = ref; } QString StoryfragmentRefer::fragmentRef() const { return fragment; } void StoryfragmentRefer::appointFragment(const QString &ref) { fragment = ref; } QString StoryfragmentRefer::operator[](int index) { switch (index) { case 0: return storyRef(); case 1: return fragmentRef(); case 2: return desc(); default: return "超出有效索引范围"; } } StoryvolumeInst::StoryvolumeInst(DocumentInst *inst, const QString &name) : ContentNode(name), doc_store(inst) {} DocumentInst *StoryvolumeInst::doc() const { return doc_store; } QString StoryvolumeInst::operator[](int index) { switch (index) { case 0: return text(); case 1: return desc(); default: return "超出有效索引范围"; } } StoryarticleInst::StoryarticleInst(const QString &name) : ContentNode(name) {} QString StoryarticleInst::operator[](int index) { switch (index) { case 0: return text(); case 1: return desc(); default: return "超出有效索引范围"; } }