xdoc-rs 0.1.1

Declarative XML engine for Rust
Documentation
# Documentacion de la libreria xdoc

Esta documentacion esta pensada para usuarios de la libreria `xdoc`: personas
que quieren construir, leer, consultar, transformar, validar o firmar XML desde
Rust sin escribir strings XML a mano.

El package publicado se llama `xdoc-rs`, pero la crate importable se llama
`xdoc`.

```toml
xdoc = { package = "xdoc-rs", version = "0.1" }
```

```rust
use xdoc::macros::xml;
```

## Que problema resuelve

`xdoc` es un motor XML generico con una experiencia declarativa parecida a
Leptos, pero sin runtime reactivo. La idea es que puedas dividir documentos XML
grandes en componentes Rust pequenos, usar props tipadas, pasar children,
iterar colecciones y producir una salida XML deterministica.

El motor es generico. No contiene reglas de dominios como DIAN, UBL, SOAP, HL7,
CDA, SAML o facturacion electronica. Una aplicacion de dominio puede depender de
`xdoc`; `xdoc` no debe depender del dominio.

## Camino de aprendizaje recomendado

1. Lee esta pagina para entender el flujo general.
2. Lee [builder.md]builder.md si quieres construir XML con API Rust explicita.
3. Lee [component.md]component.md para dividir XML grande en piezas pequenas.
4. Lee [macros.md]macros.md para usar sintaxis tipo tags con `xml!`.
5. Lee [writer.md]writer.md, [parser.md]parser.md y [query.md]query.md
   para serializar, leer y consultar XML existente.
6. Lee [schema.md]schema.md y [transform.md]transform.md cuando necesites
   validar o convertir XML.
7. Lee [signature.md]signature.md si vas a canonicalizar o firmar XML.

Indice completo: [features.md](features.md).

## Primer documento

La forma mas directa de crear XML es `xml!`.

```rust
use xdoc::core::XmlResult;
use xdoc::macros::xml;
use xdoc::writer::{to_string_pretty, WriterConfig};

fn main() -> XmlResult<()> {
    let document = xml! {
        <Document kind="example">
            <ID>DOC-001</ID>
            <Title>First document</Title>
        </Document>
    }?
    .into_document()?;

    let output = to_string_pretty(
        &document,
        WriterConfig::pretty().with_xml_declaration(false),
    )?;

    println!("{output}");
    Ok(())
}
```

Salida:

```xml
<Document kind="example">
  <ID>DOC-001</ID>
  <Title>First document</Title>
</Document>
```

## Componentes para XML grande

Cuando un XML crece, conviene partirlo en componentes. Un componente es solo una
funcion Rust. Las props son structs Rust y los children son fragments.

```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()
}

fn build() -> XmlResult<xdoc::core::Document> {
    xml! {
        <Document>
            <{Section} name="header">
                <Title>Declarative XML</Title>
            </{Section}>
            <{Section} name="body">
                <Paragraph>Created from Rust components</Paragraph>
            </{Section}>
        </Document>
    }?
    .into_document()
}
```

## Listas y datos dinamicos

`xml!` acepta expresiones Rust. Si interpolas un `Vec` de fragments o templates,
se insertan en orden.

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

struct Item {
    code: &'static str,
    name: &'static str,
}

fn build(items: &[Item]) -> XmlResult<xdoc::core::Document> {
    let item_nodes = items
        .iter()
        .map(|item| {
            xml! {
                <Item code={ item.code }>
                    <Name>{ item.name }</Name>
                </Item>
            }
        })
        .collect::<XmlResult<Vec<_>>>()?;

    xml! {
        <Catalog>
            { item_nodes }
        </Catalog>
    }?
    .into_document()
}
```

## Namespaces

La macro valida que los prefijos usados esten declarados en el scope del XML.
Esto evita construir accidentalmente nombres como `doc:Item` sin `xmlns:doc`.

```rust
let document = xml! {
    <doc:Document
        xmlns="urn:example:default"
        xmlns:doc="urn:example:document"
        xmlns:meta="urn:example:metadata"
        meta:version="1"
    >
        <doc:Title>Namespaced XML</doc:Title>
    </doc:Document>
}?
.into_document()?;
```

## Leer, consultar y volver a escribir

El parser produce el mismo `Document` que crea el builder. Query trabaja sobre
ese arbol y writer lo serializa.

```rust
use xdoc::parser::parse_str;
use xdoc::query::DocumentQueryExt;
use xdoc::writer::to_string_compact;

let document = parse_str("<Root><Item code=\"A\">one</Item></Root>")?;
let result = document.query("/Root/Item[@code='A']/text()")?;

assert_eq!(result.strings(), vec!["one"]);
assert_eq!(
    to_string_compact(&document)?,
    "<Root><Item code=\"A\">one</Item></Root>"
);
```

## Como elegir la herramienta correcta

| Necesidad | Usa |
| --- | --- |
| Construir XML con control Rust explicito | [builder.md]builder.md |
| Dividir XML grande en piezas reutilizables | [component.md]component.md |
| Escribir XML con sintaxis de tags | [macros.md]macros.md |
| Convertir `Document` a string XML | [writer.md]writer.md |
| Leer XML externo de forma segura | [parser.md]parser.md |
| Buscar nodos, textos o atributos | [query.md]query.md |
| Convertir un XML en otro | [transform.md]transform.md |
| Validar estructura ligera | [schema.md]schema.md |
| Ajustar limites de seguridad | [security.md]security.md |
| Canonicalizar o firmar XML | [signature.md]signature.md |
| Crear fixtures y golden tests | [testing.md]testing.md |
| Inspeccionar XML desde terminal | [cli.md]cli.md |

## Modelo mental

`xdoc` trabaja con un arbol XML propio:

```text
xml! / builder / parser
        |
        v
     Document
        |
        +--> writer
        +--> query
        +--> transform
        +--> schema
        +--> signature
```

Esto significa:

[] Construyes o parseas una vez.
[] Consultas, validas o transformas el mismo `Document`.
[] Serializas al final.
[] Para firma, canonicalizas y firmas sobre la estructura final.

## Errores comunes

[] Usar un prefijo XML sin declararlo con `xmlns:prefix`.
[] Intentar crear un documento con mas de un root.
[] Esperar que `query` modifique el XML; `query` solo consulta.
[] Usar `schema` como si fuera XSD completo.
[] Usar `transform` como si fuera XSLT completo.
[] Modificar nodos firmados despues de calcular digest o `SignatureValue`.

## Estado actual

La libreria tiene MVP funcional para core, builder, component, writer, parser,
macro, query, transform, schema, security, testing, CLI y una base generica de
signature. Algunas piezas son intencionalmente parciales:

[] `query` no es XQuery ni XPath completo.
[] `transform` no es XSLT.
[] `schema` no es XSD completo.
[] `signature` no es un motor legal completo de XAdES productivo.
[] `xml!` no es parser XML runtime; es azucar de compilacion sobre builder y
   componentes.