XML to Crystal
Paste XML and instantly generate ready-to-use Crystal struct definitions with inferred types and JSON serialization.
Example
Repeated elements become arrays and attributes become struct fields.
Input:
<book id="1">
<title>Crystal</title>
<pages>320</pages>
</book>
Output:
require "json"
struct Book
include JSON::Serializable
property id : Int64
property title : String
property pages : Int64
end
How it works
It parses your XML with the browser's DOMParser, builds a value model from elements, attributes and text, infers Crystal types, then emits one struct per shape including JSON::Field key mappings for names that are not valid identifiers.
Good to know
XML to Crystal turns a sample of XML into ready-to-paste Crystal struct definitions that include JSON::Serializable, so you don't have to hand-write field declarations and figure out each type yourself. It's aimed at Crystal developers who receive data as XML (a SOAP response, an RSS or Atom feed, a config file, a legacy API export) and want a typed model to deserialize into without writing the boilerplate by hand.
Reach for it when you're prototyping against an unfamiliar XML payload and want a quick, structurally accurate starting point. Paste a representative document, click Convert, and you get one struct per distinct element shape. Repeated sibling elements (like multiple <book> entries) collapse into a single struct plus an Array(...) property, and XML attributes become regular fields with a @[JSON::Field(key: "...")] annotation preserving the original name.
To read the output, scan the generated structs top to bottom: each property name : Type line shows the inferred Crystal type, and a trailing ? marks a field as nilable. The tool adds that ? when it sees the same element shape more than once and a field is present in some occurrences but missing in others, so an optional marker usually signals inconsistency across your sample rather than a true optional in the source schema.
Practical tip: feed it the most complete and varied example you have, ideally with several repeated elements, because the tool infers everything from the text you paste and cannot know about fields that never appear. Watch for fields typed as JSON::Any or Array(JSON::Any) — that means the inferencer saw mixed or empty values and fell back to a generic type you'll likely want to tighten by hand. Note that conversion to JSON serialization assumes you ultimately want JSON I/O; if you need to parse the XML directly, treat the structs as a schema reference rather than a drop-in parser.
Frequently asked questions
How are XML attributes handled?
Each attribute becomes a struct property. Since Crystal identifiers cannot contain characters like hyphens, attributes are converted to snake_case and given a @[JSON::Field(key: "...")] annotation that preserves the original name.
How does it decide between Int64, Float64, Bool, and String?
It inspects each element's text: whole numbers map to Int64, decimals to Float64, true/false to Bool, and everything else to String. When a repeated element mixes types (for example an integer and a decimal), it widens to the most general matching type.
Is my data uploaded anywhere?
No — this tool runs entirely in your browser. Your input never leaves your device and it works offline once loaded.
Is it free?
Yes, completely free with no sign-up and no limits.
People also ask
What is JSON::Serializable in Crystal?
JSON::Serializable is a module in Crystal's standard library that you include in a struct or class to automatically gain from_json and to_json methods based on the type's properties. The generated structs include it so each struct can be created directly from JSON and serialized back without writing manual parsing code.
Why does the tool output JSON serialization instead of XML parsing for Crystal?
Crystal's standard library has built-in JSON serialization via JSON::Serializable but no equivalent automatic XML mapping. The tool uses XML only to infer the data shape and types, then emits structs wired for JSON, which is the more common serialization target in Crystal projects.
How does Crystal handle nilable types like String?
In Crystal a type ending in ? such as String? is shorthand for a union with Nil, meaning the value can be either a String or nil. The tool adds this marker to fields it judges may be absent based on the sample XML.
What is the difference between a struct and a class in Crystal?
In Crystal a struct is a value type passed by copy and allocated on the stack, while a class is a reference type passed by reference and allocated on the heap. This tool generates structs, which are well suited to small immutable data records.
Can this tool convert an XSD or DTD schema instead of an XML document?
No. It works from an actual XML instance document and infers types from the literal text values it finds, so schema files like XSD or DTD are not used as input. To capture every possible field, provide an XML sample that exercises all the elements and attributes you care about.
Why are some generated fields typed as JSON::Any?
JSON::Any is Crystal's catch-all type for values whose concrete type is not known. The tool falls back to it when an element is empty or when repeated occurrences contain incompatible value types it cannot widen to a single specific type.
Does the tool need an internet connection to work?
No. It runs entirely in your browser using the built-in DOMParser, so once the page has loaded it works offline and your XML never leaves your device.
How are nested XML elements represented in the output?
Each distinct nested element shape becomes its own named struct, and the parent references it as a property. Nesting is resolved by element name, so a child element with sub-elements is emitted as a separate struct rather than being flattened.
Related tools