#include "xast_parse.h" using namespace xast_parse; using namespace std; __SiblingImpl::__SiblingImpl(SliceType t, shared_ptr pnode) : t_store(t), parent_store(pnode) { } SliceType __SiblingImpl::type() const { return t_store; } weak_ptr __SiblingImpl::parentSlice() const { return this->parent_store; } void __SiblingImpl::setPrev(shared_ptr inst) { this->prev_store = inst; } weak_ptr __SiblingImpl::prevSlice() const { return this->prev_store; } void __SiblingImpl::setNext(shared_ptr next) { if (this->next_store) { this->next_store->setPrev(next); next->setNext(this->next_store); } next->setPrev(this->shared_from_this()); this->next_store = next; } shared_ptr __SiblingImpl::nextSlice() const { return this->next_store; } uint __SiblingImpl::index() const { uint v_index = 0; auto temp_node = this->prevSlice(); while (temp_node.lock()) { v_index++; temp_node = temp_node.lock()->prevSlice(); } return v_index; } TextParagraph::TextParagraph(shared_ptr parent) : __SiblingImpl(SliceType::TextPragraph, parent) { } void TextParagraph::setLines(const QString& contents) { this->lines = contents.split('\n'); } QString TextParagraph::getLines() const { return lines.join('\n'); } void TextParagraph::addLine(const QString& line) { this->lines << line; } QList TextParagraph::nameSet() const { return parentSlice().lock()->nameSet() << "$$"; } StoryDefine::StoryDefine(const QString& name, uint sort, const QString& path) :__CollectionElement(SliceType::StoryDefines, nullptr), name_store(name), sort_store(sort), file_path(path) { } QString StoryDefine::name() const { return this->name_store; } QString xast_parse::StoryDefine::bindPath() const { return file_path; } shared_ptr StoryDefine::getFragment(const QString& name) { auto temp_node = this->firstChild(); while (temp_node) { if (temp_node->type() == SliceType::FragmentDefines) { if (dynamic_pointer_cast(temp_node)->name() == name) return temp_node; } temp_node = temp_node->nextSlice(); } return nullptr; } QList StoryDefine::nameSet() const { return QList() << name(); } uint StoryDefine::index() const { return this->sort_store; } PointDefines::PointDefines(const QString& name, shared_ptr pnode) : __DesElement(SliceType::FragmentDefines, static_pointer_cast(pnode)), name_store(name) { } QString PointDefines::name() const { return name_store; } QList> PointDefines::referSlices() const { return this->refs_list; } void PointDefines::appendRefer(shared_ptr slice) { if (this->refs_list.contains(slice)) return; this->refs_list << slice; } QList PointDefines::nameSet() const { return parentSlice().lock()->nameSet() << name(); } __CollectionElement::__CollectionElement(SliceType t, shared_ptr pnode) :__SiblingImpl(t, pnode) { } shared_ptr __CollectionElement::firstChild() const { return this->first_head; } void __CollectionElement::setFirstChild(shared_ptr inst) { this->first_head = inst; } __DesElement::__DesElement(SliceType t, shared_ptr pnode) : __SiblingImpl(t, pnode) { } shared_ptr __DesElement::getTextNode() const { if (!text_store) const_cast<__DesElement*>(this)->text_store = make_shared( const_pointer_cast<__SiblingImpl>(this->shared_from_this())); return text_store; } FragmentRefer::FragmentRefer(const QString& story, const QString& fragm, shared_ptr pnode) : __DesElement(SliceType::PointRefers, pnode), story_refers(story), fragment_refers(fragm) { } QString FragmentRefer::storyRefer() const { return this->story_refers; } QString FragmentRefer::fragmentRefer() const { return this->fragment_refers; } weak_ptr FragmentRefer::referTarget() const { return this->refer_targets; } void FragmentRefer::setReferTowards(shared_ptr target) { this->refer_targets = target; } QList FragmentRefer::nameSet() const { return parentSlice().lock()->nameSet() << "@" + storyRefer() << fragmentRefer(); } ArticleDefine::ArticleDefine(const QString& name, shared_ptr pnode) : __CollectionElement(SliceType::ArticleDefines, pnode), name_store(name) { } QString ArticleDefine::name() const { return name_store; } QList ArticleDefine::nameSet() const { return parentSlice().lock()->nameSet() << name(); } VolumeDefine::VolumeDefine(const QString& name, const QString& path) : __CollectionElement(SliceType::VolumeDefines, nullptr), name_store(name), file_path(path) { } QString VolumeDefine::name() const { return name_store; } QString VolumeDefine::bindPath() const { return file_path; } QList VolumeDefine::getArticleNames() const { QList names; auto first_elm = this->firstChild(); while (first_elm) { if (first_elm->type() == SliceType::ArticleDefines) { names << static_pointer_cast(first_elm)->name(); } first_elm = first_elm->nextSlice(); } return names; } shared_ptr VolumeDefine::getArticleWith(const QString& name) const { auto temp_elm = this->firstChild(); while (temp_elm) { if (temp_elm->type() == SliceType::ArticleDefines) { auto conv_elm = static_pointer_cast(temp_elm); if (conv_elm->name() == name) { return conv_elm; } } temp_elm = temp_elm->nextSlice(); } return nullptr; } QList VolumeDefine::nameSet() const { return QList() << name(); } XAST_Parser::XAST_Parser(const QString& ast_path) { QFile ast_file(ast_path); if (!ast_file.open(QIODevice::Text | QIODevice::ReadOnly)) throw new exception("无法打开指定文件:" + ast_path.toLocal8Bit()); this->dom_tree.setContent(&ast_file); auto ranks = this->dom_tree.elementsByTagName(u8"rank"); for (auto idx = 0; idx < ranks.size(); ++idx) { auto re = ranks.at(idx).toElement(); auto path = re.attribute(u8"doc-path"); auto rankv = re.attribute(u8"rank"); auto inst = std::make_shared(path, rankv); this->rank_coll.append(inst); } auto nodes = this->dom_tree.elementsByTagName(u8"story"); for (auto idx = 0; idx < nodes.size(); ++idx) { auto nd = nodes.at(idx); auto sinst = this->init_story_define(nd.toElement()); story_dict[sinst->name()] = sinst; } nodes = this->dom_tree.elementsByTagName(u8"volume"); for (auto idx = 0; idx < nodes.size(); ++idx) { auto nd = nodes.at(idx); auto vinst = this->init_volume_define(nd.toElement()); volume_dict[vinst->name()] = vinst; } for (auto sit : story_dict.values()) { this->fragments_plait(story_dict, sit); } for (auto vit : volume_dict.values()) { this->fragments_plait(story_dict, vit); } ast_file.close(); } QList> XAST_Parser::rankList() const { return rank_coll; } QHash> XAST_Parser::storyGraph() const { return story_dict; } QHash> XAST_Parser::volumeGraph() const { return volume_dict; } void xast_parse::XAST_Parser::output(const QDir& dir) { for (auto& r : this->rankList()) { this->write_rank(r, dir); } for (auto& s : this->storyGraph()) { this->write_story(s, dir); } for (auto& v : this->volumeGraph()) { this->write_volume(v, dir); } } shared_ptr XAST_Parser::init_story_define(const QDomElement& story_e) { auto s_name = story_e.attribute(u8"name"); auto s_sort = story_e.attribute(u8"sort").toUInt(); auto s_path = story_e.attribute(u8"file-path"); auto inst = make_shared(s_name, s_sort, s_path); QList elms_list; auto temp_elm = story_e.firstChildElement(); while (!temp_elm.isNull()) { if (temp_elm.tagName() != u8"tokens") elms_list << temp_elm; temp_elm = temp_elm.nextSiblingElement(); } shared_ptr temporary_ptr = nullptr; while (elms_list.size()) { shared_ptr current_ptr = nullptr; auto text_count = this->text_sections_count(elms_list); if (text_count) { current_ptr = this->text_paragraph_build(inst, elms_list, text_count); } else if (elms_list.at(0).tagName() == u8"fragment") { current_ptr = this->fragment_define_build(inst, elms_list.at(0)); elms_list.takeFirst(); } else if (elms_list.at(0).tagName() == u8"refer") { current_ptr = this->fragment_refer_build(inst, elms_list.at(0)); elms_list.takeFirst(); } if (!temporary_ptr) { inst->setFirstChild(current_ptr); } else { temporary_ptr->setNext(current_ptr); } temporary_ptr = current_ptr; } return inst; } uint XAST_Parser::text_sections_count(const QList& elms) { uint count = 0; for (auto enode : elms) { if (enode.tagName() != u8"text-section") break; count++; } return count; } shared_ptr XAST_Parser::text_paragraph_build(shared_ptr<__CollectionElement> pnode, QList& elms, uint count) { auto inst = make_shared(pnode); for (uint idx = 0; idx < count; ++idx) { auto telm = elms.takeAt(0); auto line = telm.attribute(u8"text"); inst->addLine(line); } return inst; } shared_ptr XAST_Parser::fragment_define_build(shared_ptr pnode, const QDomElement& e) { auto fname = e.attribute(u8"name"); auto fragm = make_shared(fname, pnode); auto temp_elm = e.firstChildElement(); while (!temp_elm.isNull()) { if (temp_elm.tagName() == u8"text-section") { auto line = temp_elm.attribute(u8"text"); fragm->getTextNode()->addLine(line); } temp_elm = temp_elm.nextSiblingElement(); } return fragm; } shared_ptr XAST_Parser::fragment_refer_build(shared_ptr<__CollectionElement> pnode, const QDomElement& e) { auto story_ref = e.attribute(u8"story"); auto fragm_ref = e.attribute(u8"fragment"); auto fragmemt_refi = make_shared(story_ref, fragm_ref, pnode); auto temp_node = e.firstChildElement(); while (!temp_node.isNull()) { if (temp_node.tagName() == u8"text-section") { auto line = temp_node.attribute(u8"text"); fragmemt_refi->getTextNode()->addLine(line); } temp_node = temp_node.nextSiblingElement(); } return fragmemt_refi; } void XAST_Parser::fragments_plait(QHash> story_map, shared_ptr reflist) { auto slice = reflist->firstChild(); while (slice) { if (slice->type() == SliceType::PointRefers) { auto refer_inst = static_pointer_cast(slice); auto story_target = story_map[refer_inst->storyRefer()]; auto fragm_target = story_target->getFragment(refer_inst->fragmentRefer()); auto fragm_cast = static_pointer_cast(fragm_target); fragm_cast->appendRefer(refer_inst); refer_inst->setReferTowards(fragm_cast); } switch (slice->type()) { case SliceType::StoryDefines: case SliceType::VolumeDefines: case SliceType::ArticleDefines: this->fragments_plait(story_map, static_pointer_cast<__CollectionElement>(slice)); break; default: break; } slice = slice->nextSlice(); } } shared_ptr XAST_Parser::init_volume_define(const QDomElement& volume_e) { auto v_name = volume_e.attribute(u8"name"); auto v_path = volume_e.attribute(u8"file-path"); auto inst = make_shared(v_name, v_path); QList node_list; auto temp_node = volume_e.firstChildElement(); while (!temp_node.isNull()) { if (temp_node.tagName() != u8"tokens") node_list << temp_node; temp_node = temp_node.nextSiblingElement(); } shared_ptr temporary_ptr = nullptr; while (node_list.size()) { shared_ptr current_ptr = nullptr; auto text_count = this->text_sections_count(node_list); if (text_count) { current_ptr = this->text_paragraph_build(inst, node_list, text_count); } else if (node_list.at(0).tagName() == u8"article") { current_ptr = this->init_article_define(inst, node_list.at(0)); node_list.takeFirst(); } if (!temporary_ptr) { inst->setFirstChild(current_ptr); } else { temporary_ptr->setNext(current_ptr); } temporary_ptr = current_ptr; } return inst; } shared_ptr XAST_Parser::init_article_define(shared_ptr pnode, const QDomElement& article_e) { auto a_name = article_e.attribute(u8"name"); auto inst = make_shared(a_name, pnode); QList node_list; auto temp_node = article_e.firstChildElement(); while (!temp_node.isNull()) { if (temp_node.tagName() != u8"tokens") node_list << temp_node; temp_node = temp_node.nextSiblingElement(); } shared_ptr temporary_ptr = nullptr; while (node_list.size()) { shared_ptr current_ptr = nullptr; auto text_count = this->text_sections_count(node_list); if (text_count) { current_ptr = this->text_paragraph_build(inst, node_list, text_count); } else if (node_list.at(0).tagName() == u8"refer") { current_ptr = this->fragment_refer_build(inst, node_list.at(0)); node_list.takeFirst(); } if (!temporary_ptr) { inst->setFirstChild(current_ptr); } else { temporary_ptr->setNext(current_ptr); } temporary_ptr = current_ptr; } return inst; } #include #include #include void xast_parse::XAST_Parser::write_rank(std::shared_ptr inst, const QDir& odir) { auto fname = inst->bindPath(); QFile target_file(odir.filePath(fname)); if (!target_file.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::critical(nullptr, "文件操作", odir.filePath(fname) + "无法打开!"); QCoreApplication::exit(0); return; } QTextStream o(&target_file); o.setCodec("UTF-8"); o << QString(u8"#排序 ") << inst->rank() << endl; } void xast_parse::XAST_Parser::write_story(std::shared_ptr inst, const QDir& odir) { auto fname = inst->bindPath(); QFile target_file(odir.filePath(fname)); if (!target_file.open(QIODevice::Append | QIODevice::Text)) { QMessageBox::critical(nullptr, "文件操作", odir.filePath(fname) + "无法打开!"); QCoreApplication::exit(0); return; } QTextStream o(&target_file); o.setCodec("UTF-8"); o << QString(u8"{故事 ") << inst->name() << "\n"; auto temp = inst->firstChild(); while (temp) { switch (temp->type()) { case SliceType::TextPragraph: this->write_text(1, std::dynamic_pointer_cast(temp), o); break; case SliceType::FragmentDefines: this->write_fragmdef(1, std::dynamic_pointer_cast(temp), o); break; case SliceType::PointRefers: this->write_fragmref(1, std::dynamic_pointer_cast(temp), o); break; default: break; } temp = temp->nextSlice(); } o << QString(u8"}\n"); } void xast_parse::XAST_Parser::write_text(int dep, std::shared_ptr inst, QTextStream& out) { auto text = inst->getLines(); text.replace("\n", "\n" + QString(dep * 2, ' ')); out << QString(dep * 2, ' ') << text << "\n"; } void xast_parse::XAST_Parser::write_fragmdef(int dep, std::shared_ptr inst, QTextStream& out) { out << QString(dep * 2, ' ') << QString(u8"{情节 %1\n").arg(inst->name()); this->write_text(dep + 1, inst->getTextNode(), out); out << QString(dep * 2, ' ') << QString(u8"}\n"); } void xast_parse::XAST_Parser::write_fragmref(int dep, std::shared_ptr inst, QTextStream& out) { out << QString(dep * 2, ' ') << QString(u8"{@情节 %1&%2\n").arg(inst->fragmentRefer(), inst->storyRefer()); this->write_text(dep + 1, inst->getTextNode(), out); out << QString(dep * 2, ' ') << QString(u8"}\n"); } void xast_parse::XAST_Parser::write_volume(std::shared_ptr inst, const QDir& odir) { auto fname = inst->bindPath(); QFile target_file(odir.filePath(fname)); if (!target_file.open(QIODevice::Append | QIODevice::Text)) { QMessageBox::critical(nullptr, "文件操作", odir.filePath(fname) + "无法打开!"); QCoreApplication::exit(0); return; } QTextStream o(&target_file); o.setCodec("UTF-8"); o << QString(u8"{分卷 %1\n").arg(inst->name()); auto temp = inst->firstChild(); while (temp) { switch (temp->type()) { case SliceType::TextPragraph: this->write_text(1, std::dynamic_pointer_cast(temp), o); break; case SliceType::ArticleDefines: this->write_article(1, std::dynamic_pointer_cast(temp), o); break; default: break; } temp = temp->nextSlice(); } o << QString(u8"}\n"); } void xast_parse::XAST_Parser::write_article(int dep, std::shared_ptr inst, QTextStream& out) { out << QString(u8"%1{章节 %2\n").arg(QString(dep * 2, ' '), inst->name()); auto temp = inst->firstChild(); while (temp) { switch (temp->type()) { case SliceType::TextPragraph: this->write_text(dep + 1, std::dynamic_pointer_cast(temp), out); break; case SliceType::PointRefers: this->write_fragmref(dep + 1, std::dynamic_pointer_cast(temp), out); break; default: break; } temp = temp->nextSlice(); } out << QString(u8"%1}\n").arg(QString(dep * 2, ' ')); } RankDecs::RankDecs(const QString& path, const QString& rank) :fpath(path), rank_v(rank) { } QString RankDecs::bindPath() const { return fpath; } QString RankDecs::rank() const { return rank_v; }