Xml in Nim

import xml, strformat

type
  Plant = object
    id: int
    name: string
    origin: seq[string]

proc `$`(p: Plant): string =
  fmt"Plant id={p.id}, name={p.name}, origin={p.origin}"

proc main() =
  var coffee = Plant(id: 27, name: "Coffee", origin: @["Ethiopia", "Brazil"])

  # Emit XML representing our plant; using
  # xmltree to produce a more human-readable output.
  var node = newElement("plant")
  node.attrs = {"id": $coffee.id}.toXmlAttributes
  node.add newElement("name")
  node.child("name").add newText(coffee.name)
  for place in coffee.origin:
    node.add newElement("origin")
    node.child("origin")[^1].add newText(place)

  echo node

  # To add a generic XML header to the output, append
  # it explicitly.
  echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", node

  # Use parseXml to parse a string with XML
  # into a data structure. If the XML is malformed or
  # cannot be mapped onto Plant, a descriptive error
  # will be raised.
  let xmlString = $node
  var parsed = parseXml(xmlString)
  var p = Plant(
    id: parseInt(parsed.attr("id")),
    name: parsed.child("name").innerText,
    origin: @[]
  )
  for originNode in parsed.findAll("origin"):
    p.origin.add originNode.innerText
  echo p

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

  # The parent>child>plant structure can be created
  # using nested XML elements
  var nesting = newElement("nesting")
  var parent = newElement("parent")
  var child = newElement("child")
  for plant in @[coffee, tomato]:
    var plantNode = newElement("plant")
    plantNode.attrs = {"id": $plant.id}.toXmlAttributes
    plantNode.add newElement("name")
    plantNode.child("name").add newText(plant.name)
    for place in plant.origin:
      plantNode.add newElement("origin")
      plantNode.child("origin")[^1].add newText(place)
    child.add plantNode
  parent.add child
  nesting.add parent

  echo nesting

main()

This Nim code demonstrates XML processing capabilities similar to the original example. Here’s a breakdown of the changes and explanations:

  1. We import the xml module for XML processing and strformat for string formatting.

  2. The Plant type is defined as an object in Nim, which is similar to a struct in other languages.

  3. The $ operator is overloaded to provide a string representation of the Plant object.

  4. In the main procedure, we create XML nodes using the newElement and newText functions from the xml module.

  5. To parse XML, we use the parseXml function, which returns an XmlNode. We then extract the data from this node to create a Plant object.

  6. The nested XML structure is created by manually constructing nested XmlNode objects.

  7. Error handling in Nim is typically done through exceptions, which would be raised automatically if there are issues with XML parsing or other operations.

This Nim code provides similar functionality to the original example, allowing for XML creation, parsing, and manipulation. The syntax and some concepts are different, but the overall structure and flow of the program remain similar.