File Coverage

inc/XML/NamespaceSupport.pm
Criterion Covered Total %
statement 68 156 43.5
branch 10 62 16.1
condition 0 27 0.0
subroutine 17 28 60.7
pod 14 15 93.3
total 109 288 37.8


line stmt bran cond sub pod time code
1             #line 1
2              
3             ###
4             # XML::NamespaceSupport - a simple generic namespace processor
5             # Robin Berjon
6             ###
7              
8 1     1   63894 package XML::NamespaceSupport;
  1         3  
  1         204  
9 1     1   20 use strict;
  1         4  
  1         183  
10 1     1   9 use constant FATALS => 0; # root object
  1         3  
  1         51  
11 1     1   7 use constant NSMAP => 1;
  1         3  
  1         46  
12 1     1   6 use constant UNKNOWN_PREF => 2;
  1         2  
  1         45  
13 1     1   6 use constant AUTO_PREFIX => 3;
  1         2  
  1         44  
14 1     1   7 use constant XMLNS_11 => 4;
  1         2  
  1         63  
15 1     1   5 use constant DEFAULT => 0; # maps
  1         4  
  1         62  
16 1     1   5 use constant PREFIX_MAP => 1;
  1         4  
  1         50  
17             use constant DECLARATIONS => 2;
18 1     1   5  
  1         4  
  1         903  
19             use vars qw($VERSION $NS_XMLNS $NS_XML);
20             $VERSION = '1.09';
21             $NS_XMLNS = 'http://www.w3.org/2000/xmlns/';
22             $NS_XML = 'http://www.w3.org/XML/1998/namespace';
23              
24              
25             # add the ns stuff that baud wants based on Java's xml-writer
26              
27              
28             #-------------------------------------------------------------------#
29             # constructor
30             #-------------------------------------------------------------------#
31 1 50   1 1 73 sub new {
32 1         3 my $class = ref($_[0]) ? ref(shift) : shift;
33 1         6 my $options = shift;
34             my $self = [
35             1, # FATALS
36             [[ # NSMAP
37             undef, # DEFAULT
38             { xml => $NS_XML }, # PREFIX_MAP
39             undef, # DECLARATIONS
40             ]],
41             'aaa', # UNKNOWN_PREF
42             0, # AUTO_PREFIX
43             1, # XML_11
44 1 50       6 ];
45 1 50       5 $self->[NSMAP]->[0]->[PREFIX_MAP]->{xmlns} = $NS_XMLNS if $options->{xmlns};
46 1 50       4 $self->[FATALS] = $options->{fatal_errors} if defined $options->{fatal_errors};
47 1 50       5 $self->[AUTO_PREFIX] = $options->{auto_prefix} if defined $options->{auto_prefix};
48 1         4 $self->[XMLNS_11] = $options->{xmlns_11} if defined $options->{xmlns_11};
49             return bless $self, $class;
50             }
51             #-------------------------------------------------------------------#
52              
53             #-------------------------------------------------------------------#
54             # reset() - return to the original state (for reuse)
55             #-------------------------------------------------------------------#
56 0     0 1 0 sub reset {
57 0         0 my $self = shift;
  0         0  
58             $#{$self->[NSMAP]} = 0;
59             }
60             #-------------------------------------------------------------------#
61              
62             #-------------------------------------------------------------------#
63             # push_context() - add a new empty context to the stack
64             #-------------------------------------------------------------------#
65 7     7 1 31 sub push_context {
66 7         25 my $self = shift;
  7         47  
67             push @{$self->[NSMAP]}, [
68 7         8 $self->[NSMAP]->[-1]->[DEFAULT],
69             { %{$self->[NSMAP]->[-1]->[PREFIX_MAP]} },
70             [],
71             ];
72             }
73             #-------------------------------------------------------------------#
74              
75             #-------------------------------------------------------------------#
76             # pop_context() - remove the topmost context fromt the stack
77             #-------------------------------------------------------------------#
78 7     7 1 49 sub pop_context {
79 7 50       11 my $self = shift;
  7         23  
80 7         9 die 'Trying to pop context without push context' unless @{$self->[NSMAP]} > 1;
  7         19  
81             pop @{$self->[NSMAP]};
82             }
83             #-------------------------------------------------------------------#
84              
85             #-------------------------------------------------------------------#
86             # declare_prefix() - declare a prefix in the current scope
87             #-------------------------------------------------------------------#
88 0     0 1 0 sub declare_prefix {
89 0         0 my $self = shift;
90 0         0 my $prefix = shift;
91             my $value = shift;
92 0 0 0     0  
93             warn <<' EOWARN' unless defined $prefix or $self->[AUTO_PREFIX];
94             Prefix was undefined.
95             If you wish to set the default namespace, use the empty string ''.
96             If you wish to autogenerate prefixes, set the auto_prefix option
97             to a true value.
98             EOWARN
99 1     1   9  
  1         2  
  1         605  
100 0 0 0     0 no warnings 'uninitialized';
    0 0        
    0 0        
101 0         0 if ($prefix eq 'xml' and $value ne $NS_XML) {
102             die "The xml prefix can only be bound to the $NS_XML namespace."
103             }
104 0         0 elsif ($value eq $NS_XML and $prefix ne 'xml') {
105             die "the $NS_XML namespace can only be bound to the xml prefix.";
106             }
107 0         0 elsif ($value eq $NS_XML and $prefix eq 'xml') {
108             return 1;
109 0 0       0 }
110 1     1   10 return 0 if index(lc($prefix), 'xml') == 0;
  1         2  
  1         10641  
111             use warnings 'uninitialized';
112 0 0 0     0  
113 0         0 if (defined $prefix and $prefix eq '') {
114             $self->[NSMAP]->[-1]->[DEFAULT] = $value;
115             }
116 0 0 0     0 else {
117 0 0 0     0 die "Cannot undeclare prefix $prefix" if $value eq '' and not $self->[XMLNS_11];
    0 0        
118 0         0 if (not defined $prefix and $self->[AUTO_PREFIX]) {
119 0         0 while (1) {
120 0 0       0 $prefix = $self->[UNKNOWN_PREF]++;
121             last if not exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
122             }
123             }
124 0         0 elsif (not defined $prefix and not $self->[AUTO_PREFIX]) {
125             return 0;
126 0         0 }
127             $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix} = $value;
128 0         0 }
  0         0  
129 0         0 push @{$self->[NSMAP]->[-1]->[DECLARATIONS]}, $prefix;
130             return 1;
131             }
132             #-------------------------------------------------------------------#
133              
134             #-------------------------------------------------------------------#
135             # declare_prefixes() - declare several prefixes in the current scope
136             #-------------------------------------------------------------------#
137 0     0 1 0 sub declare_prefixes {
138 0         0 my $self = shift;
139 0         0 my %prefixes = @_;
140 0         0 while (my ($k,$v) = each %prefixes) {
141             $self->declare_prefix($k,$v);
142             }
143             }
144             #-------------------------------------------------------------------#
145              
146             #-------------------------------------------------------------------#
147             # undeclare_prefix
148             #-------------------------------------------------------------------#
149 0     0 1 0 sub undeclare_prefix {
150 0         0 my $self = shift;
151 0 0 0     0 my $prefix = shift;
152 0 0       0 return unless not defined $prefix or $prefix eq '';
153             return unless exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
154 0         0  
  0         0  
  0         0  
155 0 0       0 my ( $tfix ) = grep { $_ eq $prefix } @{$self->[NSMAP]->[-1]->[DECLARATIONS]};
156 0         0 if ( not defined $tfix ) {
157             die "prefix $prefix not declared in this context\n";
158             }
159 0         0  
  0         0  
  0         0  
  0         0  
160 0         0 @{$self->[NSMAP]->[-1]->[DECLARATIONS]} = grep { $_ ne $prefix } @{$self->[NSMAP]->[-1]->[DECLARATIONS]};
161             delete $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
162             }
163             #-------------------------------------------------------------------#
164              
165             #-------------------------------------------------------------------#
166             # get_prefix() - get a (random) prefix for a given URI
167             #-------------------------------------------------------------------#
168 0     0 1 0 sub get_prefix {
169 0         0 my $self = shift;
170             my $uri = shift;
171              
172             # we have to iterate over the whole hash here because if we don't
173 0         0 # the iterator isn't reset and the next pass will fail
174 0         0 my $pref;
  0         0  
175 0 0       0 while (my ($k, $v) = each %{$self->[NSMAP]->[-1]->[PREFIX_MAP]}) {
176             $pref = $k if $v eq $uri;
177 0         0 }
178             return $pref;
179             }
180             #-------------------------------------------------------------------#
181              
182             #-------------------------------------------------------------------#
183             # get_prefixes() - get all the prefixes for a given URI
184             #-------------------------------------------------------------------#
185 0     0 1 0 sub get_prefixes {
186 0         0 my $self = shift;
187             my $uri = shift;
188 0 0       0  
  0         0  
189 0         0 return keys %{$self->[NSMAP]->[-1]->[PREFIX_MAP]} unless defined $uri;
  0         0  
  0         0  
190             return grep { $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$_} eq $uri } keys %{$self->[NSMAP]->[-1]->[PREFIX_MAP]};
191             }
192             #-------------------------------------------------------------------#
193              
194             #-------------------------------------------------------------------#
195             # get_declared_prefixes() - get all prefixes declared in the last context
196             #-------------------------------------------------------------------#
197 0     0 1 0 sub get_declared_prefixes {
  0         0  
198             return @{$_[0]->[NSMAP]->[-1]->[DECLARATIONS]};
199             }
200             #-------------------------------------------------------------------#
201              
202             #-------------------------------------------------------------------#
203             # get_uri() - get an URI given a prefix
204             #-------------------------------------------------------------------#
205 0     0 1 0 sub get_uri {
206 0         0 my $self = shift;
207             my $prefix = shift;
208 0 0       0  
209             warn "Prefix must not be undef in get_uri(). The emtpy prefix must be ''" unless defined $prefix;
210 0 0       0  
211 0 0       0 return $self->[NSMAP]->[-1]->[DEFAULT] if $prefix eq '';
212 0         0 return $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix} if exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
213             return undef;
214             }
215             #-------------------------------------------------------------------#
216              
217             #-------------------------------------------------------------------#
218             # process_name() - provide details on a name
219             #-------------------------------------------------------------------#
220 0     0 1 0 sub process_name {
221 0         0 my $self = shift;
222 0         0 my $qname = shift;
223             my $aflag = shift;
224 0 0       0  
225 0         0 if ($self->[FATALS]) {
226             return( ($self->_get_ns_details($qname, $aflag))[0,2], $qname );
227             }
228 0         0 else {
  0         0  
229             eval { return( ($self->_get_ns_details($qname, $aflag))[0,2], $qname ); }
230             }
231             }
232             #-------------------------------------------------------------------#
233              
234             #-------------------------------------------------------------------#
235             # process_element_name() - provide details on a element's name
236             #-------------------------------------------------------------------#
237 7     7 1 52 sub process_element_name {
238 7         12 my $self = shift;
239             my $qname = shift;
240 7 50       22  
241 7         19 if ($self->[FATALS]) {
242             return $self->_get_ns_details($qname, 0);
243             }
244 0         0 else {
  0         0  
245             eval { return $self->_get_ns_details($qname, 0); }
246             }
247             }
248             #-------------------------------------------------------------------#
249              
250              
251             #-------------------------------------------------------------------#
252             # process_attribute_name() - provide details on a attribute's name
253             #-------------------------------------------------------------------#
254 0     0 1 0 sub process_attribute_name {
255 0         0 my $self = shift;
256             my $qname = shift;
257 0 0       0  
258 0         0 if ($self->[FATALS]) {
259             return $self->_get_ns_details($qname, 1);
260             }
261 0         0 else {
  0         0  
262             eval { return $self->_get_ns_details($qname, 1); }
263             }
264             }
265             #-------------------------------------------------------------------#
266              
267              
268             #-------------------------------------------------------------------#
269             # ($ns, $prefix, $lname) = $self->_get_ns_details($qname, $f_attr)
270             # returns ns, prefix, and lname for a given attribute name
271             # >> the $f_attr flag, if set to one, will work for an attribute
272             #-------------------------------------------------------------------#
273 7     7   9 sub _get_ns_details {
274 7         13 my $self = shift;
275 7         9 my $qname = shift;
276             my $aflag = shift;
277 7         9  
278 7 50       113 my ($ns, $prefix, $lname);
279             (my ($tmp_prefix, $tmp_lname) = split /:/, $qname, 3)
280             < 3 or die "Invalid QName: $qname";
281              
282 7         14 # no prefix
283 7 50       17 my $cur_map = $self->[NSMAP]->[-1];
284 7         9 if (not defined($tmp_lname)) {
285 7         11 $prefix = undef;
286             $lname = $qname;
287 7 50       15 # attr don't have a default namespace
288             $ns = ($aflag) ? undef : $cur_map->[DEFAULT];
289             }
290              
291             # prefix
292 0 0       0 else {
293 0         0 if (exists $cur_map->[PREFIX_MAP]->{$tmp_prefix}) {
294 0         0 $prefix = $tmp_prefix;
295 0         0 $lname = $tmp_lname;
296             $ns = $cur_map->[PREFIX_MAP]->{$prefix}
297             }
298 0         0 else { # no ns -> lname == name, all rest undef
299             die "Undeclared prefix: $tmp_prefix";
300             }
301             }
302 7         38  
303             return ($ns, $prefix, $lname);
304             }
305             #-------------------------------------------------------------------#
306              
307             #-------------------------------------------------------------------#
308             # parse_jclark_notation() - parse the Clarkian notation
309             #-------------------------------------------------------------------#
310 0     0 0   sub parse_jclark_notation {
311 0           shift;
312 0           my $jc = shift;
313 0           $jc =~ m/^\{(.*)\}([^}]+)$/;
314             return $1, $2;
315             }
316             #-------------------------------------------------------------------#
317              
318              
319             #-------------------------------------------------------------------#
320             # Java names mapping
321             #-------------------------------------------------------------------#
322             *XML::NamespaceSupport::pushContext = \&push_context;
323             *XML::NamespaceSupport::popContext = \&pop_context;
324             *XML::NamespaceSupport::declarePrefix = \&declare_prefix;
325             *XML::NamespaceSupport::declarePrefixes = \&declare_prefixes;
326             *XML::NamespaceSupport::getPrefix = \&get_prefix;
327             *XML::NamespaceSupport::getPrefixes = \&get_prefixes;
328             *XML::NamespaceSupport::getDeclaredPrefixes = \&get_declared_prefixes;
329             *XML::NamespaceSupport::getURI = \&get_uri;
330             *XML::NamespaceSupport::processName = \&process_name;
331             *XML::NamespaceSupport::processElementName = \&process_element_name;
332             *XML::NamespaceSupport::processAttributeName = \&process_attribute_name;
333             *XML::NamespaceSupport::parseJClarkNotation = \&parse_jclark_notation;
334             *XML::NamespaceSupport::undeclarePrefix = \&undeclare_prefix;
335             #-------------------------------------------------------------------#
336              
337              
338             1;
339             #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
340             #`,`, Documentation `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
341             #```````````````````````````````````````````````````````````````````#
342              
343             #line 582
344