# XML Format Reference
TYTX XML encoding for legacy systems and XML-based integrations.
> **Note**: Most web applications should use JSON (the default). Use XML only when integrating with systems that require it.
## Basic Structure
XML format requires a strict structure: `{tag: {value: ..., attrs?: {...}}}`
- `value` is **required** - the element content
- `attrs` is **optional** - element attributes (defaults to `{}`)
```python
from decimal import Decimal
from datetime import date
from genro_tytx import to_xml, from_xml
# Simple element
data = {"price": {"value": Decimal("100.50")}}
xml = to_xml(data)
# Output: 100.50::N
# With attributes
data = {
"order": {
"attrs": {"id": 123, "created": date(2025, 1, 15)},
"value": {"total": {"value": Decimal("100.50")}}
}
}
xml = to_xml(data)
# Output: 100.50::N
```
## Nested Structures
```python
data = {
"invoice": {
"value": {
"header": {
"value": {
"date": {"value": date(2025, 1, 15)},
"number": {"value": 12345}
}
},
"total": {"value": Decimal("999.99")}
}
}
}
xml = to_xml(data)
#
#
# 2025-01-15::D
# 12345::L
#
# 999.99::N
#
```
## Lists and Repeated Elements
### Named repeated elements
```python
data = {
"order": {
"value": {
"item": [
{"attrs": {"name": "Widget"}, "value": Decimal("10.50")},
{"attrs": {"name": "Gadget"}, "value": Decimal("25.00")}
]
}
}
}
xml = to_xml(data)
#
# - 10.50::N
# - 25.00::N
#
```
### Direct list (creates `_item` tags)
```python
data = {
"prices": {
"value": [
{"value": Decimal("1.1")},
{"value": Decimal("2.2")}
]
}
}
xml = to_xml(data)
# <_item>1.1::N<_item>2.2::N
```
## The `root` Parameter
Wrap arbitrary data in a root element:
```python
# root=True wraps in
data = {"price": {"value": Decimal("100")}}
xml = to_xml(data, root=True)
# 100::N
# root="custom" uses custom tag name
xml = to_xml(data, root="data")
# 100::N
# root={...} adds attributes to tytx_root
xml = to_xml(data, root={"version": 1})
# 100::N
```
### Wrapping lists
```python
data = [{"value": Decimal("1.1")}, {"value": Decimal("2.2")}]
xml = to_xml(data, root=True)
# <_item>1.1::N<_item>2.2::N
```
## Auto-unwrap on Decode
When decoding, `tytx_root` is automatically unwrapped:
```python
xml = "100.50::N"
decoded = from_xml(xml)
# Returns: {"price": {"attrs": {}, "value": Decimal("100.50")}}
# NOT: {"tytx_root": {"attrs": {}, "value": {...}}}
# Regular root elements are NOT unwrapped
xml = "100.50::N"
decoded = from_xml(xml)
# Returns: {"order": {"attrs": {}, "value": {"price": {...}}}}
```
## Decoded Structure
Decoded XML always returns the full `{tag: {attrs: {...}, value: ...}}` structure:
```python
from_xml("100.50::N")
# Returns: {"price": {"attrs": {}, "value": Decimal("100.50")}}
from_xml(' ')
# Returns: {"item": {"attrs": {"name": "Widget", "price": 10}, "value": None}}
```
## JavaScript/TypeScript
```javascript
import { toXml, fromXml } from 'genro-tytx';
import Decimal from 'decimal.js';
const data = {
order: {
attrs: { id: 123 },
value: { total: { value: new Decimal('100.50') } }
}
};
const xml = toXml(data);
const decoded = fromXml(xml);
```
### With root wrapper
```javascript
const data = { price: { value: new Decimal('100.50') } };
// Wrap in tytx_root
const xml = toXml(data, { root: true });
// Custom root tag
const xml2 = toXml(data, { root: 'data' });
// Root with attributes
const xml3 = toXml(data, { root: { version: 1 } });
```
## Options
### `declaration` (default: `true`)
Include XML declaration:
```python
to_xml(data, declaration=True) # ...
to_xml(data, declaration=False) # ...
```
## Wire Format
Type suffixes in XML:
```xml
100.50::N
2025-01-15::D
1::B
Widget
```
| Type | Suffix | Example |
|------|--------|---------|
| Decimal | `::N` | `100.50::N` |
| Date | `::D` | `2025-01-15::D` |
| DateTime | `::DHZ` | `2025-01-15T10:30:00.000Z::DHZ` |
| Time | `::H` | `10:30:00.000::H` |
| Boolean | `::B` | `1::B` or `0::B` |
| Integer | `::L` | `123::L` |
| Float | `::R` | `3.14::R` |
Untyped values (plain strings) have no suffix.
## Error Handling
```python
# Invalid: missing 'value' key
to_xml({"price": Decimal("100")})
# Raises: ValueError: Element 'price' must be a dict with 'value' key
# Invalid: multiple root elements
to_xml({"a": {"value": 1}, "b": {"value": 2}})
# Raises: ValueError: Input must be object with single root element
```
## XML Entities
Special characters are escaped automatically:
```python
data = {"message": {"value": 'Hello & "friends"'}}
xml = to_xml(data)
# Hello <world> & "friends"
# Decoded back correctly
decoded = from_xml(xml)
# {"message": {"attrs": {}, "value": 'Hello & "friends"'}}
```