xdoc-rs 0.1.1

Declarative XML engine for Rust
Documentation
# Feature: Builder

Builder es la API Rust explicita para crear XML. Es el mejor punto de entrada
si quieres evitar strings XML, pero todavia prefieres funciones y metodos Rust
en vez de la macro `xml!`.

## Que aprenderas aqui

- Crear documentos con un root.
- Agregar atributos, namespaces y children.
- Crear fragments reutilizables.
- Trabajar con `Option`, `Vec` y `XmlResult` como children.
- Decidir cuando usar builder o `xml!`.

## Archivo

- `src/builder/mod.rs`

## Primer documento

```rust
use xdoc::builder::{element, DocumentBuilder};
use xdoc::core::XmlResult;
use xdoc::writer::to_string_compact;

fn build() -> XmlResult<String> {
    let root = element("Document")?
        .attr("kind", "example")?
        .child(element("ID")?.text("DOC-001")?)?
        .child(element("Title")?.text("Builder API")?)?;

    let document = DocumentBuilder::new().root(root)?.build()?;
    to_string_compact(&document)
}
```

Salida:

```xml
<Document kind="example"><ID>DOC-001</ID><Title>Builder API</Title></Document>
```

## Elementos

`element("Name")` crea un `ElementBuilder`.

```rust
let item = element("Item")?
    .attr("code", "A001")?
    .attr("quantity", 3)?
    .text("Keyboard")?;
```

Reglas:

- Los nombres se validan al construir.
- Los valores de atributos usan `ToString`.
- `text(...)`, `comment(...)`, `cdata(...)` y `processing_instruction(...)`
   agregan children.
- La salida final se materializa con `DocumentBuilder`.

## Atributos opcionales

Usa `attr_if` cuando un atributo depende de un `Option`.

```rust
let discount = Some("10");

let item = element("Item")?
    .attr("code", "A001")?
    .attr_if("discount", discount)?;
```

Si `discount` es `None`, el atributo no se emite.

## Namespaces

Para declarar namespaces:

```rust
let root = element("Document")?
    .default_namespace("urn:example:default")?
    .namespace("doc", "urn:example:document")?;
```

Para crear nombres prefijados:

```rust
use xdoc::builder::ElementBuilder;

let title = ElementBuilder::qualified(
    "doc",
    "Title",
    "urn:example:document",
)?
.text("Namespaced title")?;
```

Importante: crear un elemento prefijado no agrega automaticamente la declaracion
`xmlns:doc` al XML. Declara el namespace en el elemento donde corresponde.

## Fragments

Un fragment es una lista de nodos que puedes pasar como children.

```rust
use xdoc::builder::{element, fragment};

let header = fragment()
    .child(element("ID")?.text("DOC-001")?)?
    .child(element("IssueDate")?.text("2026-06-12")?)?;

let root = element("Document")?.child(header)?;
```

Los fragments sirven para:

- Pasar children a componentes.
- Reutilizar bloques.
- Construir listas antes de insertarlas.
- Retornar varios nodos desde una funcion.

## Listas

`children(...)` acepta iteradores de valores convertibles a XML.

```rust
struct Line {
    code: &'static str,
    name: &'static str,
}

let lines = vec![
    Line { code: "A", name: "Alpha" },
    Line { code: "B", name: "Beta" },
];

let root = element("Lines")?.children(
    lines
        .iter()
        .map(|line| element("Line")?.attr("code", line.code)?.text(line.name))
        .collect::<Vec<_>>(),
)?;
```

El orden del vector se conserva.

## Condicionales

`Option<T>` implementa `IntoXmlFragment`.

```rust
let maybe_note = Some(element("Note")?.text("Optional")?);

let root = element("Document")?
    .child(element("ID")?.text("DOC-001")?)?
    .child(maybe_note)?;
```

Si el valor es `None`, no se inserta nada.

## Errores y propagacion

Builder retorna `XmlResult<T>`. Esto permite usar `?` y propagar errores de
nombres invalidos, namespaces invalidos u operaciones no permitidas.

```rust
fn item(code: &str) -> XmlResult<xdoc::builder::ElementBuilder> {
    element("Item")?.attr("code", code)
}
```

Si tienes un `Vec<XmlResult<ElementBuilder>>`, tambien puedes pasarlo como
children porque `XmlResult<T>` se normaliza a fragment o propaga el error.

## Cuando usar builder

Usa builder si:

- El XML se arma con mucha logica Rust.
- Quieres evitar macros.
- Necesitas crear fragments paso a paso.
- Quieres una API simple para pruebas.

Prefiere `xml!` si:

- La forma del XML se entiende mejor como tags.
- Vas a usar componentes con children.
- Quieres que los namespaces prefijados se validen en la sintaxis declarativa.

## Errores comunes

- Olvidar `DocumentBuilder::new().root(root)?.build()?`.
- Intentar construir un documento desde un fragment con varios roots.
- Crear elementos prefijados sin declarar `xmlns:prefix`.
- Pasar strings XML como texto esperando que se inserten como XML; se escapan
   como texto normal.

## API principal

- `element`
- `text`
- `fragment`
- `DocumentBuilder`
- `ElementBuilder`
- `FragmentBuilder`
- `XmlNode`
- `IntoXmlFragment`

## Siguiente lectura

- [component.md]component.md para componer builder con funciones Rust.
- [macros.md]macros.md para sintaxis tipo XML.
- [writer.md]writer.md para serializar el documento.

[Volver al indice](features.md).