This release is a pre-release and may not be stable for production use.
xx2html
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=Trueraises the original exception instead of returning(False, ...).
- Returns a transformer callable with signature
Core helpers (xx2html.core, useful for advanced integrations):
get_worksheet_contents(...) -> WorksheetContentscova_render_table(worksheet_contents) -> strget_incell_images_refs(archive) -> tuple[dict[str, str], Exception | None]get_incell_css(...) -> strapply_cf_styles(html, cf_style_relations) -> strupdate_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_jsis non-empty, xx2html logs a warning and skips injection.
- If omitted while
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.coreis imported. - The explicit API entrypoint is
apply_openpyxl_patches(). xx2htmlvalidates theopenpyxlmajor/minor version before patching.- Set
XX2HTML_ALLOW_UNSUPPORTED_OPENPYXL=1to bypass the guard.
- Set
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 examplev1.2.3). - Push the tag to GitHub; the
publishworkflow 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)
| File | Size | Uploaded | |
|---|---|---|---|
| xx2html-0.18.0rc1.tar.gz | 139.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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