# myxmltools

![Python](https://img.shields.io/badge/python-3.10%2B-blue?style=plastic&logo=python)
![PyPI](https://img.shields.io/pypi/v/myxmltools)
![Build](https://img.shields.io/badge/tests-pytest-green)
![Style](https://img.shields.io/badge/lint-ruff-46a2f1)

Small utility library to read and update XML nodes using `xml.dom.minidom`.

## Installation

### Requirements

- Python 3.10+

### Option 1: Install from local source with pip

```bash
pip install .
```

### Option 2: Use Poetry (development setup)

```bash
poetry install
```

## Usage

```python
import xml.dom.minidom as md

from myxmltools import (
	getValue,
	getValues,
	getAttribute,
	tagExists,
	updateXML,
	updateOrCreateXML,
	setAttribute,
	removeTag,
	pretty_print,
)

doc = md.parseString(
	"""
	<root>
		<name id="42">John Doe</name>
		<age>30</age>
		<name id="99">Jane Doe</name>
	</root>
	"""
)

root = doc.documentElement

# Read values
first_name = getValue(root, "name")
all_names = getValues(root, "name")
name_id = getAttribute(root, "name", "id", idx=1)

# Update and create
updateXML(root, "age", 31)
updateOrCreateXML(root, "name", "Mark", idx=2)

# Attributes and removal
setAttribute(root, "age", "unit", "years")
removeTag(root, "name", idx=0)

# Check existence and pretty print
exists = tagExists(root, "age")
print(pretty_print(doc))
```

## Functions

### Reading

- `getValue(xml, label)`
Returns the text content of the first matching tag.

- `getFromXml(xml, label, idx=0)`
Returns the text content of the matching tag at index `idx`.

- `getValues(xml, label)`
Returns a list with text content for all matching tags.

- `getElement(xml, label, el=0)`
Returns the matching DOM element at index `el`.

- `getAttribute(xml, label, attribute, idx=0)`
Returns the value of `attribute` from the selected tag.

- `tagExists(xml, label)`
Returns `True` if at least one matching tag exists, otherwise `False`.

### Writing

- `updateXML(xml, label, value, idx=0)`
Updates text content for an existing tag at index `idx`.

- `updateOrCreateXML(xml, label, value, idx=0)`
Updates the tag at index `idx` if it exists. If `idx` is exactly the next valid index, it appends a new tag.

- `setAttribute(xml, label, attribute, value, idx=0)`
Sets an attribute on the selected tag.

- `removeTag(xml, label, idx=0)`
Removes the selected tag from its parent node.

### Formatting

- `pretty_print(dom)`
Returns an indented XML string with empty lines removed.

## Notes

- Functions raise descriptive exceptions for invalid labels, indices, attributes, or node types.
- Most APIs accept both `xml.dom.minidom.Document` and `xml.dom.minidom.Element`.

## Contributing

1. Fork the repository and create a feature branch.
2. Install development dependencies:

```bash
poetry install --with test,devel
```

3. Run tests:

```bash
poetry run pytest
```

4. Run lint checks:

```bash
poetry run ruff check .
```

5. Open a pull request with a clear description of your change.

## Changelog

### 0.2.0

- Added robust validation and error handling for tag/attribute access.
- Added indexed read and update operations for repeated tags.
- Added `updateOrCreateXML` support for append-at-tail behavior.
