Xml in Perl

use strict;
use warnings;
use XML::LibXML;
use Data::Dumper;

# Plant will be mapped to XML. We use XML::LibXML to handle XML operations.
# In Perl, we'll use a hash reference to represent the Plant structure.
sub new_plant {
    my ($id, $name, @origin) = @_;
    return {
        id     => $id,
        name   => $name,
        origin => \@origin,
    };
}

# Helper function to convert a plant hash to a string
sub plant_to_string {
    my $p = shift;
    return sprintf("Plant id=%d, name=%s, origin=[%s]",
        $p->{id}, $p->{name}, join(' ', @{$p->{origin}}));
}

# Create a new XML document
my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');

# Create a plant
my $coffee = new_plant(27, "Coffee", "Ethiopia", "Brazil");

# Create the plant element
my $plant = $doc->createElement('plant');
$plant->setAttribute('id', $coffee->{id});
$plant->appendTextChild('name', $coffee->{name});
for my $origin (@{$coffee->{origin}}) {
    $plant->appendTextChild('origin', $origin);
}

# Add the plant to the document
$doc->setDocumentElement($plant);

# Print the XML
print $doc->toString(1);  # The argument 1 enables pretty printing

# To add a generic XML header to the output, we can use XML declaration
print $doc->xmlDeclaration, "\n", $doc->toString(1);

# Parse XML back into a data structure
my $parsed_doc = XML::LibXML->load_xml(string => $doc->toString);
my $parsed_plant = $parsed_doc->documentElement();

my %p;
$p{id} = $parsed_plant->getAttribute('id');
$p{name} = $parsed_plant->findvalue('./name');
$p{origin} = [$parsed_plant->findnodes('./origin')];
@{$p{origin}} = map { $_->textContent } @{$p{origin}};

print plant_to_string(\%p), "\n";

# Create another plant
my $tomato = new_plant(81, "Tomato", "Mexico", "California");

# Create a nesting structure
my $nesting = {
    plants => [$coffee, $tomato]
};

# Create a new document for the nesting structure
my $nesting_doc = XML::LibXML::Document->new('1.0', 'UTF-8');
my $nesting_root = $nesting_doc->createElement('nesting');
$nesting_doc->setDocumentElement($nesting_root);

my $parent = $nesting_doc->createElement('parent');
my $child = $nesting_doc->createElement('child');
$parent->appendChild($child);
$nesting_root->appendChild($parent);

for my $p (@{$nesting->{plants}}) {
    my $plant = $nesting_doc->createElement('plant');
    $plant->setAttribute('id', $p->{id});
    $plant->appendTextChild('name', $p->{name});
    for my $origin (@{$p->{origin}}) {
        $plant->appendTextChild('origin', $origin);
    }
    $child->appendChild($plant);
}

print $nesting_doc->toString(1);

This Perl script demonstrates XML handling using the XML::LibXML module, which provides similar functionality to Go’s encoding/xml package. Here’s a breakdown of the translation:

  1. We define a new_plant function to create a hash reference representing a plant, similar to the Plant struct in Go.

  2. The plant_to_string function provides similar functionality to the String() method in Go.

  3. We use XML::LibXML::Document to create and manipulate XML documents.

  4. The createElement, setAttribute, and appendTextChild methods are used to build the XML structure.

  5. We use toString(1) to generate indented XML output, similar to MarshalIndent in Go.

  6. For parsing XML, we use XML::LibXML->load_xml and then extract data using DOM methods.

  7. The nesting structure is created in a similar way, building up the XML document using createElement and appendChild.

This script provides equivalent functionality to the Go example, demonstrating XML creation, marshaling, unmarshaling, and nested structures in Perl.