mirror of
https://github.com/opendatalab/MinerU.git
synced 2026-10-25 09:35:17 +08:00
分节与页眉页脚处理完成
This commit is contained in:
@@ -8,6 +8,7 @@ import logging
|
||||
from PIL import Image
|
||||
from loguru import logger
|
||||
from docx import Document
|
||||
from docx.document import Document as DocxDocument
|
||||
from docx.oxml.xmlchemy import BaseOxmlElement
|
||||
from docx.text.paragraph import Paragraph
|
||||
from docx.text.hyperlink import Hyperlink
|
||||
@@ -72,7 +73,8 @@ class DocxConverter:
|
||||
self.docx_obj = None
|
||||
self.max_levels: int = 10 # 文档层次结构的最大层级数
|
||||
self.parents: dict = {} # 父级节点映射
|
||||
self.blocks = []
|
||||
self.pages = []
|
||||
self.cur_page = []
|
||||
self.pre_num_id: int = -1 # 上一个处理元素的 numId
|
||||
self.pre_ilevel: int = -1 # 上一个处理元素的缩进等级, 用于判断列表层级
|
||||
self.list_block_stack: list = [] # 列表块堆栈
|
||||
@@ -81,13 +83,14 @@ class DocxConverter:
|
||||
) # 列表计数器 (numId, ilvl) -> count
|
||||
self.equation_bookends: str = "<eq>{EQ}</eq>" # 公式标记格式
|
||||
|
||||
|
||||
def convert(
|
||||
self,
|
||||
file_stream: BinaryIO,
|
||||
):
|
||||
self.docx_obj = Document(file_stream)
|
||||
self.pages.append(self.cur_page)
|
||||
self._walk_linear(self.docx_obj.element.body)
|
||||
self._add_header_footer(self.docx_obj)
|
||||
|
||||
def _walk_linear(
|
||||
self,
|
||||
@@ -165,7 +168,7 @@ class DocxConverter:
|
||||
"table_type": "",
|
||||
"table_nest_level": "",
|
||||
}
|
||||
self.blocks.append(table_block)
|
||||
self.cur_page.append(table_block)
|
||||
|
||||
def _handle_text_elements(
|
||||
self,
|
||||
@@ -179,10 +182,17 @@ class DocxConverter:
|
||||
doc: DoclingDocument 对象
|
||||
|
||||
Returns:
|
||||
list[RefItem]: 元素引用列表
|
||||
"""
|
||||
#TODO: 使用element.find(".//w:sectPr", namespaces=DocxConverter._BLIP_NAMESPACES) 找到分节位置,第一个分节符和最后一个是单独的p标签,而中间的是在最后一个body元素内的,需要分开判断
|
||||
|
||||
"""
|
||||
is_section_end = False
|
||||
if element.find(".//w:sectPr", namespaces=DocxConverter._BLIP_NAMESPACES):
|
||||
# 如果没有text内容
|
||||
if element.text == "":
|
||||
self.cur_page = []
|
||||
self.pages.append(self.cur_page)
|
||||
else:
|
||||
# 标记本节结束,处理完文本之后再分节
|
||||
is_section_end = True
|
||||
elem_ref = []
|
||||
paragraph = Paragraph(element, self.docx_obj)
|
||||
paragraph_elements = self._get_paragraph_elements(paragraph)
|
||||
@@ -251,7 +261,7 @@ class DocxConverter:
|
||||
}
|
||||
],
|
||||
}
|
||||
self.blocks.append(title_block)
|
||||
self.cur_page.append(title_block)
|
||||
elem_ref.append(id(title_block))
|
||||
|
||||
elif "Heading" in p_style_id:
|
||||
@@ -279,7 +289,7 @@ class DocxConverter:
|
||||
}
|
||||
],
|
||||
}
|
||||
self.blocks.append(h_block)
|
||||
self.cur_page.append(h_block)
|
||||
elem_ref.append(id(h_block))
|
||||
|
||||
elif len(equations) > 0:
|
||||
@@ -306,7 +316,7 @@ class DocxConverter:
|
||||
}
|
||||
],
|
||||
}
|
||||
self.blocks.append(eq_block)
|
||||
self.cur_page.append(eq_block)
|
||||
elem_ref.append(id(eq_block))
|
||||
else:
|
||||
# 行内公式
|
||||
@@ -320,7 +330,7 @@ class DocxConverter:
|
||||
}
|
||||
],
|
||||
}
|
||||
self.blocks.append(inline_eq_block)
|
||||
self.cur_page.append(inline_eq_block)
|
||||
elem_ref.append(id(inline_eq_block))
|
||||
text_tmp = text
|
||||
for eq in equations:
|
||||
@@ -401,7 +411,7 @@ class DocxConverter:
|
||||
}
|
||||
],
|
||||
}
|
||||
self.blocks.append(text_block)
|
||||
self.cur_page.append(text_block)
|
||||
elem_ref.append(id(text_block))
|
||||
else:
|
||||
# 文本样式名称不仅有默认值,还可能有用户自定义值
|
||||
@@ -424,9 +434,13 @@ class DocxConverter:
|
||||
}
|
||||
],
|
||||
}
|
||||
self.blocks.append(text_block)
|
||||
self.cur_page.append(text_block)
|
||||
elem_ref.append(id(text_block))
|
||||
|
||||
if is_section_end:
|
||||
self.cur_page = []
|
||||
self.pages.append(self.cur_page)
|
||||
|
||||
return elem_ref
|
||||
|
||||
def _handle_pictures(self, drawing_blip: Any):
|
||||
@@ -492,7 +506,7 @@ class DocxConverter:
|
||||
}
|
||||
],
|
||||
}
|
||||
self.blocks.append(image_block)
|
||||
self.cur_page.append(image_block)
|
||||
elem_ref.append(id(image_block))
|
||||
return elem_ref
|
||||
|
||||
@@ -858,7 +872,7 @@ class DocxConverter:
|
||||
"list_type": "text_list",
|
||||
"ilevel": ilevel,
|
||||
}
|
||||
self.blocks.append(list_block)
|
||||
self.cur_page.append(list_block)
|
||||
# 入栈, 记录当前的列表块
|
||||
self.list_block_stack.append(list_block)
|
||||
# 记录当前引用
|
||||
@@ -1135,3 +1149,50 @@ class DocxConverter:
|
||||
self.list_counters[key] = 0
|
||||
self.list_counters[key] += 1
|
||||
return self.list_counters[key]
|
||||
|
||||
def _add_header_footer(self, docx_obj: DocxDocument) -> None:
|
||||
"""
|
||||
处理页眉和页脚,按照分节顺序添加到 pages 列表中,
|
||||
分为整个文档是否启用奇偶页不同和每一节是否启用首页不同两种情况,
|
||||
暂不考虑包含图片和表格
|
||||
"""
|
||||
is_odd_even_different = docx_obj.settings.odd_and_even_pages_header_footer
|
||||
for sec_idx, section in enumerate(docx_obj.sections):
|
||||
hdrs = [section.header]
|
||||
if is_odd_even_different:
|
||||
hdrs.append(section.even_page_header)
|
||||
if section.different_first_page_header_footer:
|
||||
hdrs.append(section.first_page_header)
|
||||
for hdr in hdrs:
|
||||
par = [
|
||||
txt for txt in (par.text.strip() for par in hdr.paragraphs) if txt
|
||||
]
|
||||
|
||||
try:
|
||||
self.pages[sec_idx].append(
|
||||
{
|
||||
"type": BlockType.HEADER,
|
||||
"content": "".join(par),
|
||||
}
|
||||
)
|
||||
except IndexError:
|
||||
logger.error("Section index out of range when adding header.")
|
||||
|
||||
ftrs = [section.footer]
|
||||
if is_odd_even_different:
|
||||
ftrs.append(section.even_page_footer)
|
||||
if section.different_first_page_header_footer:
|
||||
ftrs.append(section.first_page_footer)
|
||||
for ftr in ftrs:
|
||||
par = [
|
||||
txt for txt in (par.text.strip() for par in ftr.paragraphs) if txt
|
||||
]
|
||||
try:
|
||||
self.pages[sec_idx].append(
|
||||
{
|
||||
"type": BlockType.FOOTER,
|
||||
"content": "".join(par),
|
||||
}
|
||||
)
|
||||
except IndexError:
|
||||
logger.error("Section index out of range when adding header.")
|
||||
|
||||
@@ -11,7 +11,7 @@ def convert_path(file_path: str):
|
||||
def convert_binary(file_binary: BinaryIO):
|
||||
converter = DocxConverter()
|
||||
converter.convert(file_binary)
|
||||
return converter.blocks
|
||||
return converter.pages
|
||||
|
||||
if __name__ == "__main__":
|
||||
# print(convert_path("test.docx"))
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user