Xml in TypeScript

Here’s the translation of the XML handling code from Go to TypeScript, formatted in Markdown suitable for Hugo:

import { parseString, Builder } from 'xml2js';

// Plant will be mapped to XML. We use class properties to define
// the structure and decorators to specify XML attributes and elements.
class Plant {
    @XmlAttribute('id')
    id: number;

    @XmlElement('name')
    name: string;

    @XmlElement('origin')
    origin: string[];

    constructor(id: number, name: string, origin: string[] = []) {
        this.id = id;
        this.name = name;
        this.origin = origin;
    }

    toString(): string {
        return `Plant id=${this.id}, name=${this.name}, origin=${this.origin}`;
    }
}

// Helper decorators for XML serialization
function XmlAttribute(name: string) {
    return function(target: any, key: string) {
        target[`$${key}`] = name;
    }
}

function XmlElement(name: string) {
    return function(target: any, key: string) {
        target[key] = { [name]: target[key] };
    }
}

async function main() {
    const coffee = new Plant(27, "Coffee", ["Ethiopia", "Brazil"]);

    // Create an XML builder
    const builder = new Builder({ rootName: 'plant' });

    // Convert the plant object to XML
    const xml = builder.buildObject(coffee);
    console.log(xml);

    // Add a generic XML header
    console.log(`<?xml version="1.0" encoding="UTF-8"?>\n${xml}`);

    // Parse XML back into an object
    parseString(xml, (err, result) => {
        if (err) {
            console.error(err);
            return;
        }
        const p = new Plant(
            parseInt(result.plant.$.id),
            result.plant.name[0],
            result.plant.origin
        );
        console.log(p.toString());
    });

    const tomato = new Plant(81, "Tomato", ["Mexico", "California"]);

    // The nested structure is represented using a class
    class Nesting {
        @XmlElement('parent>child>plant')
        plants: Plant[];

        constructor(plants: Plant[]) {
            this.plants = plants;
        }
    }

    const nesting = new Nesting([coffee, tomato]);

    // Convert the nested structure to XML
    const nestedXml = builder.buildObject(nesting);
    console.log(nestedXml);
}

main().catch(console.error);

This TypeScript code demonstrates XML handling using the xml2js library, which is commonly used for XML parsing and generation in Node.js environments. Here’s an explanation of the key parts:

  1. We define a Plant class with properties that will be mapped to XML elements and attributes. We use custom decorators (@XmlAttribute and @XmlElement) to specify how each property should be serialized.

  2. The toString method provides a string representation of the Plant object.

  3. We create helper decorator functions XmlAttribute and XmlElement to mark properties for XML serialization.

  4. In the main function, we create Plant objects and demonstrate XML serialization and deserialization.

  5. We use the Builder class from xml2js to convert objects to XML strings.

  6. For parsing XML back into objects, we use the parseString function from xml2js.

  7. We demonstrate nested XML structures using a Nesting class that contains an array of Plant objects.

To run this code, you would need to install the xml2js library using npm:

$ npm install xml2js @types/xml2js
$ ts-node xml-example.ts

This will output the XML representations of the Plant and Nesting objects, demonstrating both simple and nested XML structures.

Note that TypeScript doesn’t have built-in XML support like Go does, so we’re using a popular third-party library. The concepts are similar, but the implementation details differ.