StoryCheckTools/parse/StoryMap.py

146 lines
5.0 KiB
Python

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 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:
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
pass
def storyline_list2map(storylines: List[StoryMap]) -> Dict[str, StoryMap]:
retv = {}
for linst in storylines:
retv[linst.story_name] = linst
pass
return retv