# xml-to-xlsx

![Python](https://img.shields.io/badge/python-3.10%2B-blue)
![Typed](https://img.shields.io/badge/typing-pep561-informational)

Convert XML definitions into styled Excel `.xlsx` workbooks using `openpyxl`.

`xml-to-xlsx` is a Python library for teams that want template-driven spreadsheet generation (reports, exports, scheduled jobs) without manual cell-by-cell workbook code.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [API](#api)
- [XML Reference](#xml-reference)
- [Styling Reference](#styling-reference)
- [Values and Type Coercion](#values-and-type-coercion)
- [Troubleshooting](#troubleshooting)

## Features

- Build an in-memory `openpyxl.Workbook` directly from XML.
- Write workbooks to disk in one call.
- Apply CSS-like style declarations (`font`, `fill`, `alignment`, `border`, `number-format`).
- Merge cells using `merge`, `rowspan`, and `colspan`.
- Configure sheet behavior (tab color, freeze panes, gridlines, default row/column sizing).
- Use XML strings, file paths, `Path` objects, or file-like streams as input.

## Installation

Install from PyPI:

```bash
pip install xml-to-xlsx
```

Or install from source:

```bash
pip install .
```

## Quick Start

```python
from xml_to_xlsx import write_workbook_from_xml

xml = """
<workbook>
    <sheet name="Overview">
        <row index="1">
            <cell column="A" style="font-weight:bold">Title</cell>
            <cell column="B">Value</cell>
        </row>
        <row index="2">
            <cell column="A">Revenue</cell>
            <cell column="B" type="float" style="number-format:$#,##0.00">15230.5</cell>
        </row>
    </sheet>
</workbook>
"""

write_workbook_from_xml(xml, save_to="overview.xlsx")
```

Supported `xml_source` values:

1. XML text string.
2. `Path`, `str`, or file-like object pointing to XML content.
3. A path-like string (auto-detected and loaded if the file exists).

## API

### `generate_workbook_from_xml(xml_source)`

Builds and returns an in-memory `openpyxl.Workbook`.

Typical uses:

- Unit tests.
- In-process post-processing before save.
- Integration with Django/Celery/report workers.

### `write_workbook_from_xml(xml_source, save_to=PathLike)`

Builds a workbook, saves it to disk, and returns the workbook instance.

Typical uses:

- File export endpoints.
- Scheduled artifact generation.
- One-step transformation jobs.

## XML Reference

### `<workbook>`

- Required root element.
- Contains one or more `<sheet>` elements.
- If no sheets are provided, a blank workbook is returned.

---

### `<sheet>`

| Attribute | Description |
| --- | --- |
| `name` | Worksheet title. Defaults to `Sheet{index}`. |
| `style` | Default CSS-like style inherited by descendants unless overridden. |
| `tab-color` | Sheet tab color (`#hex`, CSS name, `rgb()`). |
| `freeze` | Freeze panes coordinate (example: `B2`). |
| `gridlines` | `true/false/1/0/on/off/yes/no`. |
| `default-column-width` | Default width for newly used columns. |
| `default-row-height` | Default height for newly used rows. |

Allowed children:

- `<column>`
- `<row>`
- `<cell>`
- `<merge>`
- `<style>`

Example:

```xml
<sheet
  name="Summary"
  tab-color="green"
  freeze="B2"
  gridlines="false"
  default-column-width="18"
  default-row-height="20"
  style="font-family:'Calibri';color:#333">
  <!-- descendants inherit default style -->
</sheet>
```

---

### `<column>`

- Use `column="C"` or `column="3"`.
- Use `range="B:D"` or `range="2:5"` for multiple columns.
- `width` is currently supported.

```xml
<column column="B" width="30" />
<column column="4" width="12.5" />
<column range="C:E" width="18" />
```

---

### `<row>`

| Attribute | Description |
| --- | --- |
| `index` | Required row number. |
| `height` | Row height. |
| `style` | Default style for row cells. |
| `start-column` | Starting column index used for cells without explicit `column`. Defaults to `1`. |

When `start-column` is set, cells without explicit column references are auto-positioned from left to right.

```xml
<row index="5" height="24" start-column="2" style="text-align:center">
  <cell>West</cell>
  <cell>East</cell>
</row>
```

---

### `<cell>`

| Attribute | Description |
| --- | --- |
| `row`, `column` | Explicit coordinates. |
| `ref` | Combined coordinate (example: `B4`). Overrides `row`/`column`. |
| `style` | Inline style overrides. |
| `value` | Literal value; if missing, body text is used. |
| `type` | `string`, `int`, `float`, `bool`, `date`, `datetime`. |
| `formula` | Formula with or without `=` prefix. |
| `hyperlink` | External or internal link. |
| `comment` | Comment body text. |
| `comment-author` | Comment author (default: `XML`). |
| `merge` | Explicit merge range (example: `A1:C1`). |
| `rowspan` | Merge span across rows (supports positive/negative values). |
| `colspan` | Merge span across columns (supports positive/negative values). |

Examples:

```xml
<cell row="7" column="A" value="42" type="int" />
<cell ref="C9" formula="SUM(A1:A8)" style="number-format:#,##0.00" />
<cell row="10" column="B" hyperlink="https://example.com" comment="Click me">
  Friendly link text
</cell>
<cell row="12" column="A" rowspan="2" colspan="3" style="text-align:center">
  Spans two rows and three columns
</cell>
```

---

### `<merge>`

- Use when merge ranges are easier to describe separately from cell declarations.

```xml
<merge range="A1:D1" />
```

Note: `<merge>` only applies geometry. If you need border/fill consistency across the merged region, define styles on the participating cells.

---

### `<style>`

- Wrapper element that cascades its `style` attribute to descendants.
- Supports nesting.
- Useful for reducing repetitive inline style declarations.

```xml
<sheet name="Receivables">
  <style style="font-weight:bold;color:#003366">
    <row index="2">
      <cell column="A">Client</cell>
      <cell column="B">Amount</cell>
    </row>
  </style>
</sheet>
```

## Styling Reference

Styles use CSS-like declarations in the format `prop:value;`.

Precedence:

1. Sheet style defaults.
2. Row style defaults.
3. Cell style overrides.

### Text and font

- `font-weight`: `bold`, `600`, `700`
- `font-style`: `italic`
- `text-decoration` or `text-decoration-line`: `underline`, `line-through`, `strike`
- `font-size`: `12`, `12px`, `12pt`
- `font-family`: supports quoted names and comma lists (first family is used)
- `color` / `font-color`

### Fill, alignment, formatting

- `background-color`, `bg-color`, `fill`
- `text-align`, `align`: `left`, `right`, `center`, `justify`, `distributed`
- `vertical-align`, `valign`: `top`, `middle|center`, `bottom`, `justify`, `distributed`
- `wrap-text`, `white-space`: supports boolean-like values; `wrap` and `pre-wrap` are accepted
- `shrink-to-fit`: boolean-like values
- `text-rotation`, `rotation`: integer degrees (clamped to `-90..90`)
- `number-format`, `format`: native Excel format string

### Borders

- `border` applies to all edges.
- `border-left`, `border-right`, `border-top`, `border-bottom` apply per edge.
- Keywords: `hair`, `thin`, `medium`, `thick`, `double`, `dotted`, `dashed`, `dashdot`, `dashdotdot`, `slantdashdot`.
- Width values map automatically (`1px -> thin`, `2px -> medium`, `3px -> thick`).

### Colors

Color-aware attributes accept:

- Hex: `#abc`, `#aabbcc`
- CSS names (example: `orange`, `navy`, `silver`)
- `rgb(r,g,b)` / `rgba(r,g,b,a)` (alpha is ignored)
- `none` / `transparent` to disable fill or color

## Values and Type Coercion

- Empty body + missing `value` results in `None`.
- Without `type`, content is preserved as text.
- Boolean parsing accepts `true/false/1/0/on/off/yes/no`.
- `date` expects ISO format (`YYYY-MM-DD`).
- `datetime` expects ISO datetime (`YYYY-MM-DDTHH:MM:SS`).
- Formulas are always written with a leading `=`.

## Troubleshooting

- Missing `<row index="...">` or unresolved cell coordinates raise `ValueError`.
- If borders look faint, prefer `2px` (`medium`) or `3px` (`thick`) over `1px` (`thin`).
- For color issues, confirm `#` prefix and RGB values in the `0..255` range.
- Use explicit `gridlines="false"` for export-ready templates.

## Contributing

Issues and pull requests are welcome. If you plan a larger change, open an issue first so API changes and XML schema updates can be discussed before implementation.
