How can I arrange tags in XML :: Simple output?

Here is my scenario:

I need to generate XML via Perl in which the schema is filled with tags <xs:sequence>(i.e. tags MUST appear in order). I don’t have control over the scheme (third party), and there were so many problems when we add new CPAN modules (they don’t have a good way to distribute them to clients, etc.), which we were mostly prohibited from adding anything new (e.g. XML::Writer).

XML-ins at my disposal: XML::Parser, XML::Simple, XML::XPath.

I really like how in XML::Simpleyou create a hashref structure w / hash / arary refs and then just spit out the XML.

Is there any way to do this using XML::Simple? Or maybe roll up my own code to spit out XML in order? It seems like my biggest problem is that I will need to pull things from hashref in input order, which Perl doesn't really do all this well. I read about Tie::IxHashfor pulling things in the order of placement, but again, a module that I don't have.

It seems like I'm kind of like SOL, but I will definitely appreciate any tricks / ideas someone might have. Thanks.

+3
source share
5 answers

, XML::Simple . , ; , , . , , "", .

, . , . , , .

. , .

, , . , XML:: Simple - : OO sorted_keys. :

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

package MyXMLSimple;      # my XML::Simple subclass 
use base 'XML::Simple';

# Overriding the method here
sub sorted_keys
{
   my ($self, $name, $hashref) = @_;
   if ($name eq 'supertag')   # only this tag I care about the order;
   {
      return ('tag1', 'tag3','tag4','tag10'); # so I specify exactly the right order.
   }
   return $self->SUPER::sorted_keys($name, $hashref); # for the rest, I don't care!
}

package main; # back to main code

my $xmlParser = MyXMLSimple->new(      # Create the parser, with options:
                  KeepRoot => 1,       # gives us our root element always.
                  ForceContent => 1,   # ensures that content stays special
               );

my $structure = { 
   supertag => { 
      tag1  => { content => 'value 1' },
      tag10 => { content => 'value 2' },
      tag3  => { content => 'value 3' },
      tag4  => { content => 'value 4' },
   },
};

my $xml = $xmlParser->XMLout($structure);
print "The xml generated is:\n$xml\n";
print "The read in structure then is:\n" . $xmlParser->XMLin($xml) . "\n";

:

The xml generated is:
<supertag>
  <tag1>value 1</tag1>
  <tag3>value 3</tag3>
  <tag4>value 4</tag4>
  <tag10>value 2</tag10>
</supertag>

The read in structure then is:
$VAR1 = {
          'supertag' => {
                          'tag10' => {
                                       'content' => 'value 2'
                                     },
                          'tag3' => {
                                      'content' => 'value 3'
                                    },
                          'tag1' => {
                                      'content' => 'value 1'
                                    },
                          'tag4' => {
                                      'content' => 'value 4'
                                    }
                        }
        };

XML::Simple CPAN.

+11

`XML:: Simple ' hook, . , , -, .

+1

, :

use strict;
use warnings;
use XML::Simple;

my $structure = { 'supertag' => [
      'value 1',
      'value 2',
      'value 3',
      'value 4',
   ],
};

my $xml = XMLout($structure, GroupTags => { supertag => 'tag'});

print "The xml generated is:\n";
print $xml;
print "\n";

:

The xml generated is:
<opt>
  <supertag>
    <tag>value 1</tag>
    <tag>value 2</tag>
    <tag>value 3</tag>
    <tag>value 4</tag>
  </supertag>
</opt>
0

@Konerak comment @robert-p. .

#!/usr/bin/perl -w
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;

package MyXMLSimple;      # my XML::Simple subclass 
use base 'XML::Simple';

# Overriding the method here
sub sorted_keys
{
   my ($self, $name, $hashref) = @_;
   if ($name eq 'supertag')   # only this tag I care about the order;
   {
      my @ordered = ('tag1', 'tag3','tag4','tag10');
      my %ordered_hash = map {$_ => 1} @ordered;

      #set ordered tags in front of others
      return @ordered, grep {not $ordered_hash{$_}} $self->SUPER::sorted_keys($name, $hashref);
   }
   return $self->SUPER::sorted_keys($name, $hashref); # for the rest, I don't care!
}

package main; # back to main code

my $xmlParser = MyXMLSimple->new(      # Create the parser, with options:
                  KeepRoot => 1,       # gives us our root element always.
                  ForceContent => 1,   # ensures that content stays special
               );

my $structure = { 
   supertag => { 
      tag1  => { content => 'value 1' },
      tag10 => { content => 'value 2' },
      tag3  => { content => 'value 3' },
      tag4  => { content => 'value 4' },
      tag90  => { content => 'value 90' },
      tag91  => { content => 'value 91' },
   },
};

my $xml = $xmlParser->XMLout($structure);
my $xml2 = $xmlParser->XMLin($xml);  
print "The xml generated is:\n$xml\n";
print "The read in structure then is:\n" . Dumper($xml2) . "\n";

The xml generated is:
<supertag>
  <tag1>value 1</tag1>
  <tag3>value 3</tag3>
  <tag4>value 4</tag4>
  <tag10>value 2</tag10>
  <tag90>value 90</tag90>
  <tag91>value 91</tag91>
</supertag>

The read in structure then is:
$VAR1 = {
          'supertag' => {
                        'tag10' => {
                                   'content' => 'value 2'
                                 },
                        'tag3' => {
                                  'content' => 'value 3'
                                },
                        'tag1' => {
                                  'content' => 'value 1'
                                },
                        'tag91' => {
                                   'content' => 'value 91'
                                 },
                        'tag90' => {
                                   'content' => 'value 90'
                                 },
                        'tag4' => {
                                  'content' => 'value 4'
                                }
                      }
        };
0

I found a problem with @mraq solution. I used it and suddenly got attributes in the "super tag" that I did not want and which were empty. The reason is that I did not have tag3 and tag4, so both became empty attributes of the super tag.

A small correction will do:

package MyXMLSimple;      # my XML::Simple subclass 
use base 'XML::Simple';

# Overriding the method here
sub sorted_keys
{
   my ($self, $name, $hashref) = @_;
   if ($name eq 'dsedib2b')   # only this tag I care about the order;
   {
      my @ordered = qw(
          tag1
          tag3
          tag4
          tag10
      );
      my %ordered_hash = map {$_ => 1} @ordered;

      #set ordered tags in front of others
      return grep {exists $hashref->{$_}} @ordered, grep {not $ordered_hash{$_}} $self->SUPER::sorted_keys($name, $hashref);
   }
   return $self->SUPER::sorted_keys($name, $hashref); # for the rest, I don't care!
}

So just replacing

return @ordered, grep {not $ordered_hash{$_}} $self->SUPER::sorted_keys($name, $hashref);

from

return grep {exists $hashref->{$_}} @ordered, grep {not $ordered_hash{$_}} $self->SUPER::sorted_keys($name, $hashref);

fixes a thing.

0
source

Source: https://habr.com/ru/post/1717278/


All Articles