File Coverage

blib/lib/XML/Simple/Sorted.pm
Criterion Covered Total %
statement 27 56 48.2
branch 0 14 0.0
condition n/a
subroutine 8 10 80.0
pod 2 2 100.0
total 37 82 45.1


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             XML::Simple::Sorted - Version of XML::Simple with enforced tag and attribute sort order.
4             This module was born out of the need to interface with some legacy systems that could not be
5             changed and that expected a certain tag order, otherwise they would crash and burn... just kidding ;-)
6              
7             =head1 SYNOPSIS
8              
9             use XML::Simple::Sorted;
10              
11             my $xml = XML::Simple::Sorted->new( [OPT] ) ;
12              
13             =cut
14              
15             package XML::Simple::Sorted;
16              
17 1     1   3609 use strict;
  1         1  
  1         26  
18 1     1   4 use warnings;
  1         1  
  1         18  
19              
20 1     1   674 use XML::Simple;
  1         6105  
  1         5  
21 1     1   49 use Carp;
  1         1  
  1         38  
22              
23             BEGIN
24             {
25 1     1   3 use Exporter();
  1         1  
  1         59  
26 1     1   1 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
27 1         1 $VERSION = '1.00';
28 1         6 @ISA = qw(XML::Simple);
29 1         1 @EXPORT = ();
30 1         2 %EXPORT_TAGS = ();
31 1         93 @EXPORT_OK = qw();
32             }
33             our @EXPORT_OK;
34              
35             =head1 CLASS METHODS
36              
37             =head2 B
38              
39             Creates a new instance of C.
40             Here, we simply override the constructor of L and check if the user has given
41             an *.ini file or hash containing the desired tag and attribute order.
42              
43             =over 4
44              
45             =item B
46              
47             This new option can either specify a hashref containing the desired tag and attribute sort
48             order or the path to an ini file (see L) containing the desired tag and
49             attribute sort order.
50             This method will croak() if one specifies a non-existing config file.
51              
52             =back
53              
54             =head3 Example
55              
56             my $xml = XML::Simple::Sorted->new(SortOrder => 'sort_config.ini');
57              
58             my $sort_hashref = { ... };
59             my $xml = XML::Simple::Sorted->new(SortOrder => $sort_hashref);
60              
61             =head3 Example sort_config.ini file
62              
63             [message]
64             tags = [ 'tradeid', 'leg' ]
65             attr = [ 'system', 'sender', 'receiver', 'timestamp' ]
66             [leg]
67             tags = [ 'legid', 'payment', 'book', 'product' ]
68             [payment]
69             tags = [ 'start', 'end', 'nominal', 'currency' ]
70             ...
71              
72             =head3 Example sort_hashref
73              
74             my $order = {
75             message => {
76             tags => [ 'tradeid', 'leg' ],
77             attr => [ 'system', 'sender', 'receiver', 'timestamp' ]
78             },
79             leg => {
80             tags => [ 'legid', 'payment', 'book', 'product' ]
81             },
82             payment => {
83             tags => [ 'start', 'end', 'nominal', 'currency' ]
84             },
85             };
86             Please note that the 'tags' und 'attr' parameters are semantically identical, i.e. one
87             could specify the attribute order also using the 'tags' parameter and vice versa.
88             Two parameters only serve to hopefully improve the readability of the *.ini file / hashref.
89              
90             =cut
91             sub new {
92 0     0 1   my ($class, %args) = @_;
93 0           my @params = ('tags', 'attr');
94 0           my $sort;
95 0 0         if (exists($args{SortOrder})) {
96 0 0         if (UNIVERSAL::isa($args{SortOrder}, 'HASH')) {
97 0           $sort = $args{SortOrder};
98             } else {
99 1     1   641 use Config::IniFiles;
  1         22791  
  1         26  
100 1     1   654 use Tie::File;
  1         12707  
  1         200  
101 0           my %ini;
102 0 0         croak($args{SortOrder}, ' not found') if (! -f $args{SortOrder});
103 0           tie %ini, 'Config::IniFiles', ( -file => $args{SortOrder} );
104 0           my %sorted;
105 0           for my $k (keys %ini) {
106 0           for my $p (@params) {
107 0 0         $sorted{$k}{$p} = eval($ini{$k}{$p}) if ($ini{$k}{$p});
108             }
109             }
110 0           $sort = \%sorted;
111             }
112 0           delete($args{SortOrder});
113             }
114 0           my $self = $class->SUPER::new(%args);
115 0           $self->{params} = \@params;
116 0           $self->{sort} = $sort;
117 0           bless($self, $class);
118 0           return $self;
119             } # new()
120              
121             =head2 B
122              
123             Override method C of L to perform the desired ordering of XML
124             tags and attributes.
125              
126             =cut
127             sub sorted_keys {
128 0     0 1   my ($self, $name, $hashref) = @_;
129 0           my @sorted_tags;
130 0           for my $p (@{$self->{params}}) {
  0            
131 0 0         if (my $val = $self->{sort}->{$name}{$p}) {
132 0           for my $k (@$val) {
133             # Only return tags and attributes that also exist in the given XML hashref to
134             # prevent the creation of empty attributes.
135 0 0         push(@sorted_tags, $k) if (exists($hashref->{$k}));
136             }
137             }
138             }
139 0 0         return @sorted_tags if (@sorted_tags);
140 0           return $self->SUPER::sorted_keys($name, $hashref);
141             } # sorted_keys()
142              
143             1;
144              
145             =head1 SEE ALSO
146              
147             L, L
148              
149             =head1 AUTHOR
150              
151             Sinisa Susnjar
152              
153             =head1 COPYRIGHT AND LICENSE
154              
155             Copyright 2012 Sinisa Susnjar
156              
157             This library is free software; you can redistribute it and/or modify it
158             under the same terms as Perl itself.
159              
160             =cut