source: main/trunk/package-kits/scripts/perllib/XML/Tidy.pm@ 29673

Last change on this file since 29673 was 29673, checked in by Jeremy Symon, 9 years ago

Moved servlet XML handling code to a module

File size: 4.9 KB
Line 
1package XML::Tidy;
2
3use strict;
4use warnings;
5use utf8;
6use XML::Parser;
7use base 'Exporter';
8
9our $VERSION = 1.00;
10our @EXPORT = ( 'read_xml', 'write_xml' );
11
12# Reads the servlets partial XML file using XML::Parser,
13# Then converts the obtained data structure to a more readable one
14# Example conversion:
15=xml
16<servlet>
17 <servlet-name>library</servlet-name>
18 <description attribute="example">The standard gsdl3 library program</description>
19 <servlet-class>org.greenstone.gsdl3.LibraryServlet</servlet-class>
20 <init-param>
21 <param-name>library_name</param-name>
22 <param-value>library</param-value>
23 </init-param>
24 <init-param>
25 <param-name>site_name</param-name>
26 <param-value>localsite</param-value>
27 </init-param>
28</servlet>
29=cut
30=data_structure
31{
32 'servlet' => {
33 'servlet-class' => 'org.greenstone.gsdl3.LibraryServlet',
34 'servlet-name' => 'library',
35 'description' => {
36 '.value' => 'The standard gsdl3 library program',
37 '.attr' => {
38 'attribute' => 'example'
39 }
40 },
41 'init-param' => [
42 {
43 'param-value' => 'library',
44 'param-name' => 'library_name'
45 },
46 {
47 'param-name' => 'site_name',
48 'param-value' => 'localsite'
49 }
50 ]
51 }
52}
53=cut
54sub read_xml {
55 my $FH = shift;
56 local $/ = undef;
57 my $xml = <$FH>;
58 # The xml needs a root element, so we wrap it in one
59 $xml='<__root__>' . $xml . '</__root__>';
60 # Parse the data using XML::Parser
61 my $data = new XML::Parser (Style => 'Tree')->parse ($xml);
62
63 sub tidy {
64 my %hash;
65 # If the element has attributes, add them to the hash
66 my $attr = shift;
67 if (scalar keys %$attr > 0) {
68 $hash{'.attr'} = $attr;
69 }
70 # Read any child elements or text value
71 while (@_) {
72 my $element = shift;
73 my $value = shift;
74 if ($element eq 0) {
75 $value =~ /^\s*$/ || ($hash{'.value'} .= $value);
76 } else {
77 # If there is more than one of a single tupe of child element,
78 # That child element must become an array
79 if (defined $hash{$element}) {
80 unless (ref $hash{$element} eq 'ARRAY') {
81 $hash{$element} = [ $hash{$element} ];
82 }
83 push @{$hash{$element}}, tidy (@{$value});
84 } else {
85 $hash{$element} = tidy (@{$value});
86 }
87 }
88 }
89 # If the element only has a value, it can become a scalar
90 if (scalar keys %hash == 1 and defined $hash{'.value'}) {
91 return $hash{'.value'};
92 }
93 return \%hash;
94 }
95 return tidy (@{@$data[1]});
96}
97
98# Writes a data structure to an XML file
99sub write_xml {
100 my ($hash, $FH) = @_;
101 select $FH;
102 sub open_tag {
103 my ($indent, $tag, $attr) = @_;
104 print $indent, "<", $tag;
105 if (defined $attr) {
106 for my $key (sort keys %$attr) {
107 print " ", $key, '="', $attr->{$key}, '"';
108 }
109 }
110 print ">";
111 }
112 sub write_element {
113 my ($indent, $hash) = @_;
114 for my $key (sort keys %$hash) {
115 $key eq '.attr' && next;
116 my $val = $hash->{$key};
117 $key eq '.value' && do {
118 print $val, "\n";
119 next;
120 };
121 for (ref $val) {
122 /^ARRAY$/ && do {
123 for my $element (@$val) {
124 open_tag ($indent, $key, $element->{'.attr'});
125 for (ref $element) {
126 /^HASH$/ && do {
127 print "\n";
128 write_element (" $indent", $element);
129 print $indent, "</", $key, ">\n";
130 last;
131 };
132 print $element, "</", $key, ">\n";
133 }
134 }
135 last;
136 };
137 /^HASH$/ && do {
138 open_tag ($indent, $key, $val->{'.attr'});
139 # If the element only has a value with attributes,
140 # it can be formatted on one line
141 if (scalar keys %$val == 2 and defined $val->{'.value'}) {
142 print $val->{'.value'}, "</", $key, ">\n";
143 } else {
144 print "\n";
145 write_element (" $indent", $val);
146 print $indent, "</", $key, ">\n";
147 }
148 last;
149 };
150 open_tag ($indent, $key);
151 print $val;
152 print "</", $key, ">\n";
153 }
154 }
155 }
156 write_element ("", $hash);
157 select STDOUT;
158}
Note: See TracBrowser for help on using the repository browser.