FormatterHQ

XML to Crystal Class Generator

Generate Crystal classes from an XML sample, with typed properties for attributes and child elements and arrays for repeated elements.

Input XML
Output RUBY
Ready.

How to use the XML to Crystal

  1. Paste your XML document into the Input editor, or use Sample, Upload file or Load URL, or press Sample to see an example.
  2. Leave Top-level class name empty to name the root type after the root element, or type your own name.
  3. The Types only option has no effect for Crystal; classes include JSON::Serializable.
  4. Press Generate (it also updates as you edit), then use Copy or Download.

XML to Crystal classes

Crystal's standard library includes an XML module based on libxml2, with XML.parse and XPath queries, but no built-in mapping from XML to typed objects. This XML to Crystal generator gives you the typed side: classes with property declarations inferred from a sample document. You then fill them from the parsed XML, getting compile-time checked models for the rest of your program.

Example: a sitemap

<sitemap>
  <url priority="1.0"><loc>https://example.com/</loc><lastmod>2026-05-01</lastmod></url>
  <url priority="0.8"><loc>https://example.com/docs</loc><lastmod>2026-04-20</lastmod></url>
</sitemap>
class Sitemap
  include JSON::Serializable
  property url : Array(Url)
end

class Url
  include JSON::Serializable
  property loc : String
  property lastmod : String
  property priority : Float64
end

The priority attribute became Float64; lastmod is a date-only value and stays String.

Filling the classes with Crystal's XML module

The generated classes include JSON::Serializable, which gives them a constructor that reads JSON. For XML, add a small class method that walks the document:

require "xml"

class Url
  def self.from_node(node : XML::Node) : Url
    json = {
      loc:      node.xpath_string("string(loc)"),
      lastmod:  node.xpath_string("string(lastmod)"),
      priority: node["priority"].to_f,
    }.to_json
    Url.from_json(json)
  end
end

doc = XML.parse(xml_text)
urls = doc.xpath_nodes("//url").map { |n| Url.from_node(n) }

Attributes are read with node["name"], element text with xpath_string, and all values arrive as strings, so convert with to_f, to_i or a comparison for booleans. Real sitemaps declare a default namespace; with namespaces, pass a namespace map to the XPath calls.

How the XML is mapped

The root element names the top-level class (Sitemap), unless you enter another name. Attributes such as priority and child elements such as <loc> become properties of the same class; if an element has attributes and text, the text becomes a value property. Namespace prefixes are removed and the XML declaration is ignored. Text is typed from its content, so 1.0 becomes Float64 and true a Bool. Keep this mapping in mind when you write the XPath for each property: the class alone does not tell you which properties were attributes.

Things to check

  • Repeated elements must appear at least twice in the sample to become Array properties.
  • Whole numbers become Int32; use Int64 for large counts or IDs.
  • Optional elements missing from some records get nilable types such as String?.

For JSON sources, JSON to Crystal is a direct fit. Prepare the input with the XML Formatter. Generation runs in your browser.

Sitemaps and other namespaced XML

Real sitemaps declare a default namespace, xmlns="http://www.sitemaps.org/schemas/sitemap/0.9". XPath then no longer matches plain //url, which is the usual reason a Crystal program finds zero nodes. Register a prefix for the namespace and use it in the query:

ns = {"s" => "http://www.sitemaps.org/schemas/sitemap/0.9"}
urls = doc.xpath_nodes("//s:url", ns).map { |n| Url.from_node(n) }

The same namespace map must be passed to the xpath_string calls inside from_node, with the prefix in each path, such as string(s:loc). The generated classes need no changes, since the generator already drops namespace prefixes from names.

Frequently asked questions

Does Crystal have built-in XML serialization?
No. The standard XML module parses documents and supports XPath, but mapping to classes is done by hand or with a shard. The generated classes give you the typed target.
Why do the classes include JSON::Serializable?
The generator models the JSON form of your XML. It is also convenient: you can build objects from a JSON string, as in the example.
Why is lastmod a String?
Date-only values are kept as strings. Parse them with Time.parse when you need Time values.
How do I read attributes in Crystal?
Use node["attribute"] on an XML::Node. Missing attributes raise, so use node["attr"]? to get nil instead.

Last updated September 26, 2026

Related tools

JSON to Crystal Generate Crystal classes with JSON mapping from a JSON sample instantly, with nested types detected automatically. XML to C# Generate C# classes with JsonProperty attributes from a XML sample instantly, with nested types detected automatically. XML to Dart Generate Dart classes with fromJson and toJson from a XML sample instantly, with nested types detected automatically. XML to Elm Generate Elm type aliases with decoders from a XML sample instantly, with nested types detected automatically. XML to Flow Generate Flow Flow type definitions from a XML sample instantly, with nested types detected automatically. XML to Go Generate Go structs with json tags from a XML sample instantly, with nested types detected automatically. XML to Haskell Generate Haskell records with Aeson instances from a XML sample instantly, with nested types detected automatically. XML to Java Generate Java POJO classes with getters and setters from a XML sample instantly, with nested types detected automatically. XML to JavaScript PropTypes Generate JavaScript PropTypes React PropTypes definitions from a XML sample instantly, with nested types detected automatically. XML to JSON Schema Generate JSON Schema a JSON Schema document from a XML sample instantly, with nested types detected automatically. XML to Kotlin Generate Kotlin data classes from a XML sample instantly, with nested types detected automatically. XML to Objective-C Generate Objective-C classes with properties from a XML sample instantly, with nested types detected automatically.