GroupDocs.Parser provides functionality to extract the text structure from documents as an XML representation, preserving document hierarchy including sections, paragraphs, tables, and lists.
Prerequisites
GroupDocs.Parser for Python via .NET installed
Sample documents for testing
Understanding of XML structure
Document structure elements
The XML structure contains the following tags:
Tag
Description
document
The root tag
section
Represents a section (worksheet, slide, etc.). Attributes: style, name
p
Represents a text paragraph. Attribute: style
ul
Represents an unordered list
ol
Represents an ordered list
li
Represents a list item
shape
Represents a shape object
table
Represents a table
tr
Represents a table row
td
Represents a table cell. Attributes: rowIndex, columnIndex, rowSpan, columnSpan
hyperlink
Represents a hyperlink. Attribute: link
strong
Represents bold text
em
Represents italic text
br
Represents a line break
Extract text structure
To extract the document structure as XML:
fromgroupdocs.parserimportParserimportxml.etree.ElementTreeasET# Create an instance of Parser classwithParser("./sample.docx")asparser:# Extract text structurexml_reader=parser.get_structure()# Check if structure extraction is supportedifxml_readerisNone:print("Text structure extraction isn't supported")else:# Read XML contentxml_reader.move_to_content()xml_content=xml_reader.read_outer_xml()print(xml_content)
The following sample file is used in this example: sample.docx
<document><section><p>Supply Agreement | Harbor Lane Provisions and Northwind Coffee Roasters | Confidential</p><p style="TITLE"><strong>Supply Agreement</strong></p><p>Harbor Lane Provisions and Northwind Coffee Roasters</p><p style="HEADING1"><strong>1. Parties</strong></p><p><strong>Buyer: </strong>Harbor Lane Provisions, 18 Quayside Road, Port Ellery, represented by Lena Park, Procurement Lead.</p><p><strong>Supplier: </strong>Northwind Coffee Roasters, 4 Roastery Lane, Millbrook, repres
[TRUNCATED]
Expected behavior: Extracts all hyperlinks with their text and URLs from the document structure.
Extract table structure
To analyze table structure:
fromgroupdocs.parserimportParserimportxml.etree.ElementTreeasETdefanalyze_tables(file_path):"""
Analyze table structure in document.
"""withParser(file_path)asparser:xml_reader=parser.get_structure()ifxml_readerisNone:print("Structure extraction not supported")return# Parse XMLxml_reader.move_to_content()xml_content=xml_reader.read_outer_xml()root=ET.fromstring(xml_content)# Find all tablestables=root.findall('.//table')print(f"Found {len(tables)} tables:\n")foridx,tableinenumerate(tables,1):rows=table.findall('.//tr')print(f"Table {idx}:")print(f" Rows: {len(rows)}")# Get column count from first row (a merged cell counts its columnSpan)ifrows:cells=rows[0].findall('td')print(f" Columns: {sum(int(td.get('columnSpan','1'))fortdincells)}")# Show cell spanning (cells that span more than one row or column)cells_with_span=[tdfortdintable.findall('.//td')iftd.get('rowSpan','1')!='1'ortd.get('columnSpan','1')!='1']ifcells_with_span:print(f" Cells with spanning: {len(cells_with_span)}")print()# Usageanalyze_tables("sample.xlsx")
The following sample file is used in this example: sample.xlsx
Expected behavior: Extracts all bold and italic text from the document.
Save structure to file
To save the XML structure to a file:
fromgroupdocs.parserimportParserdefsave_structure_to_file(file_path,output_xml):"""
Extract and save document structure to XML file.
"""withParser(file_path)asparser:xml_reader=parser.get_structure()ifxml_readerisNone:print("Structure extraction not supported")returnFalse# Read and save XMLxml_reader.move_to_content()xml_content=xml_reader.read_outer_xml()withopen(output_xml,'w',encoding='utf-8')asf:f.write(xml_content)print(f"Structure saved to {output_xml}")returnTrue# Usagesave_structure_to_file("sample.docx","structure.xml")
The following sample file is used in this example: sample.docx
<document><section><p>Supply Agreement | Harbor Lane Provisions and Northwind Coffee Roasters | Confidential</p><p style="TITLE"><strong>Supply Agreement</strong></p><p>Harbor Lane Provisions and Northwind Coffee Roasters</p><p style="HEADING1"><strong>1. Parties</strong></p><p><strong>Buyer: </strong>Harbor Lane Provisions, 18 Quayside Road, Port Ellery, represented by Lena Park, Procurement Lead.</p><p><strong>Supplier: </strong>Northwind Coffee Roasters, 4 Roastery Lane, Millbrook, repres
[TRUNCATED]
Expected behavior: Saves the document structure as an XML file for further processing.
Extract section information
To extract information about document sections:
fromgroupdocs.parserimportParserimportxml.etree.ElementTreeasETdefextract_section_info(file_path):"""
Extract section information from document.
"""withParser(file_path)asparser:xml_reader=parser.get_structure()ifxml_readerisNone:print("Structure extraction not supported")return# Parse XMLxml_reader.move_to_content()xml_content=xml_reader.read_outer_xml()root=ET.fromstring(xml_content)# Find all sectionssections=root.findall('.//section')print(f"Document has {len(sections)} sections:\n")foridx,sectioninenumerate(sections,1):name=section.get('name',f'Section {idx}')style=section.get('style','default')# Count elements in sectionparagraphs=section.findall('.//p')tables=section.findall('.//table')lists=section.findall('.//ul')+section.findall('.//ol')print(f"Section: {name}")print(f" Style: {style}")print(f" Paragraphs: {len(paragraphs)}")print(f" Tables: {len(tables)}")print(f" Lists: {len(lists)}")print()# Usageextract_section_info("sample.pptx")
The following sample file is used in this example: sample.pptx