claudexml
Pydantic-like XML parser for Claude's XML output. Define a schema, parse Claude's response, get a validated Python object.
Installation
From PyPI:
pip install claudexml
Or install from GitHub:
pip install git+https://github.com/sieuchuoicb/claudexml.git
With optional extras:
pip install claudexml[anthropic] # Anthropic SDK integration
pip install claudexml[pydantic] # Pydantic interop
Quick Start
from claudexml import XMLModel, XMLTag
class Analysis(XMLModel):
thinking: str = XMLTag("thinking")
answer: str = XMLTag("answer")
confidence: float = XMLTag("confidence")
xml = """
<thinking>The user is asking about the meaning of life.</thinking>
<answer>42</answer>
<confidence>0.95</confidence>
"""
result = Analysis.from_xml(xml)
result.thinking # "The user is asking about the meaning of life."
result.answer # "42"
result.confidence # 0.95 (float, not string)
Features
Type Coercion
Automatically converts XML string content to Python types:
class Metrics(XMLModel):
count: int = XMLTag("count") # "42" -> 42
score: float = XMLTag("score") # "0.95" -> 0.95
active: bool = XMLTag("active") # "true" -> True
Optional Fields & Defaults
class Response(XMLModel):
answer: str = XMLTag("answer")
thinking: str | None = XMLTag("thinking", default=None)
confidence: float = XMLTag("confidence", default=0.5)
Nested Models
class Source(XMLModel):
url: str = XMLTag("url")
title: str = XMLTag("title")
class Research(XMLModel):
sources: Source = XMLTag("sources")
summary: str = XMLTag("summary")
List Fields
class Review(XMLModel):
issues: list[str] = XMLTag("issue")
xml = "<issue>bug 1</issue><issue>bug 2</issue>"
result = Review.from_xml(xml)
result.issues # ["bug 1", "bug 2"]
Validators
from claudexml import XMLModel, XMLTag, field_validator
class Scored(XMLModel):
score: float = XMLTag("score")
@field_validator("score")
def check_range(cls, v):
if not 0 <= v <= 1:
raise ValueError("score must be between 0 and 1")
return v
Attributes
Extract XML attribute values alongside text content:
class Item(XMLModel):
name: str = XMLTag("item") # text content
item_id: str = XMLTag("item", attribute="id") # attribute value
xml = '<item id="123">Widget</item>'
result = Item.from_xml(xml)
result.name # "Widget"
result.item_id # "123"
Streaming
Parse XML incrementally as Claude streams tokens:
from claudexml import XMLStreamParser
parser = XMLStreamParser(Analysis)
for event in stream:
parser.feed(event.text)
partial = parser.partial() # partially filled model (no validation)
if parser.is_complete():
result = parser.result() # fully validated model
CDATA Support
Handles <![CDATA[...]]> sections for raw content:
class CodeBlock(XMLModel):
code: str = XMLTag("code")
xml = "<code><![CDATA[if (x < 5 && y > 3) { return true; }]]></code>"
result = CodeBlock.from_xml(xml)
result.code # "if (x < 5 && y > 3) { return true; }"
JSON Export
Convert models to JSON:
result = Analysis.from_xml(xml)
result.to_json() # compact JSON string
result.to_json(indent=2) # pretty-printed
result.to_dict() # Python dictionary
Schema-Free Extraction
For quick parsing without defining a model:
from claudexml import extract_tags
tags = extract_tags("<thinking>Let me analyze...</thinking><answer>42</answer>")
tags["thinking"] # "Let me analyze..."
tags["answer"] # "42"
Custom Type Coercers
Register custom type handlers for any Python type:
from datetime import datetime
from claudexml import XMLModel, XMLTag, register_coercer
@register_coercer(datetime)
def parse_datetime(value: str) -> datetime:
return datetime.fromisoformat(value)
class Event(XMLModel):
name: str = XMLTag("name")
date: datetime = XMLTag("date")
result = Event.from_xml("<name>Launch</name><date>2026-04-01T10:00:00</date>")
result.date # datetime(2026, 4, 1, 10, 0)
Prompt Helpers
Auto-generate XML schema instructions for Claude:
class CodeReview(XMLModel):
thinking: str = XMLTag("thinking")
verdict: str = XMLTag("verdict")
confidence: float = XMLTag("confidence", default=0.5)
print(CodeReview.xml_prompt())
# Respond using the following XML structure:
#
# - <thinking>: string (required)
# - <verdict>: string (required)
# - <confidence>: number (optional, default: 0.5)
Pydantic Interop
Convert between XMLModel and Pydantic (requires pip install claudexml[pydantic]):
# XMLModel -> Pydantic BaseModel
pydantic_obj = result.to_pydantic()
# Pydantic BaseModel -> XMLModel
from pydantic import BaseModel
class MySchema(BaseModel):
name: str
score: float
MyXML = XMLModel.from_pydantic_model(MySchema)
result = MyXML.from_xml("<name>test</name><score>0.95</score>")
Anthropic SDK Integration
from anthropic import Anthropic
from claudexml import XMLModel, XMLTag, parse_response
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-6-20250514",
messages=[{"role": "user", "content": "Analyze this code..."}],
)
class CodeReview(XMLModel):
thinking: str = XMLTag("thinking")
verdict: str = XMLTag("verdict")
confidence: float = XMLTag("confidence")
review = parse_response(response, CodeReview)
Error Handling
from claudexml import TagNotFoundError, ValidationError
try:
result = MyModel.from_xml(xml)
except TagNotFoundError as e:
print(f"Missing tag: {e.tag}")
except ValidationError as e:
print(f"Invalid value for {e.field}: {e}")
Fault Tolerance
claudexml gracefully handles imperfect XML from Claude:
- Unclosed tags
- Surrounding non-XML text
- Extra whitespace
- Partial output
License
MIT
Metadata
Release files for claudexml 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| claudexml-1.0.0.tar.gz | 18.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| claudexml-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.5 kB
Release files / claudexml-1.0.0.tar.gz
| Download URL | claudexml-1.0.0.tar.gz |
|---|---|
| Size | 18.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cf7d5c8a607eed9081c7fc2e222d55e88040ab4f684cee0c52ba4e0f285771f1
|
|
BLAKE2b-256 checksum How to use checksums |
e2335373fd08a27c9f5f5d824d9175917f2c8880b9d12c962b10d1ce543cc2cd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / claudexml-1.0.0-py3-none-any.whl
| Download URL | claudexml-1.0.0-py3-none-any.whl |
|---|---|
| Size | 16.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
89745786be326f3a409d65b169d692fcc445db11aa3d53434c28a49100bdb660
|
|
BLAKE2b-256 checksum How to use checksums |
71f6a3ba05979545ac5162b7e6f424d5ea7dce3d31f5f181043dfed5d1fc5328
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|