diff --git a/.gitignore b/.gitignore index ec28322..3e076b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ */x64/* .vs/* x64/* +*/bin/* +*/obj/* \ No newline at end of file diff --git a/ArgsParser/argsparser.cpp b/ArgsParser/argsparser.cpp index e1dd2e5..67f586f 100644 --- a/ArgsParser/argsparser.cpp +++ b/ArgsParser/argsparser.cpp @@ -132,7 +132,7 @@ int MatchMode::modeCode() const { return code_store; } -QString MatchMode::usageString() const { +QString MatchMode::usagestring() const { QString usage_string; for (auto& item : args_mode) usage_string += item->placeHolder() + " "; @@ -140,7 +140,7 @@ QString MatchMode::usageString() const { return usage_string; } -QString MatchMode::explanString() const { +QString MatchMode::explanstring() const { QStringList sections; sections << " " + _means_explain; sections << QString(" Switch:"); @@ -235,8 +235,8 @@ std::shared_ptr MatchMode::getUnitViaInitIndex(int pos) { QString ArgsParser::helperDoc() const { QString help_string; for (auto& mode : this->match_modes) { - help_string += "Usage:" + mode->usageString() + "\n"; - help_string += mode->explanString() + "\n\n"; + help_string += "Usage:" + mode->usagestring() + "\n"; + help_string += mode->explanstring() + "\n\n"; } return help_string; } diff --git a/ArgsParser/argsparser.h b/ArgsParser/argsparser.h index de9ced6..9e1a637 100644 --- a/ArgsParser/argsparser.h +++ b/ArgsParser/argsparser.h @@ -162,14 +162,14 @@ namespace args_parse { * * \return */ - QString usageString() const; + QString usagestring() const; /** * 返回模式解析字符串. * * \return */ - QString explanString() const; + QString explanstring() const; /** * 添加参数解析单元. diff --git a/AstConv/AstConv.fsproj b/AstConv/AstConv.fsproj new file mode 100644 index 0000000..303d6bd --- /dev/null +++ b/AstConv/AstConv.fsproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + + + + + + + + + diff --git a/AstConv/AstImport.fs b/AstConv/AstImport.fs new file mode 100644 index 0000000..fc80e6c --- /dev/null +++ b/AstConv/AstImport.fs @@ -0,0 +1,366 @@ +namespace AstAccess + +open System.Xml +open System.Linq + + module AstImport = + /// 带有地址的对象 + type AstObject() = + class + member this.address() = string(this.GetHashCode ()) + + abstract member members:unit -> AstObject list + default this.members(): AstObject list = [] + end + + let rec branch_map_conv (pnode: AstObject, childs: AstObject list) = + match childs with + | [] -> [] + | _ -> + let head = childs.Head + (head.address(), (head, pnode))::branch_map_conv(pnode, childs.Tail)@branch_map_conv(head, head.members()) + + let rec depth_seek(branchs: (string*(AstObject*AstObject))list, node: AstObject): int = + let prev_nodes = branchs |> List.filter(fun (key, _) -> key.Equals(node.address())) + match prev_nodes.Length with + | 0 -> 0 + | _ -> + let (_, (_, parent_node)) = prev_nodes.Head + depth_seek(branchs, parent_node) + 1 + + /// TextWord + type TextItem(bind: XmlElement) = + class + inherit AstObject() + member this.content():string = + bind.GetAttribute "text" + + member this.row():int = + let tokens_node = bind.ChildNodes.Cast().Where( + fun node -> node.Name.Equals "tokens").ElementAt(0) + let token_bind = tokens_node.ChildNodes.Cast().ElementAt(0) + int(token_bind.GetAttribute "row") + + static member GenerateText(text_opt: XmlNode): Option = + match text_opt with + | :? XmlElement as obj_t when obj_t.Name.Equals "text-section" -> + Some(TextItem(obj_t)) + | _ -> None + end + + /// 引用节点 + type PointRef(bind: XmlElement, texts: TextItem list) = + class + inherit AstObject() + new(bind: XmlElement) = PointRef(bind, []) + + member this.pointRef() = + bind.GetAttribute "point" + member this.sliceRef() = + bind.GetAttribute "slice" + member this.storyRef() = + bind.GetAttribute "story" + member this.appendChild(objs: TextItem list) = + PointRef(bind, texts@objs) + member this.children() = + texts + + override this.members(): AstObject list = + texts |> List.map (fun it->it :> AstObject) + + static member GenerateFromChildSibling(child: XmlNode): TextItem list = + match child with + | null -> [] + | _ -> + match TextItem.GenerateText(child) with + | Some text -> text::PointRef.GenerateFromChildSibling(child.NextSibling) + | None -> PointRef.GenerateFromChildSibling(child.NextSibling) + + static member GeneratePointRef(ref_opt: XmlNode): Option = + match ref_opt with + | :? XmlElement as refo when refo.Name.Equals "refer" -> + let text_objects = PointRef.GenerateFromChildSibling(refo.FirstChild) + Some(PointRef(refo, text_objects)) + | _ -> None + end + + /// 定义节点 + type PointDef(bind: XmlElement, texts: TextItem list) = + class + inherit AstObject() + new(bind: XmlElement) = PointDef(bind, []) + + member this.name() = + bind.GetAttribute "name" + member this.appendChild(t: TextItem) = + PointDef(bind, texts@[t]) + member this.children() = + texts + + override this.members(): AstObject list = + texts |> List.map (fun it->it :> AstObject) + + static member GenerateFromChildSibling(child: XmlNode): TextItem list = + match child with + | null -> [] + | _ -> + match TextItem.GenerateText(child) with + | Some text -> text::PointDef.GenerateFromChildSibling(child.NextSibling) + | None -> PointDef.GenerateFromChildSibling(child.NextSibling) + + static member GeneratePointDef(def_opt: XmlNode) : Option = + match def_opt with + | :? XmlElement as defo when defo.Name.Equals "point" -> + let text_objs = PointDef.GenerateFromChildSibling(defo.FirstChild) + Some(PointDef(defo, text_objs)) + | _ -> None + + end + + type SliceChildType = |Text of TextItem |Define of PointDef |Refer of PointRef + /// 情节节点 + type SliceDef(bind: XmlElement, objs: AstObject list) = + class + inherit AstObject() + new(bind: XmlElement) = SliceDef(bind, []) + + member this.name() = + bind.GetAttribute "name" + member this.appendChild(o: SliceChildType) = + match o with + | Text t -> SliceDef(bind, objs@[t]) + | Define d -> SliceDef(bind, objs@[d]) + | Refer r -> SliceDef(bind, objs@[r]) + member this.children() = objs + + override this.members(): AstObject list = objs + + static member GenerateFromChildSibling(child: XmlNode): SliceChildType list = + match child with + | null -> [] + | _ -> + let h = match child.Name with + | "text-section" -> Some(Text(TextItem.GenerateText(child).Value)) + | "refer" -> Some(Refer(PointRef.GeneratePointRef(child).Value)) + | "point" -> Some(Define(PointDef.GeneratePointDef(child).Value)) + | _ -> None + + match h with + | Some value -> value::SliceDef.GenerateFromChildSibling(child.NextSibling) + | _ -> SliceDef.GenerateFromChildSibling(child.NextSibling) + + static member GenerateSliceDef(slice_opt: XmlNode): Option = + match slice_opt with + | :? XmlElement as slice when slice.Name.Equals "slice" -> + let mbrs = SliceDef.GenerateFromChildSibling(slice.FirstChild) + let objs = mbrs |> List.map ( + fun o-> match o with + |Define defs -> defs :> AstObject + |Refer refs -> refs :> AstObject + |Text text -> text :> AstObject + ) + Some(SliceDef(slice, objs)) + | _ -> None + end + + type StoryChildType = |Text of TextItem |Slice of SliceDef + /// 故事节点 + type StoryDef(bind: XmlElement, objs: AstObject list) = + class + inherit AstObject() + new(bind: XmlElement) = StoryDef(bind, []) + + member this.name() = + bind.GetAttribute "name" + member this.sort() = + int(bind.GetAttribute "sort") + member this.appendChild(o: StoryChildType) = + match o with + |Text t -> StoryDef(bind, objs@[t]) + |Slice s -> StoryDef(bind, objs@[s]) + member this.children() = objs + + override this.members(): AstObject list = objs + + static member GenerateFromChildSibling(child: XmlNode): StoryChildType list = + match child with + | null -> [] + | _ -> + let h = match child.Name with + | "text-section" -> Some(Text(TextItem.GenerateText(child).Value)) + | "slice" -> Some(Slice(SliceDef.GenerateSliceDef(child).Value)) + | _->None + match h with + | Some value -> value::StoryDef.GenerateFromChildSibling(child.NextSibling) + | _ -> StoryDef.GenerateFromChildSibling(child.NextSibling) + + static member GenerateStoryDef(story_opt: XmlNode): Option = + match story_opt with + | :? XmlElement as story when story.Name.Equals "story" -> + let children = StoryDef.GenerateFromChildSibling(story.FirstChild) + let objs = children |> List.map ( + fun x -> + match x with + |Text valx -> valx :> AstObject + |Slice valx -> valx :> AstObject + ) + Some(StoryDef(story, objs)) + | _ -> None + end + + type ArticleChildType = |Text of TextItem |Refer of PointRef + /// 章节节点 + type ArticleDef(bind: XmlElement, objs: AstObject list) = + class + inherit AstObject() + new(bind: XmlElement) = ArticleDef(bind, []) + + member this.name() = + bind.GetAttribute "name" + member this.children() = objs + member this.appendChild(o: ArticleChildType list) = + let conv item = match item with + |Text t -> t :> AstObject + |Refer r -> r :> AstObject + + let items = o |> List.map conv + ArticleDef(bind, objs@items) + + override this.members(): AstObject list = objs + + static member GenerateFromChildSibling(child: XmlNode): ArticleChildType list = + match child with + | null -> [] + | _ -> + let data = match child.Name with + | "text-section" -> Some(Text(TextItem.GenerateText(child).Value)) + | "refer" -> Some(Refer(PointRef.GeneratePointRef(child).Value)) + | _ -> None + match data with + | Some value -> value::ArticleDef.GenerateFromChildSibling(child.NextSibling) + | None -> ArticleDef.GenerateFromChildSibling(child.NextSibling) + + static member GenerateArticleDef(article_opt: XmlNode): Option = + match article_opt with + | :? XmlElement as article when article.Name.Equals "article" -> + let mbrs = ArticleDef.GenerateFromChildSibling(article.FirstChild) + let conv it = match it with + |Text v -> v :> AstObject + |Refer v -> v:> AstObject + Some(ArticleDef(article, mbrs |> List.map conv)) + | _ -> None + end + + type VolumeChildType = |Text of TextItem |Article of ArticleDef + /// 卷宗节点 + type VolumeDef(bind: XmlElement, objs: AstObject list) = + class + inherit AstObject() + new(bind: XmlElement) = VolumeDef(bind, []) + + member this.name() = + bind.GetAttribute "name" + member this.children() = objs + member this.appendChild(o: VolumeChildType list) = + let items = o |> List.map ( + fun it-> + match it with + |Text t -> t :> AstObject + |Article a -> a :> AstObject + ) + VolumeDef(bind, objs@items) + + override this.members(): AstObject list = objs + + static member GenerateFromChildSibling(child: XmlNode): VolumeChildType list = + match child with + | null -> [] + | _ -> + let data = match child.Name with + | "text-section" -> Some(Text(TextItem.GenerateText(child).Value)) + | "article" -> Some(Article(ArticleDef.GenerateArticleDef(child).Value)) + | _ -> None + match data with + | Some value -> value::VolumeDef.GenerateFromChildSibling(child.NextSibling) + | None -> VolumeDef.GenerateFromChildSibling(child.NextSibling) + + static member GenerateVolumeDef(vol_opt: XmlNode): Option = + match vol_opt with + | :? XmlElement as volume when volume.Name.Equals "volume" -> + let mbrs = VolumeDef.GenerateFromChildSibling(volume.FirstChild) + let conv data = match data with + |Text d -> d :> AstObject + |Article d -> d:> AstObject + Some(VolumeDef(volume, mbrs |> List.map conv)) + | _ -> None + + + end + + type ProgramChildType = |Volume of VolumeDef |Story of StoryDef + /// 程序节点 + type Program(bind: XmlElement, objs: AstObject list) = + class + inherit AstObject() + new(bind: XmlElement) = Program(bind, []) + + member this.time() = + bind.GetAttribute "time" + member this.children() = objs + member this.appendChild(o: ProgramChildType list) = + let items = o |> List.map (fun it-> + match it with + |Story s -> s :> AstObject + |Volume v -> v :> AstObject + ) + Program(bind, objs @items) + + override this.members(): AstObject list = objs + + static member GenerateFromChildSibling(child: XmlNode): ProgramChildType list = + match child with + | null -> [] + | _ -> + let d = match child.Name with + | "volume" -> Some(Volume(VolumeDef.GenerateVolumeDef(child).Value)) + | "story" -> Some(Story(StoryDef.GenerateStoryDef(child).Value)) + | _ -> None + match d with + |Some value -> value::Program.GenerateFromChildSibling(child.NextSibling) + |None -> Program.GenerateFromChildSibling(child.NextSibling) + + static member GenerateFrom(doc: XmlDocument) = + let ast = doc.DocumentElement + + let mbrs = Program.GenerateFromChildSibling(ast.FirstChild) + let conv data = match data with + |Volume d -> d:>AstObject + |Story d -> d :> AstObject + Program(ast, mbrs |> List.map conv) + end + + + type AstVisitor = + interface + abstract member visit:AstObject -> bool + end + + type AstVisitEntry(root: AstObject) = + class + /// 1:node + /// 2: node + /// 2: node + /// 3: node + /// 4: node + /// ...... + member private this.visit_internal(nodes: AstObject list, visitor: AstVisitor): bool = + match nodes.Length with + | 0 -> true + | _ -> + this.visit_internal(nodes.Head.members(), visitor) && visitor.visit(nodes.Head) && this.visit_internal(nodes.Tail, visitor) + + + member this.visitWith(visitor: AstVisitor): bool = + this.visit_internal([root], visitor) + + end \ No newline at end of file diff --git a/AstConv/HtmlStruct.fs b/AstConv/HtmlStruct.fs new file mode 100644 index 0000000..eb4761b --- /dev/null +++ b/AstConv/HtmlStruct.fs @@ -0,0 +1,266 @@ +namespace HtmlStruct + +open AstAccess +open System.Xml +open System + + module Present = + /// 可访问元素 + type Access(hrefs: string) = + class + member this.accessLink(): string = + hrefs + end + + /// 回退访问元素 + type Backward(hrefs: string) = + class + member this.backwardLink(): string = + hrefs + end + + /// 内容元素:分卷、章节、引用节点、故事线、情节、定义节点、引用节点 + type IDomUnit = + interface + abstract member name:unit -> string + abstract member getHtml:XmlElement -> XmlElement + end + + /// 容器节点:分卷、章节、故事线、情节 + type IContainer = + interface + abstract member append:List -> IContainer + end + + /// 访问页面:概括页面、卷宗页面、故事线页面、节点汇总 ================================================= + type VolumePage(page_hrefs: string, volume: IDomUnit, childs: List) = + class + inherit Access(page_hrefs) + new(page_hrefs, volume) = VolumePage(page_hrefs, volume, []) + + interface IDomUnit with + member this.name():string = + volume.name() + member this.getHtml(p: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface IContainer with + member this.append(childs: List): IContainer = + raise (System.NotImplementedException()) + end + + type StoryPage(page_hrefs: string, story: IDomUnit, childs: List) = + class + inherit Access(page_hrefs) + new(page_hrefs, story) = StoryPage(page_hrefs, story, []) + + interface IDomUnit with + member this.name():string = + story.name() + member this.getHtml(p: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface IContainer with + member this.append(childs: List): IContainer = + raise (System.NotImplementedException()) + end + + type PointPage(page_hrefs: string, point: IDomUnit, refer_list: List) = + class + inherit Access(page_hrefs) + new(page_hrefs, point) = PointPage(page_hrefs, point, []) + + interface IDomUnit with + member this.name():string = + point.name() + member this.getHtml(p: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface IContainer with + member this.append(childs: List): IContainer = + raise (System.NotImplementedException()) + end + + + /// 内容节点 ========================================================================================= + module Content = + type TextContent(word: AstImport.TextItem) = + class + interface Present.IDomUnit with + member this.name(): string = "" + member this.getHtml(pnode: XmlElement): XmlElement = + raise (System.NotImplementedException()) + end + + + type PointRefer(refs: AstImport.PointRef, items: List) = + class + let ref_signature = $"@{refs.storyRef()}&{refs.sliceRef()}&{refs.pointRef()}" + let lines = refs.children() |> List.map (fun x->x.content()) + + interface Present.IDomUnit with + member this.name(): string = + ref_signature + member this.getHtml(pnode: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface Present.IContainer with + member this.append(childs: List): Present.IContainer = + raise (System.NotImplementedException()) + end + let refer_assemble (refn: AstImport.PointRef) : PointRefer = + let texts = refn.children() |> List.map (fun dom -> TextContent(dom) :> Present.IDomUnit) + PointRefer(refn, texts) + + + type PointDefine(defs: AstImport.PointDef, items: List) = + class + let lines = defs.children() |> List.map (fun x->x.content()) + + interface Present.IDomUnit with + member this.name(): string = + defs.name() + member this.getHtml(pnode: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface Present.IContainer with + member this.append(childs: List): Present.IContainer = + raise (System.NotImplementedException()) + end + let point_assemble (defs: AstImport.PointDef) : PointDefine = + let texts = defs.children() |> List.map (fun dom -> TextContent(dom) :> Present.IDomUnit) + PointDefine(defs, texts) + + + type SliceDefine(defs: AstImport.SliceDef, items: List) = + class + interface Present.IDomUnit with + member this.name(): string = + defs.name() + member this.getHtml(pnode: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface Present.IContainer with + member this.append(childs: List): Present.IContainer = + raise (System.NotImplementedException()) + end + let slice_assemble (defs: AstImport.SliceDef) : SliceDefine = + let childs = defs.children() + |> List.map(fun data -> + match data with + | :? AstImport.PointRef as refs -> refer_assemble(refs) + | :? AstImport.PointDef as defs -> point_assemble(defs) + | :? AstImport.TextItem as text -> TextContent(text) + | _ -> raise (System.NotImplementedException()) + ) + SliceDefine(defs, childs) + + + type StoryDefine(defs: AstImport.StoryDef, childs: List) = + class + interface Present.IDomUnit with + member this.name(): string = + defs.name() + member this.getHtml(pnode: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface Present.IContainer with + member this.append(childs: List): Present.IContainer = + raise (System.NotImplementedException()) + end + let story_assemble (defs: AstImport.StoryDef): StoryDefine = + let childs = defs.children() + |> List.map(fun data -> + match data with + | :? AstImport.SliceDef as defs -> slice_assemble(defs) + | :? AstImport.TextItem as text -> TextContent(text) + | _ -> raise (System.NotImplementedException()) + ) + StoryDefine(defs, childs) + + + type ArticleDefine(defs: AstImport.ArticleDef, childs: List) = + class + interface Present.IDomUnit with + member this.name(): string = + defs.name() + member this.getHtml(pnode: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface Present.IContainer with + member this.append(childs: List): Present.IContainer = + raise (System.NotImplementedException()) + end + let article_assemble (defs: AstImport.ArticleDef) : ArticleDefine = + let childs = defs.children() + |> List.map(fun data -> + match data with + | :? AstImport.TextItem as text -> TextContent(text) + | :? AstImport.PointRef as refs -> refer_assemble(refs) + | _ -> raise (System.NotImplementedException()) + ) + ArticleDefine(defs, childs) + + + type VolumeDefine(defs: AstImport.VolumeDef, childs: List) = + class + interface Present.IDomUnit with + member this.name(): string = + defs.name() + member this.getHtml(pnode: XmlElement): XmlElement = + raise (System.NotImplementedException()) + + interface Present.IContainer with + member this.append(childs: List): Present.IContainer = + raise (System.NotImplementedException()) + end + let volume_assemble (defs: AstImport.VolumeDef): VolumeDefine = + let childs = defs.children() + |> List.map(fun data -> + match data with + | :? AstImport.TextItem as text -> TextContent(text) + | :? AstImport.ArticleDef as defs -> article_assemble(defs) + | _ -> raise (System.NotImplementedException()) + ) + VolumeDefine(defs, childs) + + + type UnitGenerate(root: AstImport.AstObject) = + class + // ast 节点序列 + let forwards_map = AstImport.branch_map_conv(root, root.members()) + // 累积结果 + let mutable result_nodes: (int*Present.IDomUnit) list = [] + + interface AstImport.AstVisitor with + member this.visit(obj: AstImport.AstObject): bool = + let refs_depth = AstImport.depth_seek(forwards_map, obj) + let childs = result_nodes |> List.filter (fun (depth, _) -> depth > refs_depth) + |> List.map(fun (_, object) -> object) + + let datas = match obj with + | :? AstImport.TextItem as text -> + (refs_depth, TextContent(text) :> Present.IDomUnit)::result_nodes + | :? AstImport.PointRef as refs -> + (refs_depth, PointRefer(refs, childs))::result_nodes + | :? AstImport.PointDef as defs -> + (refs_depth, PointDefine(defs, childs))::result_nodes + | :? AstImport.SliceDef as defs -> + (refs_depth, SliceDefine(defs, childs))::result_nodes + | :? AstImport.StoryDef as defs -> + (refs_depth, StoryDefine(defs, childs))::result_nodes + | :? AstImport.ArticleDef as defs -> + (refs_depth, ArticleDefine(defs, childs))::result_nodes + | :? AstImport.VolumeDef as defs -> + (refs_depth, VolumeDefine(defs, childs))::result_nodes + | :? AstImport.Program -> result_nodes + | _ -> raise (System.NotImplementedException()) + + result_nodes <- datas + if refs_depth > 0 then + result_nodes <- result_nodes |> List.filter(fun (depth, _) -> depth <= refs_depth) + true + + member this.contents() = + result_nodes |> List.map(fun (_, obj) -> obj) + end \ No newline at end of file diff --git a/AstConv/Program.fs b/AstConv/Program.fs new file mode 100644 index 0000000..8b384ca --- /dev/null +++ b/AstConv/Program.fs @@ -0,0 +1,15 @@ +open AstAccess.AstImport +open HtmlStruct.Content +open System.Xml + +let doc = XmlDocument() +doc.Load("E:/storyline.xast") + +let prog = Program.GenerateFrom(doc) + +let entry = AstVisitEntry(prog) +let visitor = UnitGenerate(prog) +entry.visitWith(visitor) |> ignore + +for it in visitor.contents() do + printfn $"Name:{it.name()}" \ No newline at end of file diff --git a/WsNovelParser.sln b/WsNovelParser.sln index 7cafe39..5334a21 100644 --- a/WsNovelParser.sln +++ b/WsNovelParser.sln @@ -38,62 +38,102 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CoreTest", "CoreTest\CoreTe {EF557F71-99AA-4F2B-A5F5-1A4518A11C19} = {EF557F71-99AA-4F2B-A5F5-1A4518A11C19} EndProjectSection EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AstConv", "AstConv\AstConv.fsproj", "{0C77216C-6484-4C94-BE06-D5D9FF18EA81}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1EF577E8-D92D-4926-9207-1567137BB672}.Debug|Any CPU.ActiveCfg = Debug|x64 + {1EF577E8-D92D-4926-9207-1567137BB672}.Debug|Any CPU.Build.0 = Debug|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x64.ActiveCfg = Debug|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x64.Build.0 = Debug|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x86.ActiveCfg = Debug|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x86.Build.0 = Debug|x64 + {1EF577E8-D92D-4926-9207-1567137BB672}.Release|Any CPU.ActiveCfg = Release|x64 + {1EF577E8-D92D-4926-9207-1567137BB672}.Release|Any CPU.Build.0 = Release|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Release|x64.ActiveCfg = Release|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Release|x64.Build.0 = Release|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Release|x86.ActiveCfg = Release|x64 {1EF577E8-D92D-4926-9207-1567137BB672}.Release|x86.Build.0 = Release|x64 + {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|Any CPU.ActiveCfg = Debug|x64 + {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|Any CPU.Build.0 = Debug|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x64.ActiveCfg = Debug|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x64.Build.0 = Debug|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x86.ActiveCfg = Debug|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x86.Build.0 = Debug|x64 + {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|Any CPU.ActiveCfg = Release|x64 + {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|Any CPU.Build.0 = Release|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x64.ActiveCfg = Release|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x64.Build.0 = Release|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x86.ActiveCfg = Release|x64 {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x86.Build.0 = Release|x64 + {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|Any CPU.Build.0 = Debug|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x64.ActiveCfg = Debug|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x64.Build.0 = Debug|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x86.ActiveCfg = Debug|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x86.Build.0 = Debug|x64 + {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|Any CPU.ActiveCfg = Release|x64 + {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|Any CPU.Build.0 = Release|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x64.ActiveCfg = Release|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x64.Build.0 = Release|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x86.ActiveCfg = Release|x64 {C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x86.Build.0 = Release|x64 + {1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|Any CPU.ActiveCfg = Debug|x64 + {1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|Any CPU.Build.0 = Debug|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x64.ActiveCfg = Debug|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x64.Build.0 = Debug|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x86.ActiveCfg = Debug|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x86.Build.0 = Debug|x64 + {1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|Any CPU.ActiveCfg = Release|x64 + {1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|Any CPU.Build.0 = Release|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x64.ActiveCfg = Release|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x64.Build.0 = Release|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x86.ActiveCfg = Release|x64 {1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x86.Build.0 = Release|x64 + {386F6D42-C6EB-4973-9511-181472391B21}.Debug|Any CPU.ActiveCfg = Debug|x64 + {386F6D42-C6EB-4973-9511-181472391B21}.Debug|Any CPU.Build.0 = Debug|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Debug|x64.ActiveCfg = Debug|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Debug|x64.Build.0 = Debug|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Debug|x86.ActiveCfg = Debug|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Debug|x86.Build.0 = Debug|x64 + {386F6D42-C6EB-4973-9511-181472391B21}.Release|Any CPU.ActiveCfg = Release|x64 + {386F6D42-C6EB-4973-9511-181472391B21}.Release|Any CPU.Build.0 = Release|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Release|x64.ActiveCfg = Release|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Release|x64.Build.0 = Release|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Release|x86.ActiveCfg = Release|x64 {386F6D42-C6EB-4973-9511-181472391B21}.Release|x86.Build.0 = Release|x64 + {9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|Any CPU.ActiveCfg = Debug|x64 + {9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|Any CPU.Build.0 = Debug|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x64.ActiveCfg = Debug|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x64.Build.0 = Debug|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x86.ActiveCfg = Debug|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x86.Build.0 = Debug|x64 + {9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|Any CPU.ActiveCfg = Release|x64 + {9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|Any CPU.Build.0 = Release|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x64.ActiveCfg = Release|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x64.Build.0 = Release|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x86.ActiveCfg = Release|x64 {9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x86.Build.0 = Release|x64 + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x64.ActiveCfg = Debug|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x64.Build.0 = Debug|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x86.ActiveCfg = Debug|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x86.Build.0 = Debug|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|Any CPU.Build.0 = Release|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x64.ActiveCfg = Release|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x64.Build.0 = Release|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x86.ActiveCfg = Release|Any CPU + {0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/WsNovelParser/htmlprint.cpp b/WsNovelParser/htmlprint.cpp index 2450ccf..5e264e4 100644 --- a/WsNovelParser/htmlprint.cpp +++ b/WsNovelParser/htmlprint.cpp @@ -6,708 +6,9 @@ using namespace example_novel; using namespace printer; using namespace lib_parse; -Access::Access(std::shared_ptr handle) - :access_handle(handle) { -} - -std::shared_ptr Access::accessPeers() const { - return access_handle; -} - -void Access::setPageRefers(const QString& href) { - this->summary_refer_store = href; -} - -QString Access::pageRefers() const { - return this->summary_refer_store; -} - -Element::Element(std::shared_ptr handle) :Access(handle) { -} - -void printer::Element::setSliceRefer(const QString& href) { - this->refer_store = href; -} - -QString printer::Element::sliceRefers() const { - return refer_store; -} - -Group::Group(std::shared_ptr handle) : Access(handle) { -} - -void Group::append(std::shared_ptr elm) { - element_store.append(elm); -} - -QList> Group::elements() const { - return this->element_store; -} - -std::shared_ptr printer::Group::getElement(const QString& signature) const { - for (auto& it : elements()) { - if (it->accessPeers()->element()->signature() == signature) - return it; - } - return nullptr; -} - -StoryLine::StoryLine(std::shared_ptr handle) :Group(handle) { -} - -void StoryLine::buildPageHTML(QDomElement& parent) const { - auto syntax_access = this->accessPeers(); - auto storyline_inst = std::dynamic_pointer_cast(syntax_access->element()); - - auto doc = parent.ownerDocument(); - auto dom_storyline = doc.createElement("div"); - parent.appendChild(dom_storyline); - - auto dom_title = doc.createElement("h1"); - dom_title.appendChild(doc.createTextNode(storyline_inst->name())); - dom_storyline.appendChild(dom_title); - - for (auto& inst_c : syntax_access->children()) { - switch ((NovelNode) inst_c->element()->typeMark()) { - case NovelNode::TextSection: - { - auto text_inst = std::dynamic_pointer_cast(inst_c->element()); - auto dom_p = doc.createElement("p"); - dom_p.appendChild(doc.createTextNode(text_inst->content())); - dom_storyline.appendChild(dom_p); - }break; - case NovelNode::PointRefers: - case NovelNode::PointDefines: - { - auto element_inst = this->getElement(inst_c->element()->signature()); - element_inst->buildSliceHTML(dom_storyline); - }break; - default: - break; - } - } -} - -StoryVolume::StoryVolume(std::shared_ptr handle) : Group(handle) { -} - -void StoryVolume::buildPageHTML(QDomElement& parent) const { - auto syntax_access = this->accessPeers(); - auto volume_inst = std::dynamic_pointer_cast(syntax_access->element()); - - auto doc_inst = parent.ownerDocument(); - auto dom_volume = doc_inst.createElement("div"); - parent.appendChild(dom_volume); - - auto dom_title = doc_inst.createElement("h1"); - dom_title.appendChild(doc_inst.createTextNode(volume_inst->name())); - dom_volume.appendChild(dom_title); - - std::function>&)> rich_refer_build = - [&](QDomElement& parent_element, const QList> children) { - for (auto& child : children) { - auto doc_ins = parent_element.ownerDocument(); - switch ((NovelNode) child->element()->typeMark()) { - case NovelNode::TextSection: - { - auto text_inst = std::dynamic_pointer_cast(child->element()); - auto dom_p = doc_ins.createElement("p"); - dom_p.appendChild(doc_ins.createTextNode(text_inst->content())); - parent_element.appendChild(dom_p); - }break; - case NovelNode::ArticleDefine: - { - auto article_inst = std::dynamic_pointer_cast(child->element()); - auto article_group = doc_ins.createElement("div"); - auto article_head = doc_ins.createElement("h2"); - article_head.appendChild(doc_ins.createTextNode(article_inst->name() + "{")); - article_group.appendChild(article_head); - rich_refer_build(article_group, child->children()); - article_group.appendChild(doc_ins.createTextNode("}")); - parent_element.appendChild(article_group); - }break; - case NovelNode::PointRefers: - { - auto fragment_inst = std::dynamic_pointer_cast(child->element()); - auto refer_inst = this->getElement(fragment_inst->signature()); - refer_inst->buildSliceHTML(parent_element); - }break; - default: - break; - } - } - }; - - rich_refer_build(dom_volume, syntax_access->children()); -} - -FragmentRef::FragmentRef(std::shared_ptr handle) : Element(handle) { -} - -void printer::FragmentRef::setHost(std::shared_ptr frag_inst) { - this->host_inst = frag_inst; -} - -std::shared_ptr printer::FragmentRef::hostFragment() const { - return this->host_inst.lock(); -} - -void FragmentRef::buildSliceHTML(QDomElement& dom_parent) const { - auto syntax_access = this->accessPeers(); - auto refer_element = std::dynamic_pointer_cast(syntax_access->element()); - - auto jump_to_host = this->hostFragment()->pageRefers(); - auto doc = dom_parent.ownerDocument(); - - auto dom_reference = doc.createElement("div"); - dom_reference.setAttribute("id", QString::number((qulonglong) refer_element.get())); - dom_parent.appendChild(dom_reference); - - auto dom_title = doc.createElement("h2"); - dom_reference.appendChild(dom_title); - - auto dom_href = doc.createElement("a"); - dom_href.appendChild(doc.createTextNode(refer_element->referSignature())); - dom_href.setAttribute("href", "file:///" + jump_to_host); - dom_title.appendChild(dom_href); - - std::function>&)> rich_refer_build = - [&](QDomElement& parent_element, const QList> children) { - for (auto& child : children) { - auto doc_ins = parent_element.ownerDocument(); - switch ((NovelNode) child->element()->typeMark()) { - case NovelNode::TextSection: - { - auto text_inst = std::dynamic_pointer_cast(child->element()); - auto dom_p = doc_ins.createElement("p"); - dom_p.appendChild(doc_ins.createTextNode(text_inst->content())); - parent_element.appendChild(dom_p); - }break; - case NovelNode::ArticleDefine: - { - auto article_inst = std::dynamic_pointer_cast(child->element()); - auto article_group = doc_ins.createElement("div"); - auto article_head = doc_ins.createElement("h2"); - article_head.appendChild(doc_ins.createTextNode(article_inst->name() + "{")); - article_group.appendChild(article_head); - rich_refer_build(article_group, child->children()); - article_group.appendChild(doc_ins.createTextNode("}")); - parent_element.appendChild(article_group); - }break; - default: - break; - } - } - }; - - rich_refer_build(dom_reference, syntax_access->children()); -} - -void FragmentRef::buildPageHTML(QDomElement& parent) const { - auto syntax_access = this->accessPeers(); - auto refer_element = std::dynamic_pointer_cast(syntax_access->element()); - - auto doc = parent.ownerDocument(); - - auto refers_dom = doc.createElement("div"); - parent.appendChild(refers_dom); - - auto title_block = doc.createElement("h2"); - refers_dom.appendChild(title_block); - auto title_refer = doc.createElement("a"); - title_refer.appendChild(doc.createTextNode(refer_element->signature())); - title_refer.setAttribute("href", "file:///" + this->sliceRefers()); - title_block.appendChild(title_refer); - - std::function>)> build_cascade = - [&](QList> children_items) { - for (auto child : children_items) { - if (child->element()->typeMark() == (int) NovelNode::TextSection) { - auto text_inst = std::dynamic_pointer_cast(child->element()); - auto p = doc.createElement("p"); - p.appendChild(doc.createTextNode(text_inst->content())); - refers_dom.appendChild(p); - } - else { - build_cascade(child->children()); - } - } - }; - - build_cascade(syntax_access->children()); -} - -Fragment::Fragment(std::shared_ptr handle) : Element(handle) { -} - -void Fragment::appendRefers(std::shared_ptr inst) { - this->additionals_store.append(inst); - inst->setHost(std::static_pointer_cast(this->shared_from_this())); -} - -QList> Fragment::additionals() const { - return this->additionals_store; -} - -void Fragment::buildSliceHTML(QDomElement& parent) const { - auto syntax_access = this->accessPeers(); - auto fragment_inst = std::dynamic_pointer_cast(syntax_access->element()); - - auto doc = parent.ownerDocument(); - auto dom_fragment = doc.createElement("div"); - dom_fragment.setAttribute("id", QString::number((qulonglong) fragment_inst.get())); - parent.appendChild(dom_fragment); - - auto dom_title = doc.createElement("h2"); - dom_fragment.appendChild(dom_title); - - auto dom_href = doc.createElement("a"); - dom_href.appendChild(doc.createTextNode(fragment_inst->name())); - dom_href.setAttribute("href", "file:///" + this->pageRefers()); - dom_title.appendChild(dom_href); - - for (auto& inst_c : syntax_access->children()) { - if (NovelNode::TextSection == (NovelNode) inst_c->element()->typeMark()) { - auto text_inst = std::dynamic_pointer_cast(inst_c->element()); - auto dom_p = doc.createElement("p"); - dom_p.appendChild(doc.createTextNode(text_inst->content())); - dom_fragment.appendChild(dom_p); - } - } - -} - -void Fragment::buildPageHTML(QDomElement& parent) const { - auto syntax_access = this->accessPeers(); - auto fragment_inst = std::dynamic_pointer_cast(syntax_access->element()); - - auto doc = parent.ownerDocument(); - auto dom_fragment = doc.createElement("div"); - parent.appendChild(dom_fragment); - - auto dom_title = doc.createElement("h1"); - dom_fragment.appendChild(dom_title); - - auto dom_href = doc.createElement("a"); - dom_href.appendChild(doc.createTextNode(fragment_inst->signature())); - dom_href.setAttribute("href", "file:///" + this->sliceRefers()); - dom_title.appendChild(dom_href); - - for (auto& inst_c : syntax_access->children()) { - if (NovelNode::TextSection == (NovelNode) inst_c->element()->typeMark()) { - auto text_inst = std::dynamic_pointer_cast(inst_c->element()); - auto dom_p = doc.createElement("p"); - dom_p.appendChild(doc.createTextNode(text_inst->content())); - dom_fragment.appendChild(dom_p); - } - } - - for (auto& it : this->additionals()) { - it->buildPageHTML(dom_fragment); - } -} - -#include -void tools_printer::build_fragments(std::shared_ptr novel_root) { - if (novel_root->element()->typeMark() == (int) NovelNode::PointDefines) { - auto inst = std::make_shared(novel_root); - auto name = novel_root->element()->signature(); - this->fragment_defines[name] = inst; - } - - for (auto& inst_c : novel_root->children()) { - build_fragments(inst_c); - } -} - -void tools_printer::build_refers_network(std::shared_ptr novel_node) { - switch ((NovelNode) novel_node->element()->typeMark()) { - case NovelNode::StoryDefine: - { - auto storyinst = std::make_shared(novel_node); - this->storyline_defines[novel_node->element()->signature()] = storyinst; - build_storyline(storyinst); - }return; - case NovelNode::VolumeDefine: - { - auto volumeinst = std::make_shared(novel_node); - this->volume_defines[novel_node->element()->signature()] = volumeinst; - build_volumeline(volumeinst); - }return; - } - - for (auto& inst_c : novel_node->children()) - build_refers_network(inst_c); -} - -void tools_printer::build_storyline(std::shared_ptr line, std::shared_ptr novel_node) { - if (!novel_node) { - for (auto& inst_c : line->accessPeers()->children()) { - build_storyline(line, inst_c); - } - } - else { - switch ((NovelNode) novel_node->element()->typeMark()) { - case NovelNode::PointDefines: - { - auto inst = this->fragment_defines[novel_node->element()->signature()]; - line->append(inst); - }return; - case NovelNode::PointRefers: - { - auto refer_node = std::dynamic_pointer_cast(novel_node->element()); - auto refer_fragment = this->fragment_defines[refer_node->referSignature()]; - auto inst = std::make_shared(novel_node); - refer_fragment->appendRefers(inst); - line->append(inst); - }return; - } - - for (auto& inst_c : novel_node->children()) - build_storyline(line, inst_c); - } -} - -void tools_printer::build_volumeline(std::shared_ptr volume, std::shared_ptr novel_node) { - if (!novel_node) { - for (auto& inst_c : volume->accessPeers()->children()) - build_volumeline(volume, inst_c); - } - else { - if (NovelNode::PointRefers == (NovelNode) novel_node->element()->typeMark()) { - auto refer_node = std::dynamic_pointer_cast(novel_node->element()); - auto refer_fragment = this->fragment_defines[refer_node->referSignature()]; - auto inst = std::make_shared(novel_node); - refer_fragment->appendRefers(inst); - volume->append(inst); - return; - } - - for (auto& inst_c : novel_node->children()) - build_volumeline(volume, inst_c); - } -} - -void tools_printer::fragments_anchors_define(const QList>& list, const QDir& root_dir) { - auto path = root_dir.filePath("fragments"); - if (!QDir(path).exists()) - root_dir.mkdir("fragments"); - QDir target_dir(path); - - for (auto& it : list) { - auto address_x = QString::number((qulonglong) it->accessPeers()->element().get()); - it->setPageRefers(target_dir.absoluteFilePath(QString("%1.html").arg(address_x))); - } -} - -std::function>&, const QString&)> refers_refresh = -[&](const QList>& items, const QString& summary_href) { - for (auto& item : items) { - auto element_addr = QString::number((qulonglong) item->accessPeers()->element().get()); - item->setSliceRefer(summary_href + "#" + element_addr); - } - }; - -void tools_printer::storylines_anchors_define(const QList>& list, const QDir& root_dir) { - auto path = root_dir.filePath("storylines"); - if (!QDir(path).exists()) - root_dir.mkdir("storylines"); - QDir target_dir(path); - - for (auto& it : list) { - auto address_x = QString::number((qulonglong) it->accessPeers()->element().get()); - auto page_address = target_dir.absoluteFilePath(QString("%1.html").arg(address_x)); - it->setPageRefers(page_address); - refers_refresh(it->elements(), page_address); - } -} - -void tools_printer::volumes_anchors_define(const QList>& list, const QDir& root_dir) { - auto path = root_dir.filePath("volumes"); - if (!QDir(path).exists()) - root_dir.mkdir("volumes"); - QDir target_dir(path); - - for (auto& it : list) { - auto address_x = QString::number((qulonglong) it->accessPeers()->element().get()); - auto page_address = target_dir.absoluteFilePath(QString("%1.html").arg(address_x)); - it->setPageRefers(page_address); - refers_refresh(it->elements(), page_address); - } -} - -auto get_node_name = [](const std::shared_ptr item) { - return "node_" + QString::number((qulonglong) item->accessPeers()->element().get()); - }; - -QString printer::tools_printer::storylines_paint(const QList>& lines) { - QHash> node_records; - QString nodes_description; - for (auto& story : lines) { - auto story_elem = std::dynamic_pointer_cast(story->accessPeers()->element()); - node_records[story_elem->signature()] = story; - nodes_description += get_node_name(story) + QString("[fillcolor=pink,label=\"%1{%2}\",shape=\"cds\"]\n").arg(story_elem->name()).arg(story_elem->sort()); - - for (auto& frag : story->elements()) { - auto fragment_peers = frag->accessPeers()->element(); - if (fragment_peers->typeMark() == (int) example_novel::NovelNode::PointDefines) { - auto fragment_elem = std::dynamic_pointer_cast(fragment_peers); - auto node_name = fragment_elem->signature(); - node_records[node_name] = frag; - - nodes_description += get_node_name(frag) + QString("[label=\"{%2}::%1\",shape=\"rect\"]\n") - .arg(fragment_elem->name()).arg(story_elem->sort()); - } - } - } - - QString arrows_link; - for (auto& story : lines) { - auto story_elem = std::dynamic_pointer_cast(story->accessPeers()->element()); - - QString previous_node = get_node_name(story); - for (auto& frag : story->elements()) { - if (example_novel::NovelNode::PointDefines == (example_novel::NovelNode) frag->accessPeers()->element()->typeMark()) { - arrows_link += previous_node + "->" + get_node_name(frag) + QString("[label=\"%1{%2}\"]\n") - .arg(story_elem->name()).arg(story_elem->sort()); - previous_node = get_node_name(frag); - } - else if (example_novel::NovelNode::PointRefers == (example_novel::NovelNode) frag->accessPeers()->element()->typeMark()) { - auto frag_refer = std::dynamic_pointer_cast(frag->accessPeers()->element()); - auto frag_src = node_records[frag_refer->referSignature()]; - arrows_link += previous_node + "->" + get_node_name(frag_src) + QString("[label=\"%1{%2}\"]\n") - .arg(story_elem->name()).arg(story_elem->sort()); - previous_node = get_node_name(frag_src); - } - } - } - - return QString("digraph{ rankdir = LR \n node[style=filled] \n %1\n %2 }").arg(nodes_description).arg(arrows_link); -} - -QString printer::tools_printer::volumes_paint(const QList>& vols, const QList>& lines) { - QHash> node_records; - - QString clusters_description; - for (auto& story : lines) { - QString nodes_description; - for (auto& frag : story->elements()) { - auto fragment_peers = frag->accessPeers()->element(); - if (fragment_peers->typeMark() == (int) example_novel::NovelNode::PointDefines) { - auto fragment_elem = std::dynamic_pointer_cast(fragment_peers); - node_records[fragment_elem->signature()] = frag; - nodes_description += get_node_name(frag) + QString("[label=\"%1\",shape=\"ellipse\"]\n").arg(fragment_elem->name()); - } - } - - auto story_elem = std::dynamic_pointer_cast(story->accessPeers()->element()); - clusters_description += QString("subgraph cluster_%1 { label=%3 \n %2 }") - .arg((qulonglong) story_elem.get()).arg(nodes_description).arg(story_elem->name()); - } - - - auto article_cluster = [&node_records](const std::shared_ptr article_access, QList& arrows_out)->QString { - QString nodes_description; - for (auto& fragment_access : article_access->children()) { - if (fragment_access->element()->typeMark() == (int) example_novel::NovelNode::PointRefers) { - auto refer_fragment = std::dynamic_pointer_cast(fragment_access->element()); - nodes_description += QString("fragment_%1[label=\"%2\",shape=\"plaintext\"]\n") - .arg((qulonglong) refer_fragment.get()).arg(refer_fragment->sliceRefer()); - auto symbo_refer = node_records[refer_fragment->referSignature()]; - arrows_out << QString("fragment_%1 -- %2[color=\"red\"]\n").arg((qulonglong) refer_fragment.get()).arg(get_node_name(symbo_refer)); - } - } - auto article_define = std::dynamic_pointer_cast(article_access->element()); - return QString("subgraph cluster_%1{ label=%2 \n %3 }\n").arg((qulonglong) article_access->element().get()) - .arg(article_define->name()).arg(nodes_description); - }; - - QString arrows_link; - for (auto& vol : vols) { - QString members_description; - for (auto& eref : vol->accessPeers()->children()) { - QList arrows_temp; - switch ((example_novel::NovelNode) eref->element()->typeMark()) { - case example_novel::NovelNode::ArticleDefine: - members_description += article_cluster(eref, arrows_temp); - break; - default: - break; - } - for (auto& arrow : arrows_temp) { - arrows_link += arrow; - } - } - - auto volume_elem = std::dynamic_pointer_cast(vol->accessPeers()->element()); - clusters_description += QString("subgraph cluster_%1 { label=%3 \n %2 }") - .arg((qulonglong) volume_elem.get()).arg(members_description).arg(volume_elem->name()); - } - - return QString("graph scale{ %1 \n %2}").arg(clusters_description).arg(arrows_link); -} - #include #include #include -void printer::tools_printer::plain_html_output(const std::shared_ptr access_ptr, const QDir& destination_dir) const { - QTime time_stamp = QTime::currentTime(); - auto tool = *this; - tool.build_fragments(access_ptr); - tool.build_refers_network(access_ptr); - - tool.fragments_anchors_define(tool.fragment_defines.values(), destination_dir); - tool.storylines_anchors_define(tool.storyline_defines.values(), destination_dir); - tool.volumes_anchors_define(tool.volume_defines.values(), destination_dir); - - std::function)> html_output = - [](std::shared_ptr inst) { - auto target_path = inst->pageRefers(); - QFile tfile(target_path); - if (tfile.open(QIODevice::WriteOnly | QIODevice::Text)) { - QDomDocument doc_inst(QDomImplementation().createDocumentType("html", QString(), QString())); - auto html = doc_inst.createElement("html"); - doc_inst.appendChild(html); - - auto body = doc_inst.createElement("body"); - html.appendChild(body); - - inst->buildPageHTML(body); - - QTextStream tout(&tfile); - doc_inst.save(tout, 2); - tout.flush(); - } - }; - - for (auto& node : tool.fragment_defines) - html_output(node); - for (auto& node : tool.storyline_defines) - html_output(node); - for (auto& node : tool.volume_defines) - html_output(node); - - QDir::setCurrent(destination_dir.canonicalPath()); - auto dot_src = tool.storylines_paint(tool.storyline_defines.values()); - QFile dot_file(QDir::current().filePath("relates.dot")); - if (dot_file.open(QIODevice::WriteOnly | QIODevice::Text)) { - QTextStream txt(&dot_file); - txt.setCodec("UTF-8"); - txt << dot_src; - txt.flush(); - } - system("dot -Tsvg relates.dot -o relates.svg"); - - auto vols_src = tool.volumes_paint(tool.volume_defines.values(), tool.storyline_defines.values()); - QFile vols_file(QDir::current().filePath("volumes_group.dot")); - if (vols_file.open(QIODevice::WriteOnly | QIODevice::Text)) { - QTextStream txt(&vols_file); - txt.setCodec("UTF-8"); - txt << vols_src; - txt.flush(); - } - system("fdp -Tsvg volumes_group.dot -o volumes_group.svg"); - - - { - QFile tfile("./index.html"); - if (tfile.open(QIODevice::WriteOnly | QIODevice::Text)) { - QDomDocument doc_inst(QDomImplementation().createDocumentType("html", QString(), QString())); - auto html = doc_inst.createElement("html"); - doc_inst.appendChild(html); - - auto body = doc_inst.createElement("body"); - html.appendChild(body); - - auto dom_storyline = doc_inst.createElement("div"); - auto dom_storyline_title = doc_inst.createElement("h2"); - dom_storyline_title.appendChild(doc_inst.createTextNode("故事脉络")); - dom_storyline.appendChild(dom_storyline_title); - body.appendChild(dom_storyline); - - auto lines = tool.storyline_defines.values(); - std::sort(lines.begin(), lines.end(), [](std::shared_ptr a, std::shared_ptr b)->bool { - auto a_elm = std::dynamic_pointer_cast(a->accessPeers()->element()); - auto b_elm = std::dynamic_pointer_cast(b->accessPeers()->element()); - return a_elm->sort() < b_elm->sort(); - }); - for (auto& inst_line : lines) { - auto dom_line = doc_inst.createElement("p"); - dom_storyline.appendChild(dom_line); - - auto line_href = doc_inst.createElement("a"); - line_href.setAttribute("href", "file:///" + inst_line->pageRefers()); - auto a_elm = std::dynamic_pointer_cast(inst_line->accessPeers()->element()); - line_href.appendChild(doc_inst.createTextNode(QString("%1.%2").arg(a_elm->sort()).arg(a_elm->signature()))); - dom_line.appendChild(line_href); - } - - auto dom_volume = doc_inst.createElement("div"); - auto dom_volume_title = doc_inst.createElement("h2"); - dom_volume_title.appendChild(doc_inst.createTextNode("分卷内容")); - dom_volume.appendChild(dom_volume_title); - body.appendChild(dom_volume); - - for (auto& inst_volume : tool.volume_defines) { - auto dom_volume_ref = doc_inst.createElement("p"); - dom_volume.appendChild(dom_volume_ref); - - auto volume_href = doc_inst.createElement("a"); - volume_href.setAttribute("href", "file:///" + inst_volume->pageRefers()); - volume_href.appendChild(doc_inst.createTextNode(inst_volume->accessPeers()->element()->signature())); - dom_volume_ref.appendChild(volume_href); - } - - auto dom_fragment = doc_inst.createElement("div"); - auto dom_fragment_title = doc_inst.createElement("h2"); - dom_fragment_title.appendChild(doc_inst.createTextNode("情节集合")); - dom_fragment.appendChild(dom_fragment_title); - body.appendChild(dom_fragment); - - auto table_cube = doc_inst.createElement("table"); - dom_fragment.appendChild(table_cube); - - int row_ctrl = 0; - QDomElement elm_row; - for (auto& inst_frag : tool.fragment_defines) { - if (row_ctrl++ % 4 == 0) { - elm_row = doc_inst.createElement("tr"); - table_cube.appendChild(elm_row); - } - - auto dom_fragment_ref = doc_inst.createElement("td"); - elm_row.appendChild(dom_fragment_ref); - - auto frag_href = doc_inst.createElement("a"); - frag_href.setAttribute("href", "file:///" + inst_frag->pageRefers()); - frag_href.appendChild(doc_inst.createTextNode(inst_frag->accessPeers()->element()->signature())); - dom_fragment_ref.appendChild(frag_href); - } - - auto dom_relate = doc_inst.createElement("div"); - auto dom_relate_title = doc_inst.createElement("h2"); - dom_relate_title.appendChild(doc_inst.createTextNode("联系图")); - dom_relate.appendChild(dom_relate_title); - body.appendChild(dom_relate); - - auto img = doc_inst.createElement("img"); - img.setAttribute("src", "file:///" + QDir::current().filePath("relates.svg")); - dom_relate.appendChild(img); - dom_relate.appendChild(doc_inst.createElement("br")); - img = doc_inst.createElement("img"); - img.setAttribute("src", "file:///" + QDir::current().filePath("volumes_group.svg")); - dom_relate.appendChild(img); - - QTextStream tout(&tfile); - doc_inst.save(tout, 2); - tout.flush(); - } - } - - auto current_stamp = QTime::currentTime(); - qDebug().noquote() << QString("%html构建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp)); - qDebug().noquote() << "%编译成功:" << destination_dir.absoluteFilePath("index.html"); -} void printer::AstGenerate::append_tokens(QDomElement _elm, std::shared_ptr inst) { auto dom_tokens = doc.createElement("tokens"); diff --git a/WsNovelParser/htmlprint.h b/WsNovelParser/htmlprint.h index 44ba2b9..6bcc4e9 100644 --- a/WsNovelParser/htmlprint.h +++ b/WsNovelParser/htmlprint.h @@ -8,175 +8,6 @@ #include namespace printer { - /** - * 概括页面 - * 故事分卷汇总 - * 故事脉络汇总 - * 故事脉络关系图. - * - * 故事脉络发展页面 - * 故事剧情节点汇总 - * 内容展示 - * - * 剧情节点汇总页面 - * 引用来源汇总 - * 各节点内容展示 - */ - - - /* - * @brief 所有可访问元素的基类:卷宗、章节、故事线、剧情、节点、引用等 - */ - class Access : public std::enable_shared_from_this { - public: - Access(std::shared_ptr handle); - virtual ~Access() = default; - - /* - * @brief 获取绑定的语法元素 - * @return 元素内存指针 - */ - std::shared_ptr accessPeers() const; - - /* - * @brief 设置汇总页面路径 - * @param href 页面路径 - */ - void setPageRefers(const QString& href); - QString pageRefers() const; - - /* - * @brief 获取汇总页面的HTML - */ - virtual void buildPageHTML(QDomElement& doc) const = 0; - - private: - std::shared_ptr access_handle; - QString summary_refer_store; - }; - - /* - * @brief 可访问片段元素:故事片段本篇,故事片段引用 - */ - class Element : public Access { - public: - Element(std::shared_ptr handle); - virtual ~Element() = default; - - /* - * @brief 设置片段URL,从故事汇总页面跳转回出处页面 - */ - virtual void setSliceRefer(const QString& href); - virtual QString sliceRefers() const; - - /* - * @brief 获取故事片段出处的节点HTML - */ - virtual void buildSliceHTML(QDomElement &doc) const = 0; - - private: - QString refer_store; - }; - - /* - * @brief 可访问集合的基类:故事线、剧情节点、故事卷宗 - */ - class Group : public Access { - public: - Group(std::shared_ptr handle); - virtual ~Group() = default; - - void append(std::shared_ptr elm); - QList> elements() const; - std::shared_ptr getElement(const QString& signature) const; - - private: - QList> element_store; - }; - - class StoryLine : public Group { - public: - StoryLine(std::shared_ptr handle); - - // 通过 Group 继承 - void buildPageHTML(QDomElement& doc) const override; - - }; - - class StoryVolume : public Group { - public: - StoryVolume(std::shared_ptr handle); - - // 通过 Group 继承 - void buildPageHTML(QDomElement& doc) const override; - - }; - class Fragment; - /* - * @brief 情节片段引用定义 - */ - class FragmentRef : public Element { - public: - FragmentRef(std::shared_ptr handle); - - void setHost(std::shared_ptr frag_inst); - std::shared_ptr hostFragment() const; - - // 通过 Access 继承 - void buildPageHTML(QDomElement& doc) const override; - - // 通过 Element 继承 - void buildSliceHTML(QDomElement& doc) const override; - - private: - std::weak_ptr host_inst; - }; - - /* - * @brief 情节片段本篇定义,存储情节引用定义 - */ - class Fragment : public Element{ - private: - QList> additionals_store; - - public: - Fragment(std::shared_ptr handle); - - void appendRefers(std::shared_ptr inst); - QList> additionals() const; - - // 通过 Access 继承 - void buildPageHTML(QDomElement& doc) const override; - - // 通过 Element 继承 - void buildSliceHTML(QDomElement& doc) const override; - }; - - - class tools_printer { - public: - QHash> fragment_defines; - QHash> storyline_defines; - QHash> volume_defines; - - public: - void build_fragments(std::shared_ptr novel_root); - - void build_refers_network(std::shared_ptr novel_node); - - void build_storyline(std::shared_ptr line, std::shared_ptr novel_node = nullptr); - void build_volumeline(std::shared_ptr line, std::shared_ptr novel_node = nullptr); - - void fragments_anchors_define(const QList> &list, const QDir &destdir); - void storylines_anchors_define(const QList> &list, const QDir &destdir); - void volumes_anchors_define(const QList> &list, const QDir &destdir); - - QString storylines_paint(const QList> &lines); - QString volumes_paint(const QList> &vols, const QList> &lines); - - void plain_html_output(const std::shared_ptr root, const QDir &destinationdir) const; - }; - /** * @brief Ast输出构建器. */ diff --git a/WsNovelParser/main.cpp b/WsNovelParser/main.cpp index 69c300f..2a8fd52 100644 --- a/WsNovelParser/main.cpp +++ b/WsNovelParser/main.cpp @@ -34,8 +34,7 @@ int main(int argc, char* argv[]) { args_parser << build_mode; *build_mode << make_shared("nsc", "程序名称") << make_shared("path", "指定源代码目录") - << make_shared("dest", "指定生成目录") - << make_shared("html", "生成html文件格式取代AST", true); + << make_shared("dest", "指定生成目录"); auto p_result = args_parser.parse(argc, argv); @@ -49,7 +48,6 @@ int main(int argc, char* argv[]) { { auto src_dir = dynamic_pointer_cast(p_result->getUnitViaKey("path")); auto dst_dir = dynamic_pointer_cast(p_result->getUnitViaKey("dest")); - auto html_opt = dynamic_pointer_cast(p_result->getUnitViaKey("html")); auto source_dir = QDir(src_dir->value().toString()); if (!source_dir.exists()) { @@ -93,11 +91,7 @@ int main(int argc, char* argv[]) { } } - if (html_opt->value().toInt() == 1 && access_ptr) { - printer::tools_printer tool; - tool.plain_html_output(access_ptr, destination_dir); - } - else if (access_ptr) { + if (access_ptr) { QTime time_stamp = QTime::currentTime(); lib_parse::VisitEntry control; auto visitor = make_shared(source_dir); diff --git a/libSyntax/libsyntax.h b/libSyntax/libsyntax.h index 2ce613f..2d370bd 100644 --- a/libSyntax/libsyntax.h +++ b/libSyntax/libsyntax.h @@ -52,7 +52,7 @@ namespace lib_syntax { MatchCursor(std::shared_ptr other_ptr); virtual ~MatchCursor() = default; - bool operator>(const MatchCursor & other) const; + bool operator>(const MatchCursor& other) const; virtual std::shared_ptr previous() const; virtual QString filePath() const; @@ -195,7 +195,8 @@ namespace lib_syntax { std::shared_ptr _define_peers; public: - __token_match_impl(std::shared_ptr define) : _define_peers(define) { } + __token_match_impl(std::shared_ptr define) : _define_peers(define) { + } // IBasicRule interface public: @@ -293,7 +294,8 @@ namespace lib_syntax { class ElementRule : public ExprRule { public: ElementRule(const QString& rule_name) - :ExprRule(rule_name, mark), _children_store(std::make_shared()) { } + :ExprRule(rule_name, mark), _children_store(std::make_shared()) { + } virtual QList> children() const { return QList>() << this->_children_store; @@ -337,16 +339,10 @@ namespace lib_syntax { [](std::shared_ptr ins) { return !ins->parseFailure(); }); } - if (!branch_procs.size()) - branch_procs = nbranch; - - - decltype(nbranch) results_fnl; - for (auto curs : branch_procs) { - if (curs->parseFailure()) { - results_fnl.append(curs); - } - else { + // 表达式匹配结尾 + if (branch_procs.size()) { + decltype(nbranch) results_fnl; + for (auto curs : branch_procs) { auto t_end = curs->token(); auto w_end = curs->words(); @@ -363,9 +359,11 @@ namespace lib_syntax { break; } } + return results_fnl; } - return results_fnl; + // 匹配失败 + return branch_procs; } protected: