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

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

Added gs-mkservlet script which creates a servlet with a valid site and interface.

File size: 6.2 KB
Line 
1package Greenstone::XML::Tidy;
2
3use strict;
4use warnings;
5use utf8;
6use XML::Parser;
7use POSIX 'isatty';
8use Hash::Ordered;
9use base 'Exporter';
10
11our $VERSION = 1.00;
12our @EXPORT = ( 'read_xml', 'write_xml' );
13
14# Reads the servlets partial XML file using XML::Parser,
15# Then converts the obtained data structure to a more readable one
16# Example conversion:
17=xml
18<servlet>
19 <servlet-name>library</servlet-name>
20 <description attribute="example">The standard gsdl3 library program</description>
21 <servlet-class>org.greenstone.gsdl3.LibraryServlet</servlet-class>
22 <init-param>
23 <param-name>library_name</param-name>
24 <param-value>library</param-value>
25 </init-param>
26 <init-param>
27 <param-name>site_name</param-name>
28 <param-value>localsite</param-value>
29 </init-param>
30</servlet>
31=cut
32=data_structure
33{
34 'servlet' => {
35 'servlet-class' => 'org.greenstone.gsdl3.LibraryServlet',
36 'servlet-name' => 'library',
37 'description' => {
38 '.value' => 'The standard gsdl3 library program',
39 '.attr' => {
40 'attribute' => 'example'
41 }
42 },
43 'init-param' => [
44 {
45 'param-value' => 'library',
46 'param-name' => 'library_name'
47 },
48 {
49 'param-name' => 'site_name',
50 'param-value' => 'localsite'
51 }
52 ]
53 }
54}
55=cut
56sub read_xml {
57 my $file = shift;
58 my $xml;
59 if ($file eq '-') {
60 if (isatty *STDIN) {
61 print STDERR "Reading XML from STDIN. Press ^D to end\n";
62 }
63 local $/ = undef;
64 $xml = '<__root__>' . <STDIN> . '</__root__>';
65 } else {
66 $xml = '<!DOCTYPE doc [<!ENTITY real_doc SYSTEM "' . $file . '">]>
67 <__root__>&real_doc;</__root__>';
68 }
69 # Parse the data using XML::Parser
70 my $data = new XML::Parser (Style => 'Tree')->parse ($xml);
71
72 sub tidy {
73 my $hash = Hash::Ordered->new;
74 # If the element has attributes, add them to the hash
75 my $attr = shift;
76 if (scalar keys %$attr > 0) {
77 my $attr_ordered = Hash::Ordered->new;
78 for my $key (keys %$attr) {
79 $attr_ordered->set ($key => $attr->{$key});
80 }
81 $hash->set ('.attr' => $attr_ordered);
82 }
83 # Read any child elements or text value
84 while (@_) {
85 my $element = shift;
86 my $value = shift;
87 if ($element eq 0) {
88 unless ($value =~ /^\s*$/) {
89 my $existing = $hash->get ('.value');
90 defined $existing and ($value .= $existing);
91 $hash->set ('.value' => $value);
92 }
93 } else {
94 # If there is more than one of a single tupe of child element,
95 # That child element must become an array
96 if ($hash->exists ($element)) {
97 my $existing = $hash->get ($element);
98 unless (ref $existing eq 'ARRAY') {
99 $hash->set ($element => [ $existing ]);
100 }
101 push @{$hash->get ($element)}, tidy (@{$value});
102 } else {
103 $hash->set ($element => tidy (@{$value}));
104 }
105 }
106 }
107 # If the element only has a value, it can become a scalar
108 if (scalar $hash->keys == 1 and $hash->exists ('.value')) {
109 return $hash->get ('.value');
110 }
111 return $hash;
112 }
113 return tidy (@{@$data[1]});
114}
115
116# Writes a data structure to an XML file
117sub write_xml {
118 my ($hash, $file, $mode) = @_;
119 $mode = '>' unless defined $mode;
120 my $FH;
121 if ($file ne '-') {
122 unless (open $FH, $mode . ':utf8', $file) {
123 print STDERR "Failed to open output file '$file': $!\n";
124 return 0;
125 }
126 select $FH;
127 }
128 sub escape {
129 my @r;
130 for (@_) {
131 my $str = ''. $_;
132 $str =~ s/(['\\])/\\$1'/g;
133 push @r, $str;
134 }
135 return @r;
136 }
137 sub open_tag {
138 my ($indent, $tag, $attr) = @_;
139 print $indent, "<", $tag;
140 if (defined $attr) {
141 my $iter = $attr->iterator;
142 while (my ($key, $value) = $iter->()) {
143 print " ", $key, '="', escape $value, '"';
144 }
145 }
146 print ">";
147 }
148 sub write_element {
149 my ($indent, $hash) = @_;
150 for my $key ($hash->keys) {
151 $key eq '.attr' && next;
152 my $val = $hash->get ($key);
153 $key eq '.value' && do {
154 print $val, "\n";
155 next;
156 };
157 for (ref $val) {
158 /^ARRAY$/ && do {
159 for my $element (@$val) {
160 open_tag ($indent, $key, $element->get ('.attr'));
161 for (ref $element) {
162 /^Hash::Ordered$/ && do {
163 print "\n";
164 write_element (" $indent", $element);
165 print $indent, "</", $key, ">\n";
166 last;
167 };
168 print $element, "</", $key, ">\n";
169 }
170 }
171 last;
172 };
173 /^Hash::Ordered$/ && do {
174 open_tag ($indent, $key, $val->get ('.attr'));
175 # If the element only has a value with attributes,
176 # it can be formatted on one line
177 if (scalar $val->keys == 2 and $val->exists ('.value')) {
178 print $val->get ('.value'), "</", $key, ">\n";
179 } else {
180 print "\n";
181 write_element (" $indent", $val);
182 print $indent, "</", $key, ">\n";
183 }
184 last;
185 };
186 open_tag ($indent, $key);
187 print $val;
188 print "</", $key, ">\n";
189 }
190 }
191 }
192 write_element ("", $hash);
193 if ($file ne '-') {
194 select STDOUT;
195 close $FH;
196 }
197 return 1;
198}
199
2001;
Note: See TracBrowser for help on using the repository browser.