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