XBRL Document Conversion
This example demonstrates how to parse XBRL (eXtensible Business Reporting Language) documents using Docling, completely offline.
XBRL is a standard XML-based format used globally by companies, regulators, and financial institutions for exchanging business and financial information in a structured, machine-readable format. It's widely adopted for regulatory filings (e.g., SEC filings in the US).
What you'll learn
- How to configure Docling to parse XBRL documents offline
- How to provide a local taxonomy package for XBRL validation
- How to extract structured data from XBRL instance documents
- How to export XBRL content to various formats (Markdown, JSON, etc.)
The data to run this notebook has been fetched from the SEC's Electronic Data Gathering, Analysis, and Retrieval (EDGAR) system.
Setup
Install Docling with XBRL support:
%pip install -q docling
/Users/ceb/git/docling-3/.venv/bin/python: No module named pip
Note: you may need to restart the kernel to use updated packages.
Download Sample XBRL Data
For this example, we'll use a sample XBRL instance document and its taxonomy. In a real scenario, you would have your own XBRL files and taxonomy packages.
We'll download the test data from the Docling repository:
import urllib.request
from pathlib import Path
# Create directories for XBRL data
data_dir = Path("xbrl_data")
taxonomy_dir = data_dir / "taxonomy"
taxonomy_dir.mkdir(parents=True, exist_ok=True)
# Base URL for test data
base_url = (
"https://raw.githubusercontent.com/docling-project/docling/main/tests/data/xbrl/"
)
# Download XBRL instance file
instance_file = data_dir / "mlac-20251231.xml"
if not instance_file.exists():
print("Downloading XBRL instance file...")
urllib.request.urlretrieve(f"{base_url}mlac-20251231.xml", instance_file)
print(f"Downloaded: {instance_file}")
# Download taxonomy files
taxonomy_files = [
"mlac-20251231.xsd",
"mlac-20251231_cal.xml",
"mlac-20251231_def.xml",
"mlac-20251231_lab.xml",
"mlac-20251231_pre.xml",
]
print("Downloading taxonomy files...")
for filename in taxonomy_files:
target_file = taxonomy_dir / filename
if not target_file.exists():
urllib.request.urlretrieve(f"{base_url}mlac-taxonomy/{filename}", target_file)
print(f" Downloaded: {filename}")
# Download taxonomy package (contains URL mappings for offline parsing)
taxonomy_package = taxonomy_dir / "taxonomy_package.zip"
if not taxonomy_package.exists():
print("Downloading taxonomy package...")
urllib.request.urlretrieve(
f"{base_url}mlac-taxonomy/taxonomy_package.zip", taxonomy_package
)
print(" Downloaded: taxonomy_package.zip")
print("\nAll files downloaded successfully!")
Downloading XBRL instance file...
Downloaded: xbrl_data/mlac-20251231.xml
Downloading taxonomy files...
Downloaded: mlac-20251231.xsd
Downloaded: mlac-20251231_cal.xml
Downloaded: mlac-20251231_def.xml
Downloaded: mlac-20251231_lab.xml
Downloaded: mlac-20251231_pre.xml
Downloading taxonomy package...
Downloaded: taxonomy_package.zip
All files downloaded successfully!
Configure XBRL Backend
To parse XBRL documents offline, we need to:
- Enable local resource fetching (for taxonomy files)
- Disable remote resource fetching (for offline operation)
- Provide the path to the local taxonomy directory
from docling.datamodel.backend_options import XBRLBackendOptions
from docling.datamodel.base_models import InputFormat
from docling.document_converter import DocumentConverter, XBRLFormatOption
# Configure XBRL backend options
backend_options = XBRLBackendOptions(
enable_local_fetch=True, # Allow reading local taxonomy files
enable_remote_fetch=False, # Disable remote fetching for offline operation
taxonomy=taxonomy_dir, # Path to local taxonomy directory
)
# Create document converter with XBRL support
converter = DocumentConverter(
allowed_formats=[InputFormat.XML_XBRL],
format_options={
InputFormat.XML_XBRL: XBRLFormatOption(backend_options=backend_options)
},
)
print("XBRL converter configured successfully!")
XBRL converter configured successfully!
π‘ Because the converter must read the supporting taxonomy files, set the enable_local_fetch option to True in the XBRL backend settings.
π‘ In addition to the XBRL report's own taxonomy files, you need a taxonomy package-a bundle containing URL remappings that enables completely offline parsing. If you prefer not to supply a taxonomy package, omit it and set enable_remote_fetch to True in the XBRL backend settings. The backend will fetch the webβreferenced files from the remote publishers and cache them locally for reuse.
Convert XBRL Document
Now we can convert the XBRL instance document. The converter will:
- Parse the XBRL instance file
- Validate it against the local taxonomy
- Extract metadata, text blocks, and numeric facts
- Convert everything to a unified DoclingDocument representation
# Convert the XBRL document
print(f"Converting XBRL document: {instance_file}")
result = converter.convert(instance_file)
doc = result.document
print("\nConversion successful!")
print(f"Document name: {doc.name}")
print(f"Number of items: {len(list(doc.iterate_items()))}")
Converting XBRL document: xbrl_data/mlac-20251231.xml
Conversion successful!
Document name: mlac-20251231
Number of items: 292
Inspect Document Structure
Let's examine the structure of the converted document:
from docling_core.types.doc import DocItemLabel
# Count items by type
item_counts = {}
for item, _ in doc.iterate_items():
label = item.label
item_counts[label] = item_counts.get(label, 0) + 1
print("Document structure:")
for label, count in sorted(item_counts.items(), key=lambda x: x[1], reverse=True):
print(f" {label.value}: {count}")
Document structure:
text: 267
table: 23
title: 1
key_value_region: 1
View Sample Content
Let's look at some of the extracted content:
# Display first few text items
print("Sample text content:\n")
text_count = 0
for item, _ in doc.iterate_items():
if item.label == DocItemLabel.TEXT and text_count < 3:
print(f"- {item.text[:200]}..." if len(item.text) > 200 else f"- {item.text}")
print()
text_count += 1
Sample text content:
- None
- We are a special purpose acquisition company with no business operations. Since our initial public offering, our sole business activity has been identifying and evaluating suitable acquisition transac...
- We depend on digital technologies, including information systems, infrastructure and cloud applications and services, including those of third parties with which we may deal. Sophisticated and deliber...
View Key-Value Pairs
XBRL numeric facts are extracted as key-value pairs:
# Display sample key-value pairs
graph_data = doc.key_value_items[0].graph
print(f"Total key-value pairs extracted: {len(graph_data.links)}\n")
for link in graph_data.links[:10]:
source = next(
item for item in graph_data.cells if item.cell_id == link.source_cell_id
)
target = next(
item for item in graph_data.cells if item.cell_id == link.target_cell_id
)
print(f"{source.text} -> {target.text}")
Total key-value pairs extracted: 319
EntityPublicFloat -> 239160600
EntityCommonStockSharesOutstanding -> 23805000
EntityCommonStockSharesOutstanding -> 7187500
Cash -> 452680
Cash -> 1383392
OtherPrepaidExpenseCurrent -> 16840
OtherPrepaidExpenseCurrent -> 23669
PrepaidInsurance -> 87776
PrepaidInsurance -> 92500
AssetsCurrent -> 557296
π‘ The current backend implementation flattens all keyβvalue pairs in an XBRL report. Future improvements will preserve the rich taxonomy of those data points.
Export to Markdown
Export the document to Markdown format for easy reading:
# Export to Markdown
markdown_content = doc.export_to_markdown()
# Display first 2000 characters
print("Markdown export (first 2000 characters):\n")
print(markdown_content[:2000])
print("\n...")
# Save to file
output_md = data_dir / "output.md"
output_md.write_text(markdown_content)
print(f"\nFull markdown saved to: {output_md}")
Markdown export (first 2000 characters):
# 10-K MOUNTAIN LAKE ACQUISITION CORP. 2025-12-31
None
We are a special purpose acquisition company with no business operations. Since our initial public offering, our sole business activity has been identifying and evaluating suitable acquisition transaction candidates. Therefore, we do not consider that we face significant cybersecurity risk and have not adopted any cybersecurity risk management program or formal processes for assessing cybersecurity risk.
We depend on digital technologies, including information systems, infrastructure and cloud applications and services, including those of third parties with which we may deal. Sophisticated and deliberate attacks on, or security breaches in, our information systems or infrastructure, or the information systems or infrastructure of third parties or the cloud, could lead to corruption or misappropriation of our assets, proprietary information and sensitive or confidential data. Because of our reliance on the technologies of third parties, we also depend upon the personnel and the processes of third parties to protect against cybersecurity threats. In the event of a cybersecurity incident impacting us, the management team will report to the board of directors and provide updates on the management team's incident response plan for addressing and mitigating any risks associated with the cybersecurity incident. As an early-stage company without significant investments in data security protection, there can be no assurance that we will have sufficient resources to adequately protect against, or to investigate and remediate any vulnerability to, cyber incidents. It is possible that any of these occurrences, or a combination of them, could have adverse consequences on our business and lead to financial loss.
As of the date of this Report, we have not identified any risks from cybersecurity threats, including as a result of any previous cybersecurity incidents, that we believe have, or are likely to, materially affect
...
Full markdown saved to: xbrl_data/output.md
Export to JSON
Export the complete document structure to JSON:
import json
# Export to JSON
output_json = data_dir / "output.json"
doc.save_as_json(output_json)
print(f"Document exported to JSON: {output_json}")
print(f"File size: {output_json.stat().st_size / 1024:.2f} KB")
Document exported to JSON: xbrl_data/output.json
File size: 1538.26 KB
Summary
In this example, we demonstrated:
β
How to configure Docling for offline XBRL parsing
β
How to provide a local taxonomy for XBRL validation
β
How to convert XBRL instance documents to DoclingDocument
β
How to extract metadata, text blocks, and numeric facts
β
How to export XBRL content to Markdown and JSON formats
Key Points
- Offline operation: By setting
enable_remote_fetch=False, all processing happens locally - Taxonomy support: The local taxonomy directory should contain all necessary schema and linkbase files
- Structured extraction: XBRL numeric facts are extracted as key-value pairs with graph representation
- Text blocks: HTML text blocks in XBRL are converted to structured content
Note on Future Changes
β οΈ The current implementation uses DoclingDocument's GraphData object to represent key-value pairs. This design will change in a future release of the docling-core library.