XML a JSON v Rustu

Quick-xml poskytuje čtení událostí a volitelné mapování Serde. Serde_json převádí JSON na Value nebo typované struktury; zpracování chyb zůstává součástí integrace.

Autor: Aktualizováno

1. Načtení XML

Příklad používá quick-xml 0.42 s feature serialize a serde s derive. Cargo.toml potřebuje závislosti níže. Struktura mapuje jednoduchý známý XML formát; JSON objekt příklad vytváří samostatně, aby do něj nepřenesl XML názvy atributů.

1. Načtení XML
[dependencies]
quick-xml = { version = "0.42", features = ["serialize"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

2. Vytvoření XML

Struktura nese hodnoty; pro ruční XML události použij Writer. Serde rename @id v této XML reprezentaci označuje atribut. Pro JSON v příkladu proto používáme samostatný objekt s běžným klíčem id.

2. Vytvoření XML
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename = "kniha")]
struct Kniha {
    #[serde(rename = "@id")]
    id: String,
    nazev: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut k: Kniha = quick_xml::de::from_str(r#"<kniha id="1"><nazev>XML</nazev></kniha>"#)?;
    k.nazev = "XML & JSON".into();
    println!("{}", quick_xml::se::to_string(&k)?);
    let value = serde_json::json!({"id": k.id, "nazev": k.nazev});
    let text = serde_json::to_string(&value)?;
    let parsed: serde_json::Value = serde_json::from_str(&text)?;
    println!("{parsed}");
    Ok(())
}

3. Serializace XML

Quick_xml::se::to_string serializuje Serde model; Writer zapisuje události. Ověř podporu mapování, atributů a smíšeného obsahu v dokumentaci přesné verze.

4. DOM

Quick-xml je čtečka a zapisovač, ne plný měnitelný DOM. Pro čtení stromu lze zvolit jiný parser; model a podpora namespace se mohou lišit.

5. Streamové čtení

Reader.read_event_into čte do opakovaně použitého bufferu. Zpracuj událost před dalším načtením a buffer vyčisti. Pro rozlišení namespace použij NsReader. Nastavení trim_text může změnit význam whitespace.

6. XPath

Quick-xml XPath neprovádí. Pro známý výběr použij průchod událostmi, nebo samostatný stromový procesor s požadovanou verzí XPath.

7. Validace XSD

Serde deserializace ověřuje svůj model, nikoli všechny XSD podmínky. Pro XSD používej samostatný procesor a řízené reference schémat.

8. Bezpečné nastavení

Omez vstup, hloubku a bufferované události. Zapnutí overlapped-lists může výrazně zvýšit paměťové nároky. Kódování není automaticky neomezené: ne-ASCII-kompatibilní vstupy vyžadují zvláštní dekódování podle dokumentace quick-xml.

9. Načtení JSON

Serde_json::from_str načítá text, from_reader čte z Read. Value je dynamická reprezentace; pro vlastní model použij derive Deserialize a definuj povinné a volitelné hodnoty.

10. Vytvoření JSON

Makro json! vytváří Value, alternativou je serializace vlastní struktury. Zvol jiný XML a JSON model, pokud požadují jiné názvy nebo typy.

11. Serializace JSON

To_string vrací Result; to_writer zapisuje do Write. Zachovej přesnost hodnot výběrem správného numerického typu a dohodou cílového jazyka.

12. JSON Schema

Serde_json není JSON Schema validátor. Použij například crate jsonschema a nastav požadovaný draft i resolver. Quick-xml a serde_json dokumentují mapování a omezení použitých API.

Jak založit projekt a ověřit mapování

Spusť cargo new xml-json-demo, v Cargo.toml zachovej sekci package a do dependencies vlož úvodní závislosti. Rust program z druhé sekce ulož do src/main.rs a spusť cargo run. XML výstup obsahuje kniha s atributem id a názvem XML & JSON, kde serializátor správně zapíše ampersand. JSON výstup má obyčejné klíče id a nazev.

Serde rename s @id platí pro XML reprezentaci quick-xml; použití stejné struktury bez oddělení modelů by dalo do JSON klíč @id. Proto příklad vytváří vlastní JSON objekt. U povinného pole bez default či Option je absence chyba deserializace. Option a serde(default) určují, zda pole může chybět: používej je jen pro skutečně volitelná data.

Streamové události bez vytváření DOM

Samostatný main.rs pro quick-xml 0.42; známý soubor bez namespace
use quick_xml::{Reader, events::Event};
use std::{fs::File, io::BufReader};
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::open("katalog.xml")?;
    if file.metadata()?.len() > 10 * 1024 * 1024 { return Err("Limit souboru".into()); }
    let mut reader = Reader::from_reader(BufReader::new(file));
    let mut buffer = Vec::new();
    let mut count = 0;
    loop {
        match reader.read_event_into(&mut buffer)? {
            Event::Start(e) | Event::Empty(e) if e.name().as_ref() == "kniha" => count += 1,
            Event::DocType(_) => return Err("DTD není povoleno".into()),
            Event::Eof => break,
            _ => {}
        }
        buffer.clear();
    }
    println!("{count}");
    Ok(())
}

Pro <katalog><kniha/><kniha/></katalog> program vypíše 2. Empty je samouzavřený element, Start začátek párového elementu. Clear znovu použije buffer po skončení zpracování události. Událost může buffer půjčovat, proto si reference na ni neuchovávej přes další čtení.

Tento výběr se vztahuje ke známému dokumentu bez namespace. Pro namespace použij NsReader a porovnej vyřešené URI i lokální jméno. Pro stromové čtení lze použít roxmltree, který má jiný model a neposkytuje automaticky měnitelný DOM nebo XSD validaci. Trim_text může změnit text smíšeného obsahu; nezapínej jej bez pravidel datového modelu.

Samostatná validace JSON Schema

Další samostatný main.rs; přidej závislost cargo add jsonschema@0.58.4
use serde_json::json;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let schema = json!({
        "$schema":"https://json-schema.org/draft/2020-12/schema",
        "type":"object", "required":["id"],
        "properties":{"id":{"type":"string"}}, "additionalProperties":false
    });
    let validator = jsonschema::validator_for(&schema)?;
    for data in [json!({"id":"001"}), json!({"id":1})] {
        println!("{}", validator.is_valid(&data));
    }
    Ok(())
}

Očekávané výsledky jsou true a false. Serde_json zajišťuje JSON model; jsonschema za běhu programu kontroluje hodnoty podle zvolené verze schématu. Pro chybové hlášení využij API iter_errors podle použité verze a vracej uživateli cestu i důvod. Při načítání odkazovaných schémat povol pouze známé zdroje, například předem registrované místní schéma.

Dokumentace použitého API: Reader, jsonschema. Zabezpečení XML se neodvozuje pouze od paměťové bezpečnosti Rustu: hloubka, velikost a aplikační oprávnění zůstávají samostatné požadavky.