Xml in D Programming Language

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

import std.stdio;
import std.xml;

// Plant will be mapped to XML. Field attributes contain directives for the
// encoder and decoder. Here we use some special features
// of the std.xml package: the `xmlName` attribute dictates
// the name of the XML element representing this struct;
// `attr` means that the `id` field is an XML
// *attribute* rather than a nested element.
struct Plant {
    @xmlName("plant")
    string elementName;
    
    @attr
    int id;
    
    string name;
    string[] origin;
    
    string toString() const {
        import std.format : format;
        return format("Plant id=%d, name=%s, origin=%s", id, name, origin);
    }
}

void main() {
    auto coffee = Plant(null, 27, "Coffee", ["Ethiopia", "Brazil"]);

    // Emit XML representing our plant; using
    // `PrettyPrintXML` to produce a more
    // human-readable output.
    auto xml = coffee.toXML();
    writeln(xml.toPrettyString());

    // To add a generic XML header to the output, prepend
    // it explicitly.
    writeln("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", xml.toPrettyString());

    // Use `parseXML` to parse a stream of characters with XML
    // into a data structure. If the XML is malformed or
    // cannot be mapped onto Plant, an exception
    // will be thrown.
    auto p = xml.parseXML!Plant;
    writeln(p);

    auto tomato = Plant(null, 81, "Tomato", ["Mexico", "California"]);

    // The `parent>child>plant` field attribute tells the encoder
    // to nest all `plant`s under `<parent><child>...`
    struct Nesting {
        @xmlName("nesting")
        string elementName;
        
        @xmlElementList("parent", "child", "plant")
        Plant[] plants;
    }

    auto nesting = Nesting(null, [coffee, tomato]);

    xml = nesting.toXML();
    writeln(xml.toPrettyString());
}

This D code demonstrates XML encoding and decoding using the std.xml module. Here are some key points about the translation:

  1. D uses structs instead of Go’s structs, but they serve a similar purpose.

  2. XML attributes in D are specified using UDAs (User-Defined Attributes) like @xmlName, @attr, and @xmlElementList.

  3. The toString method in D is similar to Go’s String method for custom string representation.

  4. D’s toXML() method is used for marshaling, which is similar to Go’s xml.Marshal.

  5. D’s parseXML!Plant is used for unmarshaling, which is similar to Go’s xml.Unmarshal.

  6. D’s toPrettyString() method is used to produce indented XML output, similar to Go’s MarshalIndent.

  7. Error handling in D typically uses exceptions, rather than returning error values like in Go.

  8. D doesn’t have a direct equivalent to Go’s XML header constant, so we manually prepend it when needed.

This code provides similar functionality to the original Go example, demonstrating XML marshaling, unmarshaling, and working with nested XML structures in D.