Xmloxide: AI 에이전트 지원으로 생성된 libxml2의 Rust 재구현

Xmloxide란 무엇인가요?
Xmloxide는 XML 및 HTML 문서를 파싱, 생성, 조작하는 데 널리 사용되는 C 라이브러리인 libxml2를 순수 Rust로 재구현한 프로젝트입니다. 이 프로젝트는 2025년 12월에 공식적으로 유지 관리가 중단되고 알려진 보안 문제가 발생한 libxml2 이후에 만들어졌습니다. 개발자는 Claude Code를 사용하여 AI 에이전트가 기존 테스트 스위트를 통과할 때까지 작업하도록 하여 라이브러리를 재현했습니다.
주요 기능 및 능력
- 메모리 안전 — 공개 API에서 안전하지 않은 코드 없이 아레나 기반 트리 제공
- 표준 준수 — W3C XML 적합성 테스트 스위트 100% 통과율 (1727/1727 적용 가능 테스트)
- 오류 복구 — 손상된 XML을 파싱하고 여전히 사용 가능한 트리 생성 (libxml2와 동일)
- 다중 파싱 API — DOM 트리, SAX2 스트리밍, XmlReader 풀, 푸시/증분 파싱
- HTML 파서 — 오류 허용 HTML 4.01 파싱, 자동 닫기 및 빈 요소 지원
- XPath 1.0 — 모든 핵심 함수를 포함한 완전한 표현식 파서 및 평가기
- 검증 — DTD, RelaxNG, XML 스키마(XSD) 검증
- 정규 XML — C14N 1.0 및 배타적 C14N 직렬화
- XInclude — 문서 포함 처리
- XML 카탈로그 — URI 해결을 위한 OASIS XML 카탈로그
- xmllint CLI — XML 파싱, 검증, 쿼리를 위한 명령줄 도구
- 가능한 경우 제로 카피 — 빠른 비교를 위한 문자열 인터닝
- 전역 상태 없음 — 각 문서는 자체 포함되어 있으며 Send + Sync 지원
- C/C++ FFI — C/C++ 프로젝트에 내장하기 위한 헤더 파일(include/xmloxide.h)을 포함한 완전한 C API
- 최소 의존성 — encoding_rs만 사용 (라이브러리는 다른 의존성 없음; clap은 CLI 전용)
성능 및 호환성
대부분의 파싱 작업에서 libxml2와 유사한 성능을 보이며 직렬화에서는 더 나은 성능을 제공합니다. 이 라이브러리는 호환성 스위트와 W3C XML 적합성 테스트 스위트를 모두 통과합니다.
코드 예제
기본 파싱:
use xmloxide::Document;
let doc = Document::parse_str("<root><child>Hello</child></root>").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("root"));
assert_eq!(doc.text_content(root), "Hello");
직렬화:
use xmloxide::Document;
use xmloxide::serial::serialize;
let doc = Document::parse_str("<root><child>Hello</child></root>").unwrap();
let xml = serialize(&doc);
assert_eq!(xml, "<root><child>Hello</child></root>");
XPath 쿼리:
use xmloxide::Document;
use xmloxide::xpath::{evaluate, XPathValue};
let doc = Document::parse_str("<library><book><title>Rust</title></book></library>").unwrap();
let root = doc.root_element().unwrap();
let result = evaluate(&doc, root, "count(book)").unwrap();
assert_eq!(result.to_number(), 1.0);
SAX2 스트리밍:
use xmloxide::sax::{parse_sax, SaxHandler, DefaultHandler};
use xmloxide::parser::ParseOptions;
struct MyHandler;
impl SaxHandler for MyHandler {
fn start_element(&mut self, name: &str, _: Option<&str>, _: Option<&str>, _: &[(String, String, Option<String>, Option<String>)]) {
println!("Element: {name}");
}
}
parse_sax("<root><child/></root>", &ParseOptions::default(), &mut MyHandler).unwrap();
HTML 파싱:
use xmloxide::html::parse_html;
let doc = parse_html("<p>Hello <br> World").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("html"));
오류 복구:
use xmloxide::parser::{parse_str_with_options, ParseOptions};
let opts = ParseOptions::default().recover(true);
let doc = parse_str_with_options("<root><unclosed>", &opts).unwrap();
for diag in &doc.diagnostics {
eprintln!("{}", diag);
}
CLI 사용법
xmllint CLI 도구는 다음을 제공합니다:
# 파싱 및 예쁘게 출력
xmllint --format document.xml
스키마에 대해 검증
xmllint --schema schema.xsd document.xml
xmllint --relaxng schema.rng document.xml
xmllint --dtdvalid
AI 에이전트 개발 배경
개발자는 libxml2를 대상으로 하기 전에 Claude Code를 사용하여 Redis와 SQLite를 재현하는 실험을 했습니다. 이 접근 방식은 AI 에이전트가 기존 테스트 스위트를 통과할 때까지 프로젝트 작업을 수행하도록 하는 것을 포함했습니다. 이는 코딩 에이전트가 테스트 스위트가 주어지면 빠르게 반복 작업을 수행하여 레거시 코드 유지 관리 문제를 해결할 수 있는 방법을 보여줍니다.
📖 전체 소스 읽기: HN AI Agents
👀 See Also

클로드 코드의 병렬 서브 에이전트: 토큰 절약과 소모의 순간
Anthropic은 멀티 에이전트 시스템이 단일 채팅보다 약 15배 더 많은 토큰을 사용하지만, 프롬프트 캐싱을 통해 토큰 비용을 90% 할인받을 수 있다고 보고합니다. 하위 에이전트가 비용을 절약하거나 낭비하는지는 캐시 적중률에 달려 있습니다.

cstat: Claude Code를 위한 2ms 성능의 네이티브 Rust 상태 표시줄
cstat은 네이티브 Rust 바이너리로, 24개의 서브프로세스 생성 제거를 통해 claude-hud의 62ms 상태 표시줄을 2ms 구현으로 대체합니다. 모델 정보, 속도 제한, git 상태, 컨텍스트 창 사용량, 활성 도구, 서브에이전트 및 작업 진행 상황을 표시합니다.

마인드 프로토콜: 오픈소스 시스템으로 클로드에 지속적 메모리와 실시간 생체 인식 통합 제공
Mind Protocol은 Claude가 자율적인 동반자로 지속적으로 실행되는 오픈소스 시스템입니다. 이 시스템은 모든 세션에 걸쳐 지속적인 메모리를 제공하며, 패턴, 선호도, 기록에 대한 수개월간 누적된 컨텍스트를 Claude에 제공합니다. 또한 모든 대화에 실시간 Garmin 워치 데이터(심박수, HRV, 스트레스, 수면 지표, 체력 배터리 수치 등)를 주입합니다.

로컬 LLM을 Claude 코드 서브에이전트로 사용하여 컨텍스트 사용량 줄이기
레딧 사용자가 Claude Code가 LM Studio를 통해 실행되는 로컬 LLM에 작업을 위임하여 파일 내용을 Claude의 컨텍스트 밖으로 유지하는 방법을 시연합니다. 이 설정은 로컬 파일 작업을 처리하기 위해 LM Studio의 도구 호출 API를 사용하는 약 120줄의 Python 스크립트를 활용합니다.