xdoc-rs 0.1.1

Declarative XML engine for Rust
Documentation
# Feature: Componentes

Los componentes permiten dividir XML grande en funciones pequenas. La idea es
similar a Leptos o JSX, pero el resultado es XML estatico y deterministico, no
un DOM reactivo.

## Que aprenderas aqui

- [ ] Definir props tipadas.
- [ ] Recibir children.
- [ ] Retornar un elemento o un fragment.
- [ ] Componer componentes desde `xml!`.
- [ ] Iterar listas con componentes.

## Archivo

- [ ] `src/component/mod.rs`

## Modelo mental

Un componente es una funcion Rust:

```rust
fn Component(props: Props, children: Children) -> XmlResult<ElementBuilder>
```

No hay runtime especial. No hay lifecycle. No hay reactividad. Solo Rust normal
que retorna builders/fragments.

## Primer componente

```rust
use xdoc::builder::ElementBuilder;
use xdoc::core::XmlResult;
use xdoc::macros::xml;

#[derive(Clone)]
struct HeaderProps {
    id: String,
}

#[allow(non_snake_case)]
fn Header(props: HeaderProps) -> XmlResult<ElementBuilder> {
    xml! {
        <Header>
            <ID>{ props.id }</ID>
        </Header>
    }?
    .into_fragment()
    .into_single_element()
}
```

Uso:

```rust
let document = xml! {
    <Document>
        <{Header} id={ "DOC-001".to_owned() }/>
    </Document>
}?
.into_document()?;
```

La macro crea `HeaderProps { id: ... }` usando los atributos pasados al
componente.

## Componentes con children

```rust
use xdoc::builder::ElementBuilder;
use xdoc::component::Children;
use xdoc::core::XmlResult;
use xdoc::macros::xml;

#[derive(Clone)]
struct SectionProps {
    name: &'static str,
}

#[allow(non_snake_case)]
fn Section(props: SectionProps, children: Children) -> XmlResult<ElementBuilder> {
    xml! {
        <Section name={ props.name }>
            { children }
        </Section>
    }?
    .into_fragment()
    .into_single_element()
}
```

Uso:

```rust
let document = xml! {
    <Document>
        <{Section} name="summary">
            <Title>Summary</Title>
            <Text>Reusable children</Text>
        </{Section}>
    </Document>
}?
.into_document()?;
```

## Componentes que retornan fragments

Un componente tambien puede retornar varios nodos si devuelve `Fragment`.

```rust
use xdoc::builder::{element, fragment};
use xdoc::component::Fragment;
use xdoc::core::XmlResult;

#[derive(Clone)]
struct PairProps {
    first: &'static str,
    second: &'static str,
}

#[allow(non_snake_case)]
fn Pair(props: PairProps) -> XmlResult<Fragment> {
    fragment()
        .child(element("First")?.text(props.first)?)?
        .child(element("Second")?.text(props.second)?)
}
```

Uso:

```rust
let document = xml! {
    <Root>
        <{Pair} first="one" second="two"/>
    </Root>
}?
.into_document()?;
```

Salida:

```xml
<Root><First>one</First><Second>two</Second></Root>
```

## Listas con componentes

Puedes mapear datos Rust a componentes y luego insertar el vector.

```rust
#[derive(Clone)]
struct ItemProps {
    code: &'static str,
    name: &'static str,
}

#[allow(non_snake_case)]
fn Item(props: ItemProps) -> XmlResult<ElementBuilder> {
    xml! {
        <Item code={ props.code }>
            <Name>{ props.name }</Name>
        </Item>
    }?
    .into_fragment()
    .into_single_element()
}

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

let item_nodes = items
    .iter()
    .map(|item| xml! { <{Item} code={ item.code } name={ item.name }/> })
    .collect::<XmlResult<Vec<_>>>()?;

let document = xml! {
    <Catalog>{ item_nodes }</Catalog>
}?
.into_document()?;
```

## Props tipadas

Las props son structs. Esto te da:

- [ ] Errores de compilacion si falta un campo.
- [ ] Tipos Rust reales para numeros, fechas propias, enums, etc.
- [ ] Refactors mas seguros.
- [ ] Separacion clara entre datos y forma XML.

En el MVP, los props que pasan por `xml!` deben ser identificadores simples.
Para valores mas complejos, calcula el valor antes:

```rust
let total_text = format!("{:.2}", total);
let node = xml! { <Amount>{ total_text }</Amount> }?;
```

## Cuando usar componentes

Usa componentes si:

- [ ] Tu XML es grande.
- [ ] Varias secciones se repiten.
- [ ] Quieres encapsular reglas de construccion.
- [ ] Quieres probar piezas pequenas.
- [ ] Quieres mantener props tipadas.

No necesitas componentes si:

- [ ] Tu XML es pequeno y plano.
- [ ] Un solo `xml!` o builder ya se entiende bien.

## Errores comunes

- [ ] Olvidar `#[allow(non_snake_case)]` si quieres nombres estilo componente.
- [ ] Intentar usar props complejos directamente dentro del tag; calcula antes.
- [ ] Retornar un fragment con varios nodos y luego convertirlo a documento.
- [ ] Pensar que `Children` es una closure; aqui es un fragment ya construido.

## API principal

- [ ] `Children`
- [ ] `Fragment`
- [ ] `FragmentNode`
- [ ] `IntoXml`
- [ ] `IntoXmlFragment`
- [ ] `document`
- [ ] `children`

## Siguiente lectura

- [ ] [macros.md](macros.md) para escribir componentes con tags.
- [ ] [builder.md](builder.md) para crear componentes sin macro.
- [ ] [writer.md](writer.md) para serializar.

[Volver al indice](features.md).