# 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).