feat: RuleDocParser 规则文档 Markdown 化与分类
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from docx import Document
|
||||
from docx.oxml.ns import qn
|
||||
|
||||
from genesis.data_models import RuleDocument
|
||||
from genesis.parsers._word_common import heading_level
|
||||
|
||||
# 列表项前缀(真实样本为 Normal 样式 + ・ 前缀,样式名通道不足以命中)
|
||||
LIST_PREFIXES = ("・", "-", "•")
|
||||
|
||||
|
||||
def _is_list_item(text: str, style_name: str) -> bool:
|
||||
"""双通道列表检测:List 样式或文本前缀(spec §3.3)。"""
|
||||
if "List" in style_name:
|
||||
return True
|
||||
return text.startswith(LIST_PREFIXES)
|
||||
|
||||
|
||||
def _table_to_markdown(table) -> list[str]:
|
||||
"""docx 表格 → GFM 表格行。"""
|
||||
lines: list[str] = []
|
||||
for r_idx, row in enumerate(table.rows):
|
||||
cells = [cell.text.replace("|", "\\|").strip() for cell in row.cells]
|
||||
lines.append("| " + " | ".join(cells) + " |")
|
||||
if r_idx == 0:
|
||||
lines.append("| " + " | ".join(["---"] * len(cells)) + " |")
|
||||
return lines
|
||||
|
||||
|
||||
class RuleDocParser:
|
||||
"""规则文档 docx 解析:Markdown 化 + 分类。"""
|
||||
|
||||
def parse(self, path: str | Path, category: str = "write") -> RuleDocument:
|
||||
doc = Document(str(path))
|
||||
md: list[str] = []
|
||||
|
||||
# 按文档顺序遍历段落与表格(body 级子元素)
|
||||
for child in doc.element.body.iterchildren():
|
||||
tag = child.tag
|
||||
if tag == qn("w:p"):
|
||||
from docx.text.paragraph import Paragraph
|
||||
para = Paragraph(child, doc)
|
||||
text = para.text
|
||||
style_name = para.style.name if para.style else "Normal"
|
||||
stripped = text.strip()
|
||||
if not stripped:
|
||||
md.append("")
|
||||
elif style_name.startswith("Heading"):
|
||||
md.append("#" * heading_level(style_name) + " " + stripped)
|
||||
elif _is_list_item(stripped, style_name):
|
||||
md.append("- " + stripped.lstrip("・-•").strip())
|
||||
else:
|
||||
md.append(stripped)
|
||||
elif tag == qn("w:tbl"):
|
||||
from docx.table import Table
|
||||
md.extend(_table_to_markdown(Table(child, doc)))
|
||||
md.append("")
|
||||
|
||||
content = "\n".join(md).strip()
|
||||
return RuleDocument(
|
||||
file_name=Path(path).name,
|
||||
category=category,
|
||||
markdown_content=content,
|
||||
source_path=str(path),
|
||||
file_type="word",
|
||||
hash=hashlib.sha256(Path(path).read_bytes()).hexdigest(),
|
||||
)
|
||||
Reference in New Issue
Block a user