xldown
Convert Excel (.xlsx) files to Markdown.
Install
uv pip install -e /path/to/xldown
CLI
xldown input.xlsx # creates input_output/ folder
xldown input.xlsx -o my_report # creates my_report/ folder
xldown --help
Output folder structure:
my_report/
├── output.md # converted markdown with tables and chart links
├── charts/ # rendered chart images (1.png, 2.png, ...)
└── images/ # extracted embedded images (1.png, 2.png, ...)
Python API
from xldown import excel_to_markdown
excel_to_markdown("data.xlsx", "my_report/")
Creates my_report/ with output.md, charts/, and images/ subdirectories.
Dependencies
- pandas
- openpyxl
- matplotlib
- click
- tabulate
- pydantic
Excel Edge Cases Handled
The converter is designed to gracefully handle common Excel edge cases without failing or losing data:
Worksheet and Cell-Level
- Empty worksheets: Worksheets with no cell content are skipped entirely (no output generated)
- Prose cells: Single isolated cells are rendered as plain text paragraphs
- Row length variance: Rows may have different numbers of cells; they are padded to the region's width before table construction
- Merged cells: Merged cell ranges are filled with the top-left cell's value and formatting applied to all cells in the range
- Hidden columns: Columns marked as hidden in the worksheet are detected and labeled with "(hidden)" in the table header
- Cell formatting: Rich text with character-level subscript/superscript (e.g., H₂O) is detected and rendered as
<sub>/<sup>HTML tags; cell-level formatting (bold, italic, strikethrough, superscript, subscript, rotation) is applied as Markdown or HTML annotations - Cell colors and borders: Font colors, background colors, and border styles are extracted and documented in an Annotations section below each table (filtering out default black/white)
- Cell metadata: Comments and hyperlinks are extracted and documented with cell coordinates below each table
Data Organization
- Non-contiguous regions: Adjacent cells are grouped into connected components (4-connected flood-fill), and isolated cells are treated as prose while multi-cell regions become tables
- Annotation grouping: Cells with identical formatting annotations are grouped into connected components; solid rectangles are expressed as ranges (e.g.,
A1:C3), while irregular patterns list individual cells
Chart Edge Cases
- Missing or invalid data: Empty charts, missing sheets, and malformed range references are silently skipped
- Data length mismatches: Series with varying lengths are padded with zeros; missing category labels are replaced with numeric indices
- Missing attributes: Unset or None chart attributes default to sensible values (e.g., "clustered" for bar grouping)
Chart Type-Specific Handling
- Single-series charts (Pie, Doughnut, Radar): Only the first series is plotted
- Stacked charts: Series are stacked correctly, with percent-stacked variants normalized to 100%
- Minimum requirements (Stock, Surface): Charts requiring specific data combinations may be skipped if incomplete
- Coordinate systems: Charts using special projections (3D, polar) are rendered with appropriate matplotlib settings
Metadata
Release files for xldown 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| xldown-0.1.1.tar.gz | 24.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| xldown-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.7 kB
Release files / xldown-0.1.1.tar.gz
| Download URL | xldown-0.1.1.tar.gz |
|---|---|
| Size | 24.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
515023a24e5a4cf534325928bf463520627d0072daf4d43b3531e8c14d8a8b2e
|
|
BLAKE2b-256 checksum How to use checksums |
f2db5bbd2292c03ae6b3eaf15070e019dd98de0fdeded130b00db5291c4bca74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 26, 2026.
Transparency logRelease files / xldown-0.1.1-py3-none-any.whl
| Download URL | xldown-0.1.1-py3-none-any.whl |
|---|---|
| Size | 16.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a19ad877dff2ff8475016a0d13fca4d05e70b4c396010e723c2b7fb2f9b53985
|
|
BLAKE2b-256 checksum How to use checksums |
3f65a7d7a8231e048c6436087627c046c52275bfcf13d62c50d5208564325295
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 26, 2026.
Transparency log