# Feature: Core XML
El core es el modelo comun que usan todas las demas features. Normalmente no lo
usarĂ¡s directamente para crear XML del dia a dia, pero conviene entenderlo
porque parser, builder, macro, query, transform, schema y signature terminan
trabajando sobre los mismos tipos.
## Que aprenderas aqui
[] Que es un `Document`.
[] Como se representan nombres XML y namespaces.
[] Como se reportan errores.
[] Cuando conviene bajar al core en vez de usar builder o macro.
## Archivos
[] `src/core/error.rs`
[] `src/core/names.rs`
[] `src/core/namespace.rs`
[] `src/core/tree.rs`
[] `src/core/mod.rs`
## Modelo mental
Un XML en `xdoc` es un `Document` con nodos internos identificados por `NodeId`.
Cada nodo tiene un `NodeKind`:
[] `Element`
[] `Text`
[] `Comment`
[] `CData`
[] `ProcessingInstruction`
Los elementos tienen:
[] Un `QName`.
[] Atributos.
[] Declaraciones de namespace.
[] Children como `NodeId`.
```text
Document
root: NodeId
nodes:
0: Element(Root)
1: Element(Child)
2: Text("value")
```
## Primer ejemplo con core
```rust
use xdoc::core::{Document, QName, XmlResult};
use xdoc::writer::to_string_compact;
fn build() -> XmlResult<String> {
let mut document = Document::new();
let root = document.add_root_element(QName::new("Root")?)?;
let child = document.add_element(root, QName::new("Child")?)?;
document.add_text(child, "value")?;
to_string_compact(&document)
}
```
Salida:
```xml
<Root><Child>value</Child></Root>
```
Para XML normal, este ejemplo se escribiria mas comodo con builder o `xml!`.
El core es util cuando necesitas manipular el arbol con control fino.
## Nombres XML
`QName` evita tratar nombres XML como strings sueltos.
```rust
use xdoc::core::QName;
let local = QName::new("ID")?;
let qualified = QName::qualified("doc", "ID", "urn:example:doc")?;
let namespaced = QName::namespaced("ID", "urn:example:default")?;
```
Reglas importantes:
[] `QName::new("ID")` crea un nombre local sin prefijo.
[] `QName::qualified("doc", "ID", "...")` crea `doc:ID`.
[] El prefijo `xml` solo puede apuntar al namespace reservado de XML.
[] El prefijo `xmlns` no se usa como prefijo normal de elementos.
[] La validacion de nombres es conservadora y ASCII en el MVP.
## Namespaces
`NamespaceDeclaration` representa una declaracion `xmlns`.
```rust
use xdoc::core::{NamespaceDeclaration, NamespaceTable};
let default_ns = NamespaceDeclaration::default("urn:default")?;
let prefixed = NamespaceDeclaration::prefixed("doc", "urn:doc")?;
let mut table = NamespaceTable::new();
table.declare(default_ns);
table.declare(prefixed);
```
El writer serializa las declaraciones agregadas al elemento. En builder y
`xml!` normalmente usas helpers mas ergonomicos:
```rust
let root = xdoc::builder::element("Root")?
.default_namespace("urn:default")?
.namespace("doc", "urn:doc")?;
```
## Errores
La mayoria de APIs retornan `XmlResult<T>`, que es un alias de
`Result<T, XmlError>`.
```rust
use xdoc::core::{ErrorKind, QName};
let error = QName::new("1Invalid").expect_err("invalid name must fail");
assert_eq!(error.kind(), &ErrorKind::InvalidName);
```
Categorias comunes:
[] `InvalidName`: nombre XML invalido.
[] `InvalidNamespace`: binding de namespace invalido.
[] `InvalidOperation`: operacion que rompe reglas del arbol.
[] `Parse`: XML externo invalido.
[] `Query`: expresion query invalida.
[] `Validation`: contrato no valido o mal definido.
[] `Signature`: error de canonicalizacion, digest, firma o verificacion.
## Cuando usar core directamente
Usa core si:
[] Necesitas construir o inspeccionar nodos a bajo nivel.
[] Estas implementando una nueva feature del motor.
[] Necesitas `NodeId` para una operacion especifica, por ejemplo placement de
firma.
[] Estas escribiendo pruebas sobre estructura interna.
Prefiere builder o `xml!` si:
[] Solo quieres crear XML.
[] Quieres componer componentes.
[] Quieres una API mas declarativa.
## Errores comunes
[] Crear un segundo root en el mismo `Document`.
[] Intentar agregar children a un nodo que no es elemento.
[] Usar nombres con `:` dentro de `QName::new`; usa `QName::qualified`.
[] Crear un `QName` prefijado sin declarar el namespace al serializar.
## API principal
[] `Document`
[] `NodeId`
[] `Node`
[] `NodeKind`
[] `ElementData`
[] `Attribute`
[] `XmlPath`
[] `QName`
[] `NamespaceUri`
[] `NamespacePrefix`
[] `NamespaceDeclaration`
[] `NamespaceTable`
[] `XmlError`
[] `ErrorKind`
[] `XmlResult<T>`
## Siguiente lectura
[] [builder.md](builder.md) para construir XML sin manipular `NodeId`.
[] [writer.md](writer.md) para serializar el `Document`.
[] [parser.md](parser.md) para crear `Document` desde XML externo.
[Volver al indice](features.md).