From 12a0e648929ce75da73617904792a50f5145fe4a Mon Sep 17 00:00:00 2001 From: AndrewTsai0406 <33444357+AndrewTsai0406@users.noreply.github.com> Date: Mon, 19 May 2025 21:01:36 +0800 Subject: [PATCH] feat: add textbox content extraction in msword_backend (#1538) * feat: add textbox content extraction in msword_backend Signed-off-by: Andrew * feat: add textbox content extraction in msword_backend Signed-off-by: Andrew * feat: add textbox content extraction in msword_backend Signed-off-by: Andrew --------- Signed-off-by: Andrew --- docling/backend/msword_backend.py | 281 ++++++++++++++++++++++++++++-- tests/data/docx/textbox.docx | Bin 0 -> 48867 bytes tests/test_backend_msword.py | 21 +++ 3 files changed, 290 insertions(+), 12 deletions(-) create mode 100644 tests/data/docx/textbox.docx diff --git a/docling/backend/msword_backend.py b/docling/backend/msword_backend.py index f136222..6cfa086 100644 --- a/docling/backend/msword_backend.py +++ b/docling/backend/msword_backend.py @@ -2,7 +2,7 @@ import logging import re from io import BytesIO from pathlib import Path -from typing import Any, Optional, Union +from typing import Any, List, Optional, Union from docling_core.types.doc import ( DocItemLabel, @@ -24,7 +24,6 @@ from docx.text.hyperlink import Hyperlink from docx.text.paragraph import Paragraph from docx.text.run import Run from lxml import etree -from lxml.etree import XPath from PIL import Image, UnidentifiedImageError from pydantic import AnyUrl from typing_extensions import override @@ -59,6 +58,11 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): self.parents: dict[int, Optional[NodeItem]] = {} self.numbered_headers: dict[int, int] = {} self.equation_bookends: str = "{EQ}" + # Track processed textbox elements to avoid duplication + self.processed_textbox_elements: List[int] = [] + # Track content hash of processed paragraphs to avoid duplicate content + self.processed_paragraph_content: List[str] = [] + for i in range(-1, self.max_levels): self.parents[i] = None @@ -175,10 +179,74 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): "a": "http://schemas.openxmlformats.org/drawingml/2006/main", "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships", "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + "wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + "mc": "http://schemas.openxmlformats.org/markup-compatibility/2006", + "v": "urn:schemas-microsoft-com:vml", + "wps": "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + "w10": "urn:schemas-microsoft-com:office:word", + "a14": "http://schemas.microsoft.com/office/drawing/2010/main", } - xpath_expr = XPath(".//a:blip", namespaces=namespaces) + xpath_expr = etree.XPath(".//a:blip", namespaces=namespaces) drawing_blip = xpath_expr(element) + # Check for textbox content - check multiple textbox formats + # Only process if the element hasn't been processed before + element_id = id(element) + if element_id not in self.processed_textbox_elements: + # Modern Word textboxes + txbx_xpath = etree.XPath( + ".//w:txbxContent|.//v:textbox//w:p", namespaces=namespaces + ) + textbox_elements = txbx_xpath(element) + + # No modern textboxes found, check for alternate/legacy textbox formats + if not textbox_elements and tag_name in ["drawing", "pict"]: + # Additional checks for textboxes in DrawingML and VML formats + alt_txbx_xpath = etree.XPath( + ".//wps:txbx//w:p|.//w10:wrap//w:p|.//a:p//a:t", + namespaces=namespaces, + ) + textbox_elements = alt_txbx_xpath(element) + + # Check for shape text that's not in a standard textbox + if not textbox_elements: + shape_text_xpath = etree.XPath( + ".//a:bodyPr/ancestor::*//a:t|.//a:txBody//a:t", + namespaces=namespaces, + ) + shape_text_elements = shape_text_xpath(element) + if shape_text_elements: + # Create custom text elements from shape text + text_content = " ".join( + [t.text for t in shape_text_elements if t.text] + ) + if text_content.strip(): + _log.debug(f"Found shape text: {text_content[:50]}...") + # Create a paragraph-like element to process with standard handler + level = self._get_level() + shape_group = doc.add_group( + label=GroupLabel.SECTION, + parent=self.parents[level - 1], + name="shape-text", + ) + doc.add_text( + label=DocItemLabel.PARAGRAPH, + parent=shape_group, + text=text_content, + ) + + if textbox_elements: + # Mark the parent element as processed + self.processed_textbox_elements.append(element_id) + # Also mark all found textbox elements as processed + for tb_element in textbox_elements: + self.processed_textbox_elements.append(id(tb_element)) + + _log.debug( + f"Found textbox content with {len(textbox_elements)} elements" + ) + self._handle_textbox_content(textbox_elements, docx_obj, doc) + # Check for Tables if element.tag.endswith("tbl"): try: @@ -291,15 +359,17 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): @classmethod def _get_format_from_run(cls, run: Run) -> Optional[Formatting]: - has_any_formatting = run.bold or run.italic or run.underline - return ( - Formatting( - bold=run.bold or False, - italic=run.italic or False, - underline=run.underline or False, - ) - if has_any_formatting - else None + # The .bold and .italic properties are booleans, but .underline can be an enum + # like WD_UNDERLINE.THICK (value 6), so we need to convert it to a boolean + has_bold = run.bold or False + has_italic = run.italic or False + # Convert any non-None underline value to True + has_underline = bool(run.underline is not None and run.underline) + + return Formatting( + bold=has_bold, + italic=has_italic, + underline=has_underline, ) def _get_paragraph_elements(self, paragraph: Paragraph): @@ -355,6 +425,182 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): return paragraph_elements + def _get_paragraph_position(self, paragraph_element): + """Extract vertical position information from paragraph element.""" + # First try to directly get the index from w:p element that has an order-related attribute + if ( + hasattr(paragraph_element, "getparent") + and paragraph_element.getparent() is not None + ): + parent = paragraph_element.getparent() + # Get all paragraph siblings + paragraphs = [ + p for p in parent.getchildren() if etree.QName(p).localname == "p" + ] + # Find index of current paragraph within its siblings + try: + paragraph_index = paragraphs.index(paragraph_element) + return paragraph_index # Use index as position for consistent ordering + except ValueError: + pass + + # Look for position hints in element attributes and ancestor elements + for elem in (*[paragraph_element], *paragraph_element.iterancestors()): + # Check for direct position attributes + for attr_name in ["y", "top", "positionY", "y-position", "position"]: + value = elem.get(attr_name) + if value: + try: + # Remove any non-numeric characters (like 'pt', 'px', etc.) + clean_value = re.sub(r"[^0-9.]", "", value) + if clean_value: + return float(clean_value) + except (ValueError, TypeError): + pass + + # Check for position in transform attribute + transform = elem.get("transform") + if transform: + # Extract translation component from transform matrix + match = re.search(r"translate\([^,]+,\s*([0-9.]+)", transform) + if match: + try: + return float(match.group(1)) + except ValueError: + pass + + # Check for anchors or relative position indicators in Word format + # 'dist' attributes can indicate relative positioning + for attr_name in ["distT", "distB", "anchor", "relativeFrom"]: + if elem.get(attr_name) is not None: + return elem.sourceline # Use the XML source line number as fallback + + # For VML shapes, look for specific attributes + for ns_uri in paragraph_element.nsmap.values(): + if "vml" in ns_uri: + # Try to extract position from style attribute + style = paragraph_element.get("style") + if style: + match = re.search(r"top:([0-9.]+)pt", style) + if match: + try: + return float(match.group(1)) + except ValueError: + pass + + # If no better position indicator found, use XML source line number as proxy for order + return ( + paragraph_element.sourceline + if hasattr(paragraph_element, "sourceline") + else None + ) + + def _collect_textbox_paragraphs(self, textbox_elements): + """Collect and organize paragraphs from textbox elements.""" + processed_paragraphs = [] + container_paragraphs = {} + + for element in textbox_elements: + element_id = id(element) + # Skip if we've already processed this exact element + if element_id in processed_paragraphs: + continue + + tag_name = etree.QName(element).localname + processed_paragraphs.append(element_id) + + # Handle paragraphs directly found (VML textboxes) + if tag_name == "p": + # Find the containing textbox or shape element + container_id = None + for ancestor in element.iterancestors(): + if any(ns in ancestor.tag for ns in ["textbox", "shape", "txbx"]): + container_id = id(ancestor) + break + + if container_id not in container_paragraphs: + container_paragraphs[container_id] = [] + container_paragraphs[container_id].append( + (element, self._get_paragraph_position(element)) + ) + + # Handle txbxContent elements (Word DrawingML textboxes) + elif tag_name == "txbxContent": + paragraphs = element.findall(".//w:p", namespaces=element.nsmap) + container_id = id(element) + if container_id not in container_paragraphs: + container_paragraphs[container_id] = [] + + for p in paragraphs: + p_id = id(p) + if p_id not in processed_paragraphs: + processed_paragraphs.append(p_id) + container_paragraphs[container_id].append( + (p, self._get_paragraph_position(p)) + ) + else: + # Try to extract any paragraphs from unknown elements + paragraphs = element.findall(".//w:p", namespaces=element.nsmap) + container_id = id(element) + if container_id not in container_paragraphs: + container_paragraphs[container_id] = [] + + for p in paragraphs: + p_id = id(p) + if p_id not in processed_paragraphs: + processed_paragraphs.append(p_id) + container_paragraphs[container_id].append( + (p, self._get_paragraph_position(p)) + ) + + return container_paragraphs + + def _handle_textbox_content( + self, + textbox_elements: list, + docx_obj: DocxDocument, + doc: DoclingDocument, + ) -> None: + """Process textbox content and add it to the document structure.""" + level = self._get_level() + # Create a textbox group to contain all text from the textbox + textbox_group = doc.add_group( + label=GroupLabel.SECTION, parent=self.parents[level - 1], name="textbox" + ) + + # Set this as the current parent to ensure textbox content + # is properly nested in document structure + original_parent = self.parents[level] + self.parents[level] = textbox_group + + # Collect and organize paragraphs + container_paragraphs = self._collect_textbox_paragraphs(textbox_elements) + + # Process all paragraphs + all_paragraphs = [] + + # Sort paragraphs within each container, then process containers + for container_id, paragraphs in container_paragraphs.items(): + # Sort by vertical position within each container + sorted_container_paragraphs = sorted( + paragraphs, + key=lambda x: ( + x[1] is None, + x[1] if x[1] is not None else float("inf"), + ), + ) + + # Add the sorted paragraphs to our processing list + all_paragraphs.extend(sorted_container_paragraphs) + + # Process all the paragraphs + for p, _ in all_paragraphs: + self._handle_text_elements(p, docx_obj, doc, is_from_textbox=True) + + # Restore original parent + self.parents[level] = original_parent + return + def _handle_equations_in_text(self, element, text): only_texts = [] only_equations = [] @@ -423,10 +669,21 @@ class MsWordDocumentBackend(DeclarativeDocumentBackend): element: BaseOxmlElement, docx_obj: DocxDocument, doc: DoclingDocument, + is_from_textbox: bool = False, ) -> None: paragraph = Paragraph(element, docx_obj) + # Skip if from a textbox and this exact paragraph content was already processed + # Skip if from a textbox and this exact paragraph content was already processed raw_text = paragraph.text + if is_from_textbox and raw_text: + # Create a simple hash of content to detect duplicates + content_hash = f"{len(raw_text)}:{raw_text[:50]}" + if content_hash in self.processed_paragraph_content: + _log.debug(f"Skipping duplicate paragraph content: {content_hash}") + return + self.processed_paragraph_content.append(content_hash) + text, equations = self._handle_equations_in_text(element=element, text=raw_text) if text is None: diff --git a/tests/data/docx/textbox.docx b/tests/data/docx/textbox.docx new file mode 100644 index 0000000000000000000000000000000000000000..8945f25efbf7a824f124aa9a7d7fdb4829d42985 GIT binary patch literal 48867 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 F{tuL{pIHC^ literal 0 HcmV?d00001 diff --git a/tests/test_backend_msword.py b/tests/test_backend_msword.py index c50e071..3c1500e 100644 --- a/tests/test_backend_msword.py +++ b/tests/test_backend_msword.py @@ -16,6 +16,27 @@ from .verify_utils import verify_document, verify_export GENERATE = GEN_TEST_DATA +def test_textbox_extraction(): + in_path = Path("tests/data/docx/textbox.docx") + in_doc = InputDocument( + path_or_stream=in_path, + format=InputFormat.DOCX, + backend=MsWordDocumentBackend, + ) + backend = MsWordDocumentBackend( + in_doc=in_doc, + path_or_stream=in_path, + ) + doc = backend.convert() + + # Verify if a particular textbox content is extracted + textbox_found = False + for item, _ in doc.iterate_items(): + if item.text[:30] == """Suggested Reportable Symptoms:""": + textbox_found = True + assert textbox_found + + def test_heading_levels(): in_path = Path("tests/data/docx/word_sample.docx") in_doc = InputDocument(