StoryCheckTools/parse/StoryMap.py

433 lines
13 KiB
Python
Raw Permalink Normal View History

2024-07-29 02:26:16 +00:00
import xml.dom.minidom as mdom
2024-08-04 02:00:45 +00:00
from typing import List, Tuple, Dict, Union
2024-08-04 01:50:17 +00:00
from abc import abstractmethod
from enum import Enum
2024-07-29 13:30:54 +00:00
from frame.ReferView import EmptyNode
2024-07-29 02:26:16 +00:00
2024-08-04 01:50:17 +00:00
class SliceType(Enum):
StoryDefine = 0,
TextParagraph = 1,
FragmentDefine = 2,
FragmentRefer = 3,
VolumeDefine = 4,
ArticleDefine = 5,
class ElementSlice:
@abstractmethod
def type(self) -> SliceType:
raise NotImplementedError("type")
@abstractmethod
2024-08-04 02:00:45 +00:00
def parent_slice(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
raise NotImplementedError()
@abstractmethod
2024-08-04 02:00:45 +00:00
def set_prev(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
raise NotImplementedError()
@abstractmethod
2024-08-04 02:00:45 +00:00
def prev_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
raise NotImplementedError()
@abstractmethod
2024-08-04 02:00:45 +00:00
def set_next(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
raise NotImplementedError()
@abstractmethod
2024-08-04 02:00:45 +00:00
def next_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
raise NotImplementedError()
@abstractmethod
def index(self) -> int:
raise NotImplementedError()
class Collection:
@abstractmethod
def children(self) -> List[ElementSlice]:
raise NotImplementedError()
class SiblingsImpl(ElementSlice):
def __init__(self):
2024-08-04 02:00:45 +00:00
self.__prev_sib: Union['StoryDefine', None] = None
self.__next_sib: Union['StoryDefine', None] = None
2024-08-04 01:50:17 +00:00
pass
2024-08-04 02:00:45 +00:00
def parent_slice(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
pass
2024-08-04 02:00:45 +00:00
def set_prev(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
pass
2024-08-04 02:00:45 +00:00
def prev_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
pass
2024-08-04 02:00:45 +00:00
def set_next(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
pass
2024-08-04 02:00:45 +00:00
def next_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
pass
def index(self) -> int:
pass
class StoryDefine(ElementSlice, Collection):
def __init__(self, nm: str, idx: int):
self.__index = idx
self.__name = nm
2024-08-04 02:00:45 +00:00
self.__prev_sib: Union['StoryDefine', None] = None
self.__next_sib: Union['StoryDefine', None] = None
2024-08-04 01:50:17 +00:00
self.__children: List[ElementSlice] = []
pass
def type(self) -> SliceType:
return SliceType.StoryDefine
2024-08-04 02:00:45 +00:00
def parent_slice(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return None
2024-08-04 02:00:45 +00:00
def set_prev(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
self.__prev_sib = inst
pass
2024-08-04 02:00:45 +00:00
def prev_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__prev_sib
pass
2024-08-04 02:00:45 +00:00
def set_next(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
self.__next_sib = inst
pass
2024-08-04 02:00:45 +00:00
def next_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__next_sib
pass
def index(self) -> int:
return self.__index
pass
def children(self) -> List[ElementSlice]:
return self.__children
def name(self) -> str:
return self.__name
def calc_index(inst: ElementSlice) -> int:
temp_refer = inst.prev_sibling()
index_v = 0
while temp_refer is not None:
index_v += 1
temp_refer = temp_refer.prev_sibling()
pass
return index_v
class TextParagraph(ElementSlice):
def __init__(self, parent: ElementSlice):
self.__parent_node = parent
2024-08-04 02:00:45 +00:00
self.__prev_node: Union[ElementSlice, None] = None
self.__next_node: Union[ElementSlice, None] = None
2024-08-04 01:50:17 +00:00
self.__text_lines: List[str] = []
pass
def type(self) -> SliceType:
return SliceType.TextParagraph
2024-08-04 02:00:45 +00:00
def parent_slice(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__parent_node
2024-08-04 02:00:45 +00:00
def set_prev(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
self.__prev_node = inst
pass
2024-08-04 02:00:45 +00:00
def prev_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__prev_node
2024-08-04 02:00:45 +00:00
def set_next(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
self.__next_node = inst
inst.set_prev(self)
pass
2024-08-04 02:00:45 +00:00
def next_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__next_node
def index(self) -> int:
return calc_index(self)
class FragmentDefine(ElementSlice):
def __init__(self, nm:str, parent: ElementSlice):
self.__name = nm
self.__parent_inst = parent
2024-08-04 02:00:45 +00:00
self.__prev_node: Union[ElementSlice, None] = None
self.__next_node: Union[ElementSlice, None] = None
2024-08-04 01:50:17 +00:00
self.__refer_nodes: List[ElementSlice] = []
self.__description: TextParagraph = TextParagraph(self)
pass
def type(self) -> SliceType:
return SliceType.FragmentDefine
2024-08-04 02:00:45 +00:00
def parent_slice(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__parent_inst
2024-08-04 02:00:45 +00:00
def set_prev(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
self.__prev_node = inst
pass
2024-08-04 02:00:45 +00:00
def prev_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__prev_node
2024-08-04 02:00:45 +00:00
def set_next(self, inst: Union['ElementSlice', None]):
2024-08-04 01:50:17 +00:00
self.__next_node = inst
inst.set_prev(self)
pass
2024-08-04 02:00:45 +00:00
def next_sibling(self) -> Union['ElementSlice', None]:
2024-08-04 01:50:17 +00:00
return self.__next_node
def index(self) -> int:
return calc_index(self)
def name(self) -> str:
return self.__name
def refer_slices(self) -> List[ElementSlice]:
return self.__refer_nodes
def refer_append(self, e:ElementSlice):
return self.__refer_nodes.append(e)
def text_description(self) -> TextParagraph:
return self.__description
class FragmentRefer(ElementSlice):
def __init__(self, parent: ElementSlice):
2024-08-04 02:00:45 +00:00
pass
2024-08-04 01:50:17 +00:00
2024-07-29 02:26:16 +00:00
class FragmentSlice(EmptyNode):
2024-08-04 01:50:17 +00:00
def __init__(self, def_mark: bool = False, name: str = ""):
2024-07-29 02:26:16 +00:00
self.is_define_node = (def_mark, name)
2024-07-29 13:25:38 +00:00
self.parent_story = ""
2024-07-29 02:26:16 +00:00
self.story_refer = ""
self.fragm_refer = ""
2024-07-29 04:01:14 +00:00
self.fragm_sort_i = 0
2024-07-29 02:26:16 +00:00
2024-08-04 02:00:45 +00:00
self.prev_node: Union['FragmentSlice', None] = None # 上游节点
self.next_node: Union['FragmentSlice', None] = None # 下游节点
2024-08-04 01:50:17 +00:00
self.refers_slice: Dict[str, 'FragmentSlice'] = {} # 引用切面
2024-07-29 02:26:16 +00:00
2024-08-04 01:50:17 +00:00
self.text_sections: List[str] = [] # 文本段落
2024-07-29 02:26:16 +00:00
pass
def get_from_memory(self) -> str:
2024-07-29 13:25:38 +00:00
return "\n".join(self.text_sections)
2024-07-29 02:26:16 +00:00
pass
def set_to_memory(self, content: str):
2024-07-29 13:25:38 +00:00
self.text_sections = content.split("\n")
2024-07-29 02:26:16 +00:00
pass
2024-08-02 09:07:41 +00:00
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}"
2024-08-04 01:50:17 +00:00
self.refer_target: List[str] = [] # 引用切面
self.text_sections: List[str] = [] # 文本段落
2024-08-02 09:07:41 +00:00
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
2024-07-29 02:26:16 +00:00
class StoryMap:
def __init__(self, name: str):
self.story_name = name
self.sort_index = 0
self.empty_head = FragmentSlice()
2024-07-29 14:19:48 +00:00
self.empty_head.set_to_memory("<空节点>")
2024-07-29 02:26:16 +00:00
self.slice_list: List[FragmentSlice] = [self.empty_head]
pass
def append_fragment_slice(self, node: FragmentSlice):
self.slice_list[-1].next_node = node
2024-07-29 13:25:38 +00:00
node.parent_story = self.story_name
2024-07-29 02:26:16 +00:00
node.prev_node = self.slice_list[-1]
2024-07-29 04:01:14 +00:00
node.fragm_sort_i = len(self.slice_list)
2024-07-29 02:26:16 +00:00
self.slice_list.append(node)
pass
2024-08-04 02:00:45 +00:00
def get_fragment_defined(self, name: str) -> Union[FragmentSlice, None]:
2024-07-29 02:26:16 +00:00
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
2024-08-04 02:00:45 +00:00
def __extract_empty_storymap(self, name: str) -> Union[Tuple[StoryMap, mdom.Element], None]:
2024-07-29 02:26:16 +00:00
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"))
2024-07-31 03:47:09 +00:00
return mem_node, node
2024-07-29 02:26:16 +00:00
pass
return None
def __storynode_initfrags(self, node: StoryMap, e: mdom.Element):
first_elem: mdom.Element = e.firstChild
2024-08-04 01:50:17 +00:00
while first_elem is not None:
2024-07-29 02:26:16 +00:00
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
2024-08-04 01:50:17 +00:00
while node_elem is not None:
2024-07-29 02:26:16 +00:00
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
2024-07-31 03:47:09 +00:00
def get_story_graph(self) -> Dict[str, StoryMap]:
story_dict = storyline_list2map(self.story_list)
self.storylines_plait(story_dict)
return story_dict
2024-08-02 09:07:41 +00:00
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
2024-08-04 01:50:17 +00:00
def __volume_node_parse(self, vnode: mdom.Element) -> List[ArticleSlice]:
2024-08-02 09:07:41 +00:00
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
2024-08-04 01:50:17 +00:00
2024-07-29 02:26:16 +00:00
pass
def storyline_list2map(storylines: List[StoryMap]) -> Dict[str, StoryMap]:
retv = {}
for linst in storylines:
retv[linst.story_name] = linst
pass
return retv