Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

xx2html

PyPI Version CI License Buy Me a Coffee

xx2html converts Excel workbooks (.xlsx) into a single HTML file while preserving:

  • Cell formatting and styles
  • Conditional formatting classes (via condif2css)
  • Worksheet link behavior
  • Embedded worksheet images and in-cell rich-value images

Repository: https://github.com/gocova/xx2html
Issues: https://github.com/gocova/xx2html/issues

Installation

pip install xx2html

Usage

from xx2html import apply_openpyxl_patches, create_xlsx_transform

# Explicit entrypoint. Patches are also applied automatically on import.
apply_openpyxl_patches()

transform = create_xlsx_transform(
    sheet_html=(
        '<section id="{enc_sheet_name}" data-sheet-name="{sheet_name}">'
        "{table_generated_html}"
        "</section>"
    ),
    sheetname_html='<a class="sheet-nav" href="#{enc_sheet_name}">{sheet_name}</a>',
    index_html=(
        "<!doctype html><html><head>"
        "{fonts_html}{core_css_html}{user_css_html}{generated_css_html}"
        "{generated_incell_css_html}{conditional_css_html}"
        '</head><body data-source="{source_filename}">{sheets_names_generated_html}{sheets_generated_html}'
        "{safari_js}</body></html>"
    ),
    fonts_html="",
    core_css="",
    user_css="",
    safari_js="",
    apply_cf=True,
    max_sheets=3,   # optional preview limit
    max_rows=200,   # optional preview limit per sheet
    max_cols=20,    # optional preview limit per sheet
    raise_on_error=False,
)

ok, err = transform("input.xlsx", "output.html", "en_US")
if not ok:
    raise RuntimeError(err)

API Map

Public API (xx2html):

  • apply_openpyxl_patches() -> None
    • Applies required openpyxl monkey patches (idempotent).
  • create_xlsx_transform(...) -> Callable[[str, str, str], tuple[bool, str | None]]
    • Returns a transformer callable with signature (source_xlsx, dest_html, locale).
    • Returns (True, None) on success, (False, "<error repr>") on failure.
    • Optional preview controls:
      • max_sheets: convert only the first N visible sheets.
      • max_rows: convert only the first N rows per included sheet.
      • max_cols: convert only the first N columns per included sheet.
    • Optional error mode:
      • raise_on_error=True raises the original exception instead of returning (False, ...).

Core helpers (xx2html.core, useful for advanced integrations):

  • get_worksheet_contents(...) -> WorksheetContents
  • cova_render_table(worksheet_contents) -> str
  • get_incell_images_refs(archive) -> tuple[dict[str, str], Exception | None]
  • get_incell_css(...) -> str
  • apply_cf_styles(html, cf_style_relations) -> str
  • update_links(html, encoded_sheet_names, ...) -> str

Template Placeholders

sheet_html requires:

  • {enc_sheet_name}
  • {sheet_name}
  • {table_generated_html}

sheetname_html requires:

  • {enc_sheet_name}
  • {sheet_name}

index_html requires:

  • {sheets_generated_html}
  • {sheets_names_generated_html}
  • {source_filename}
  • {fonts_html}
  • {core_css_html}
  • {user_css_html}
  • {generated_css_html}
  • {generated_incell_css_html}
  • {conditional_css_html}

index_html optional:

  • {safari_js}
    • If omitted while safari_js is non-empty, xx2html logs a warning and skips injection.

Generated output also includes:

  • <meta name="generator" content="xx2html {version}"> in <head>
  • <!-- Generated by xx2html {version} --> as the first node in <body>

Monkey Patching Behavior

xx2html relies on an openpyxl monkey patch to carry rich-value metadata used for in-cell images.

  • The patch is applied automatically when xx2html.core is imported.
  • The explicit API entrypoint is apply_openpyxl_patches().
  • xx2html validates the openpyxl major/minor version before patching.
    • Set XX2HTML_ALLOW_UNSUPPORTED_OPENPYXL=1 to bypass the guard.

Development

pdm sync --group dev --frozen-lockfile
python3 tests/scripts/generate_fixtures.py
pdm run python -m compileall src tests
ruff check src tests
mypy src/xx2html
pdm run pytest

Release

  • Stable releases are tag-driven and use SemVer tags: vMAJOR.MINOR.PATCH (for example v1.2.3).
  • Push the tag to GitHub; the publish workflow builds from SCM metadata and publishes with PyPI Trusted Publishing.

License

xx2html is dual-licensed under MIT or Apache-2.0.

Metadata

Release files for xx2html 0.18.0rc1

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

Source distribution (sdist)

Source distribution for xx2html 0.18.0rc1
File Size Uploaded
xx2html-0.18.0rc1.tar.gz 139.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xx2html 0.18.0rc1
File Interpreter ABI Platform
xx2html-0.18.0rc1-py3-none-any.whl Python 3 none any Details

Total release size: 169.1 kB

Release files / xx2html-0.18.0rc1.tar.gz

Download URL xx2html-0.18.0rc1.tar.gz
Size 139.3 kB
Tags Source
SHA-256 checksum
How to use checksums
380e835bbe2061529bbf6a881805e84d45304292cab85ade25947b2ea5066ae1
BLAKE2b-256 checksum
How to use checksums
a22a8f8ffae78b2d3ef4c21630345e1297387ddde2a4b75c9e4e327d4d6187d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 19, 2026.

Transparency log

Release files / xx2html-0.18.0rc1-py3-none-any.whl

Download URL xx2html-0.18.0rc1-py3-none-any.whl
Size 29.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f529b18ce89458fa48c182ec513795f898bd9317669ce2df539d8c0f8c1554f4
BLAKE2b-256 checksum
How to use checksums
7c0b43914d706cfef612d68a4ef45e5d2b6b161ae616470f5dbb236ee7480c57
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 19, 2026.

Transparency log
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