···11+# xmlt
22+33+Declarative XML codecs using GADT-based bidirectional maps and bytesrw streaming.
44+55+## Overview
66+77+Xmlt provides type-safe XML encoding and decoding using a combinator-based
88+approach inspired by the {e finally tagged} pattern from
99+[An alphabet for your data soups](https://github.com/dbuenzli/jsont/blob/main/paper/soup.tex)
1010+by Daniel Buenzli. Define a codec once and use it for both encoding and decoding.
1111+1212+Codecs compose from attributes, child elements, and text content using the
1313+`El` builder module, the same way Jsont composes JSON objects from members.
1414+Streaming I/O is built on [bytesrw](https://github.com/dbuenzli/bytesrw).
1515+1616+## Installation
1717+1818+```
1919+opam install xmlt
2020+```
2121+2222+## Usage
2323+2424+```ocaml
2525+open Xmlt
2626+2727+(* Define a codec for a record type *)
2828+type person = { name : string; age : int; email : string option }
2929+3030+let person =
3131+ El.(element "person"
3232+ (obj (fun name age email -> { name; age; email })
3333+ |> attr "name" Attr.string ~enc:(fun p -> p.name)
3434+ |> attr "age" Attr.int ~enc:(fun p -> p.age)
3535+ |> child_opt "email" string ~enc:(fun p -> p.email)
3636+ |> finish))
3737+3838+(* Decode from XML *)
3939+let () =
4040+ match decode_string person "<person name=\"Alice\" age=\"30\"/>" with
4141+ | Ok p -> Printf.printf "Name: %s, Age: %d\n" p.name p.age
4242+ | Error e -> prerr_endline e
4343+4444+(* Encode to XML *)
4545+let xml = encode_string ~indent:2 person { name = "Bob"; age = 25; email = None }
4646+```
4747+4848+## API Overview
4949+5050+- **`'a t`** -- XML codec type (bidirectional)
5151+- **`string`**, **`int`**, **`float`**, **`bool`** -- Text content codecs
5252+- **`element`** -- Wrap a codec in a named XML element
5353+- **`Attr`** module -- Attribute-level codecs (`Attr.string`, `Attr.int`, `Attr.float`, `Attr.option`)
5454+- **`El`** module -- Element builder: `obj`, `attr`, `child`, `child_opt`, `children`, `text`, `finish`
5555+- **`map`**, **`const`**, **`option`**, **`list`** -- Codec combinators
5656+- **`decode_string`**, **`encode_string`** -- String I/O
5757+- **`decode`**, **`encode`** -- Streaming I/O via bytesrw readers/writers
5858+- **`Tree`** module -- Low-level XML tree access (escape hatch)
5959+- **`child`**, **`attr`**, **`nth`** -- Query combinators for navigating into structures
6060+6161+## References
6262+6363+- [Jsont](https://github.com/dbuenzli/jsont) -- The JSON codec library that
6464+ inspired this approach
6565+- [bytesrw](https://github.com/dbuenzli/bytesrw) -- Composable byte stream
6666+ readers and writers
6767+6868+## Licence
6969+7070+ISC License. See [LICENSE.md](LICENSE.md) for details.