Skip to main content

Confluence Content Parser

Important: This is an early-stage release. The API may change and using it in production carries risk. Pin versions and evaluate carefully before deployment.

PyPI version Python versions CI Coverage License Code Style

A powerful and comprehensive Python library for parsing Confluence Storage Format content into structured data models using Pydantic.

Features

✨ Comprehensive Coverage: Supports 40+ Confluence Storage Format elements and macros
🚀 High Performance: Built with lxml for fast XML parsing
🏗️ Structured Data: Uses Pydantic models for type-safe, validated data structures
📝 Modern Python: Built for Python 3.12+ with full type hints
🔧 Extensible: Clean architecture makes it easy to add new element types

Installation

# Using uv (recommended)
uv add confluence-content-parser

# Using pip
pip install confluence-content-parser

Quick Start

from confluence_content_parser import ConfluenceParser

# Initialize the parser
parser = ConfluenceParser()

# Parse Confluence Storage Format content
content = """
<ac:layout>
    <ac:layout-section ac:type="fixed-width">
        <ac:layout-cell>
            <h2>My Document</h2>
            <p>This is a <strong>bold</strong> paragraph.</p>
            <ac:structured-macro ac:name="info">
                <ac:rich-text-body>
                    <p>This is an info panel.</p>
                </ac:rich-text-body>
            </ac:structured-macro>
        </ac:layout-cell>
    </ac:layout-section>
</ac:layout>
"""

# Parse the content
document = parser.parse(content)

# Access the structured data
print(f"Document text: {document.text}")

# Find all nodes of specific types
from confluence_content_parser import HeadingElement, PanelMacro

headings = document.find_all(HeadingElement)
panels = document.find_all(PanelMacro)

# Or find multiple types at once
headings, panels = document.find_all(HeadingElement, PanelMacro)

print(f"Found {len(headings)} headings and {len(panels)} panels")

# Navigate the structure
for node in document.walk():
    print(f"Node type: {type(node).__name__}")

Examples

  • examples/basic_usage.py: Basic parsing, text extraction, and element traversal
  • examples/advanced_usage.py: Complex layouts, macros, nested content analysis
  • examples/diagnostics_usage.py: Error handling, unknown elements, and parsing diagnostics

Supported Elements & Macros

Text Elements

Element Node Class Description
<p> TextBreakElement Paragraph with text and formatting
<h1>-<h6> HeadingElement Heading levels 1-6
<strong>, <em>, <u> TextEffectElement Bold, italic, underline
<sub>, <sup>, <del> TextEffectElement Subscript, superscript, strikethrough
<blockquote> TextEffectElement Block quotations
<span> TextEffectElement Inline text with styling
<code> TextEffectElement Inline code formatting
Text content Text Plain text nodes

Lists & Structure

Element Node Class Description
<ul>, <ol> ListElement Unordered and ordered lists
<li> ListItem List items (regular and tasks)
<ac:task-list> ListElement Task lists
<ac:task> ListItem Individual task items
<table> Table Tables with headers and data
<tr> TableRow Table rows
<td>, <th> TableCell Table cells
<hr> TextBreakElement Horizontal dividers
<br> TextBreakElement Line breaks

Layout Elements

Element Node Class Description
<ac:layout> LayoutElement Page layout container
<ac:layout-section> LayoutSection Layout section with columns
<ac:layout-cell> LayoutCell Individual layout cell

Media Elements

Element Node Class Description
<ac:image> Image Images with attachments or URLs

Interactive Elements

Element Node Class Description
<ac:link> LinkElement Links to pages, users, attachments
<a> LinkElement External links and mailto
<ac:emoticon> Emoticon Confluence emoticons and emojis
<ac:placeholder> PlaceholderElement Dynamic content placeholders
<time> Time Date and time elements
<ri:*> ResourceIdentifier Resource identifiers (pages, attachments, etc.)

Macros

Macro Node Class Description
info, warning, note, tip PanelMacro Notification panels
panel PanelMacro Custom styled panels
code CodeMacro Syntax-highlighted code blocks
status StatusMacro Status indicators
jira JiraMacro JIRA issue integration
expand ExpandMacro Expandable content sections
details DetailsMacro Collapsible content sections
toc TocMacro Auto-generated table of contents
view-file ViewFileMacro File preview macro
viewpdf ViewPdfMacro PDF viewer macro
excerpt ExcerptMacro Content excerpts
excerpt-include ExcerptIncludeMacro Include content excerpts
include IncludeMacro Include other pages
attachments AttachmentsMacro List page attachments
profile ProfileMacro User profile display
anchor AnchorMacro Page anchors
tasks-report-macro TasksReportMacro Task reports

Advanced Elements

Element Node Class Description
<ac:adf-extension> PanelMacro, DecisionList ADF panel and decision list extensions
Decision lists DecisionList Decision tracking lists
Decision items DecisionListItem Individual decision items
Fragment Fragment Container for multiple top-level nodes

Advanced Usage

Working with Structured Data

from confluence_content_parser import ConfluenceParser, Image, ListElement, ListType

parser = ConfluenceParser()
document = parser.parse(confluence_content)

# Find all images in the document
images = document.find_all(Image)
for image in images:
    print(f"Image: {image.alt or 'No alt text'} ({image.width}x{image.height})")

# Find all task lists
all_lists = document.find_all(ListElement)
task_lists = [lst for lst in all_lists if lst.type == ListType.TASK]
for task_list in task_lists:
    print(f"Task list with {len(task_list.children)} tasks")

# Analyze content structure efficiently
images, tables, links = document.find_all(Image, Table, LinkElement)
print(f"Document contains: {len(images)} images, {len(tables)} tables, {len(links)} links")

# Walk through all nodes in the document
for node in document.walk():
    if hasattr(node, 'text') and node.text:
        print(f"Text node: {node.text[:50]}...")

Custom Processing

from confluence_content_parser import ConfluenceParser, Text

parser = ConfluenceParser()
document = parser.parse(content)

# Extract all text content (built-in method)
full_text = document.text
print(f"Document text: {full_text}")

# Or manually collect text nodes
text_nodes = document.find_all(Text)
all_text = " ".join(node.text for node in text_nodes)
print(f"All text: {all_text}")

# Custom traversal
def find_nodes_with_condition(document, condition_func):
    """Find all nodes matching a custom condition."""
    matching_nodes = []
    for node in document.walk():
        if condition_func(node):
            matching_nodes.append(node)
    return matching_nodes

# Example: Find all nodes that contain specific text
nodes_with_api = find_nodes_with_condition(
    document, 
    lambda node: hasattr(node, 'text') and 'API' in getattr(node, 'text', '')
)

Error Handling

from confluence_content_parser import ConfluenceParser, ParsingError
import xml.etree.ElementTree as ET

# Default behavior: collect diagnostics without raising errors
parser = ConfluenceParser(raise_on_finish=False)

try:
    document = parser.parse(malformed_content)
    # Check diagnostics for any issues
    diagnostics = document.metadata.get("diagnostics", [])
    if diagnostics:
        print(f"Parsing issues found: {diagnostics}")
except ET.ParseError as e:
    print(f"XML parsing error: {e}")

# Strict parsing: raise errors for unknown elements
strict_parser = ConfluenceParser(raise_on_finish=True)
try:
    document = strict_parser.parse(content_with_unknown_elements)
except ParsingError as e:
    print(f"Parsing failed with diagnostics: {e.diagnostics}")

Diagnostics

The parser collects non-fatal parsing notes (e.g., unknown macros) in document.metadata["diagnostics"].

from confluence_content_parser import ConfluenceParser

parser = ConfluenceParser(raise_on_finish=False)
doc = parser.parse('<ac:structured-macro ac:name="unknown-macro"/>')
diagnostics = doc.metadata.get("diagnostics", [])
for diagnostic in diagnostics:
    print(diagnostic)  # Outputs: unknown_macro:unknown-macro
# See examples/diagnostics_usage.py for a complete example

Development

Setup

# Clone the repository
git clone https://github.com/Unificon/confluence-content-parser.git
cd confluence-content-parser

# Install dependencies with uv
uv sync --dev

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=confluence_content_parser --cov-report=html

Project Structure

src/confluence_content_parser/
├── __init__.py           # Main exports
├── parser.py            # Core parser implementation
├── document.py          # ConfluenceDocument model
└── nodes.py             # All node types and models

Running Tests

# Run all tests
uv run pytest

# Run with coverage report
uv run pytest --cov=confluence_content_parser --cov-report=term-missing

# Run specific test file
uv run pytest tests/test_parser.py

# Run with verbose output
uv run pytest -v

Code Quality

# Format code
uv run black src/ tests/

# Lint code  
uv run ruff check src/ tests/

# Type checking
uv run mypy src/

Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes with tests
  4. Ensure all tests pass: uv run pytest
  5. Submit a pull request

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Acknowledgments

  • Built with lxml for robust XML parsing
  • Uses Pydantic for data validation and serialization
  • Uses types-lxml for lxml type annotations
  • Inspired by the Confluence Storage Format specification

Metadata

Release files for confluence-content-parser 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for confluence-content-parser 0.2.1
File Size Uploaded
confluence_content_parser-0.2.1.tar.gz 17.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for confluence-content-parser 0.2.1
File Interpreter ABI Platform
confluence_content_parser-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 36.8 kB

Release files / confluence_content_parser-0.2.1.tar.gz

Download URL confluence_content_parser-0.2.1.tar.gz
Size 17.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b8f11dfc66e43ca0cd9c55a33456b5f3cbc4d891059a2904f74d9844fa7a6ccd
BLAKE2b-256 checksum
How to use checksums
f9610be7ba69168e38807a0da3810865e5b3887d17ad0a0f3434412969196bca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.13

Release files / confluence_content_parser-0.2.1-py3-none-any.whl

Download URL confluence_content_parser-0.2.1-py3-none-any.whl
Size 19.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
950a50a0367444316a8d44cbbe0cc9c4f756908f12d9a7896b5c42a5920108c8
BLAKE2b-256 checksum
How to use checksums
7406a444cd86260ee9c756f5723bff31eacf86e358f3275fec85c4643c4b0f84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.13

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page