oxml
🌐 FR , Changer de langue
llms.txt

Guide de Migration

Migration depuis Python lxml vers oxml

Faites évoluer vos flux XML du wrapper C libxml2 vers la sécurité mémoire du Rust pur, le streaming zéro-copie et un parallélisme sans GIL.

Pourquoi migrer ?

En Python, lxml a longtemps dominé en encapsulant les bibliothèques C libxml2 et libxslt. Cependant, les exigences modernes de production ont évolué :

  1. Sécurité Mémoire & Zéro Vulnérabilité : libxml2 a subi de nombreuses failles CVE (dépassements de tampon, use-after-free). oxml applique #![forbid(unsafe_code)] en Rust pur sans compromis.
  2. Parallélisme Réel (Sans GIL) : lxml est restreint par le Global Interpreter Lock de Python. Les structures d'oxml (Document, XPath) implémentent Send et Sync, permettant un traitement multi-cœur fluide avec Rayon ou Tokio.
  3. Compilation Croisée Sans Dépendance C : Aucun en-tête C requis (libxml2-dev), aucun compilateur externe, fonctionnement identique sous macOS, Linux (glibc/musl) et Windows.
  4. Prise en Charge WebAssembly : oxml compile directement en WebAssembly (oxml-wasm), assurant la parité d'exécution sur le web et dans Cloudflare Workers.

Correspondance des Concepts

Python lxml.etree Écosystème Rust oxml Avantage Clé
etree.fromstring(xml) oxml::parse(xml) Arène générationnelle rapide et compacte
etree.parse(file) oxml::stream::Reader::from_reader(f) Tampon borné à 34 Ko
tree.xpath("//book/text()") doc.select("//book/text()") Moteur XPath 1.0 complet avec raccourci entier $O(1)$
XPath(expr)(tree) oxml::XPath::compile(expr)? Expression précompilée partageable entre threads
etree.iterparse(...) reader.next_borrowed() Emprunt &str zéro-copie sans allocation sur le tas
etree.tostring(el) oxml::format_xml(doc, ...) Indentation, minification et balises vides personnalisables
etree.XMLSchema(xsd).validate(doc) xmlschema::validate(&doc, &schema) Validateur XSD en Rust pur (95,2 % conformité W3C)
Scripts d'agents LLM sur mesure oxml-mcp 5 outils MCP natifs pour Claude, Cursor et agents IA

Comparaisons de Code

1. Analyse et Requêtes XPath

En Python avec lxml :

from lxml import etree

xml = """<catalog>
    <book id="bk101"><title>Dune</title>19.95</price></book>
    <book id="bk102"><title>Fondation</title>15.95</price></book>
</catalog>"""

root = etree.fromstring(xml.encode("utf-8"))
titles = root.xpath("//book[price > 18]/title/text()")
print(titles)  # ['Dune']

En Rust avec oxml :

use oxml::{parse, XPath};

fn main() -> Result<(), Box<dyn std::error.Error>> {
    let xml = r#"<catalog>
        <book id="bk101"><title>Dune</title>19.95</price></book>
        <book id="bk102"><title>Fondation</title>15.95</price></book>
    </catalog>"#;

    let doc = parse(xml)?;
    let xpath = XPath::compile("//book[price > 18]/title/text()")?;
    let titles = xpath.evaluate(&doc);
    assert_eq!(titles.to_str(&doc), "Dune");
    Ok(())
}

2. Flux à Haute Performance et Mémoire Bornée

En Python, iterparse impose un appel systématique à elem.clear() pour éviter les fuites mémoire :

for event, elem in etree.iterparse(file_obj, tag="item"):
    process(elem)
    elem.clear()  # Requis pour libérer la mémoire en C

En Rust avec oxml, la mémoire est strictement bornée avec emprunt de tranches zéro-copie :

use oxml::stream::{BorrowedEvent, Reader};

let mut reader = Reader::from_reader(file)?;
while let Some(event) = reader.next_borrowed()? {
    match event {
        BorrowedEvent::StartElement { name, .. } if name.local == "item" => {
            // Emprunt direct depuis le tampon sans allocation sur le tas
        }
        _ => {}
    }
}

3. Validation de Schémas XML (XSD)

En Python avec lxml :

schema = etree.XMLSchema(etree.parse("schema.xsd"))
doc = etree.parse("document.xml")
is_valid = schema.validate(doc)
if not is_valid:
    print(schema.error_log)

En Rust avec xmlschema :

use xmlschema::{parse_schema, validate};

let schema = parse_schema(&std::fs::read_to_string("schema.xsd")?)?;
let doc = oxml::parse(&std::fs::read_to_string("document.xml")?)?;
let report = validate(&doc, &schema);

if report.is_valid() {
    println!("Document strictement valide !");
} else {
    for violation in &report.violations {
        eprintln!("{violation}");
    }
}