Xml in Crystal

Here’s the translation of the XML example from Go to Crystal, formatted in Markdown suitable for Hugo:

# Crystal offers XML parsing and generation through the `XML` module.

require "xml"

# Plant will be mapped to XML. We use annotations to specify
# how the struct should be serialized. The `XML::Serializable`
# module provides the functionality for XML serialization.
class Plant
  include XML::Serializable

  # The `root` annotation specifies the name of the root XML element.
  @[XML::Name(name: "plant")]
  # The `attribute` annotation indicates that `id` should be an XML attribute.
  @[XML::Attribute(name: "id")]
  property id : Int32

  property name : String
  property origin : Array(String)

  def initialize(@id : Int32, @name : String, @origin : Array(String) = [] of String)
  end

  def to_s
    "Plant id=#{@id}, name=#{@name}, origin=#{@origin}"
  end
end

# The main function where we demonstrate XML operations
def main
  coffee = Plant.new(id: 27, name: "Coffee", origin: ["Ethiopia", "Brazil"])

  # Generate XML representing our plant
  xml = coffee.to_xml(indent: "  ")
  puts xml

  # To add a generic XML header to the output, prepend it explicitly
  puts "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n#{xml}"

  # Parse XML into a Plant object
  parsed_plant = Plant.from_xml(xml)
  puts parsed_plant

  tomato = Plant.new(id: 81, name: "Tomato", origin: ["Mexico", "California"])

  # Define a structure for nesting plants
  class Nesting
    include XML::Serializable

    @[XML::Name(name: "nesting")]
    property plants : Array(Plant)

    def initialize(@plants : Array(Plant))
    end
  end

  nesting = Nesting.new([coffee, tomato])

  # Generate nested XML
  nested_xml = nesting.to_xml(indent: "  ")
  puts nested_xml
end

main

This Crystal code demonstrates XML parsing and generation using the XML module. Here’s a breakdown of the main components:

  1. We define a Plant class that includes XML::Serializable for XML serialization and deserialization. We use annotations to control how the class is serialized to XML.

  2. In the main function, we create Plant instances and demonstrate XML generation using to_xml.

  3. We show how to parse XML back into Crystal objects using from_xml.

  4. We create a Nesting class to demonstrate nested XML structures.

  5. Finally, we generate nested XML using the Nesting class.

To run this program, save it as xml_example.cr and use the Crystal compiler:

$ crystal xml_example.cr

This will output the generated XML structures and the parsed Plant object.

Crystal’s XML handling is similar to Go’s, but it uses annotations and modules instead of struct tags. The XML::Serializable module provides functionality similar to Go’s encoding/xml package.