import xml.dom.minidom as mdom from typing import List, Tuple, Dict from frame.ReferView import EmptyNode class FragmentSlice(EmptyNode): def __init__(self, def_mark: bool = False, name: str= ""): self.is_define_node = (def_mark, name) self.parent_story = "" self.story_refer = "" self.fragm_refer = "" self.fragm_sort_i = 0 self.prev_node: 'FragmentSlice' = None # 上游节点 self.next_node: 'FragmentSlice' = None # 下游节点 self.refers_slice: Dict[str, 'FragmentSlice'] = {} # 引用切面 self.text_sections: List[str] = [] # 文本段落 pass def get_from_memory(self) -> str: return "\n".join(self.text_sections) pass def set_to_memory(self, content: str): self.text_sections = content.split("\n") pass class ArticleSlice(EmptyNode): def __init__(self, a_name: str, v_name: str): self.article_name = a_name self.volume_blongs = v_name self.article_fullname = f"{v_name}@{a_name}" self.refer_target: List[str] = [] # 引用切面 self.text_sections: List[str] = [] # 文本段落 pass def get_from_memory(self) -> str: return "\n".join(self.text_sections) def set_to_memory(self, content: str): self.text_sections = content.split("\n") pass class StoryMap: def __init__(self, name: str): self.story_name = name self.sort_index = 0 self.empty_head = FragmentSlice() self.empty_head.set_to_memory("<空节点>") self.slice_list: List[FragmentSlice] = [self.empty_head] pass def append_fragment_slice(self, node: FragmentSlice): self.slice_list[-1].next_node = node node.parent_story = self.story_name node.prev_node = self.slice_list[-1] node.fragm_sort_i = len(self.slice_list) self.slice_list.append(node) pass def get_fragment_defined(self, name: str) -> FragmentSlice|None: for fit in self.slice_list: if fit.is_define_node[0]: if fit.is_define_node[1] == name: return fit pass pass return None class XAST_ParseTool: def __init__(self, ast_path: str): self.dom_tree = mdom.parse(ast_path) self.story_list: List[StoryMap] = [] names = self.story_names() for nm in names: vinst = self.__extract_empty_storymap(nm) self.__storynode_initfrags(vinst[0], vinst[1]) self.story_list.append(vinst[0]) pass def story_names(self) -> List[str]: """ 获取所有故事名称 :return: List[故事名] """ storys = self.dom_tree.getElementsByTagName("story") values = [] for n in storys: values.append(n.getAttribute("name")) pass return values def __extract_empty_storymap(self, name: str) -> Tuple[StoryMap, mdom.Element]: storys = self.dom_tree.getElementsByTagName("story") for node in storys: if node.getAttribute("name") == name: mem_node = StoryMap(name) mem_node.sort_index = int(node.getAttribute("sort")) return mem_node, node pass return None def __storynode_initfrags(self, node: StoryMap, e: mdom.Element): first_elem: mdom.Element = e.firstChild while first_elem != None: if hasattr(first_elem, "tagName"): dom_tag = first_elem.tagName if first_elem.tagName == "fragment": fnode = FragmentSlice(True, first_elem.getAttribute("name")) self.__fragmnode_init_desc(fnode, first_elem) node.append_fragment_slice(fnode) elif first_elem.tagName == "refer": fnode = FragmentSlice() fnode.story_refer = first_elem.getAttribute("story") fnode.fragm_refer = first_elem.getAttribute("fragment") self.__fragmnode_init_desc(fnode, first_elem) node.append_fragment_slice(fnode) pass pass first_elem = first_elem.nextSibling pass def __fragmnode_init_desc(self, node: FragmentSlice, e: mdom.Element): node_elem: mdom.Element = e.firstChild while node_elem != None: if hasattr(node_elem, "tagName") and node_elem.tagName == "text-section": line = node_elem.getAttribute("text") node.text_sections.append(line) pass node_elem = node_elem.nextSibling pass pass def storylines_plait(self, storys: Dict[str, StoryMap]): for snode in storys.values(): self.__storyline_plait_within(snode, storys) pass def __storyline_plait_within(self, story: StoryMap, storys_map: Dict[str, StoryMap]): for fnode in story.slice_list[1:]: if not fnode.is_define_node[0]: sname = fnode.story_refer fname = fnode.fragm_refer target_story = storys_map[sname] target_fragment = target_story.get_fragment_defined(fname) target_fragment.refers_slice[story.story_name] = fnode pass pass pass def get_story_graph(self) -> Dict[str, StoryMap]: story_dict = storyline_list2map(self.story_list) self.storylines_plait(story_dict) return story_dict def get_article_nodes(self) -> List[ArticleSlice]: retvalues = [] hangout_nodes = ArticleSlice("悬空节点", "") retvalues.append(hangout_nodes) fragments = self.__get_all_fragment_names() volumes = self.dom_tree.getElementsByTagName("volume") for vnode in volumes: child_articles = self.__volume_node_parse(vnode) retvalues.extend(child_articles) for child in child_articles: for refn in child.refer_target: if refn in fragments: fragments.remove(refn) pass pass pass pass hangout_nodes.refer_target.extend(fragments) return retvalues def __get_all_fragment_names(self) -> List[str]: values = [] frags = self.dom_tree.getElementsByTagName("fragment") for frag in frags: story: mdom.Element = frag.parentNode values.append(f"{story.getAttribute("name")}&{frag.getAttribute("name")}") pass return values def __volume_node_parse(self, vnode: mdom.Element)-> List[ArticleSlice]: retvalues = [] vname = vnode.getAttribute("name") articles = vnode.getElementsByTagName("article") for anode in articles: aname = anode.getAttribute("name") node_inst = ArticleSlice(aname, vname) retvalues.append(node_inst) refsnode = anode.getElementsByTagName("refer") for refnode in refsnode: ref_story = refnode.getAttribute("story") ref_fragment = refnode.getAttribute("fragment") node_inst.refer_target.append(f"{ref_story}&{ref_fragment}") pass pass return retvalues pass def storyline_list2map(storylines: List[StoryMap]) -> Dict[str, StoryMap]: retv = {} for linst in storylines: retv[linst.story_name] = linst pass return retv