File Coverage

blib/lib/DJabberd/XMLElement.pm
Criterion Covered Total %
statement 9 124 7.2
branch 0 42 0.0
condition 0 20 0.0
subroutine 3 22 13.6
pod 0 18 0.0
total 12 226 5.3


line stmt bran cond sub pod time code
1             package DJabberd::XMLElement;
2 1     1   7 use strict;
  1         1  
  1         51  
3             use fields (
4 1         6 'ns', # namespace name
5             'element', # element name
6             'attrs', # hashref of {namespace}attr => value. NOTE: used by Stanza.pm directly.
7             'children', # arrayref of child elements of this same type, or scalars for text nodes
8             'raw', # in some cases we have the raw xml and we have to create a fake XMLElement object
9             # business logic is that as_xml returns the raw stuff if it is exists, children has to be empty -- sky
10             'prefix', # namepace prefix in use in this element
11 1     1   1004 );
  1         1859  
12              
13 1     1   739 use DJabberd::Util;
  1         3  
  1         1658  
14              
15             sub new {
16 0     0 0   my $class = shift;
17 0 0         if (ref $_[0]) {
18             # the down-classer that subclasses can inherit
19 0           return bless $_[0], $class;
20             }
21              
22             # constructing a new XMLElement:
23 0           my DJabberd::XMLElement $self = fields::new($class);
24 0           ($self->{ns},
25             $self->{element},
26             $self->{attrs},
27             $self->{children},
28             $self->{raw},
29             $self->{prefix}) = @_;
30             #my ($ns, $elementname, $attrs, $children) = @_;
31             #Carp::confess("children isn't an arrayref, is: $children") unless ref $children eq "ARRAY";
32              
33             #DJabberd->track_new_obj($self);
34 0           return $self;
35             }
36              
37             #sub DESTROY {
38             # my $self = shift;
39             # DJabberd->track_destroyed_obj($self);
40             #}
41              
42             sub push_child {
43 0     0 0   my DJabberd::XMLElement $self = $_[0];
44 0           push @{$self->{children}}, $_[1]; # $node
  0            
45             }
46              
47             sub set_raw {
48 0     0 0   my DJabberd::XMLElement $self = shift;
49 0           $self->{raw} = shift;
50 0           $self->{children} = [];
51             }
52              
53             sub children_elements {
54 0     0 0   my DJabberd::XMLElement $self = $_[0];
55 0           return grep { ref $_ } @{ $self->{children} };
  0            
  0            
56             }
57              
58             sub remove_child {
59 0     0 0   my DJabberd::XMLElement $self = $_[0];
60 0           @{$self->{children}} = grep { $_ != $_[1] } @{$self->{children}};
  0            
  0            
  0            
61             }
62              
63             sub children {
64 0     0 0   my DJabberd::XMLElement $self = $_[0];
65 0           return @{ $self->{children} };
  0            
66             }
67              
68             sub first_child {
69 0     0 0   my DJabberd::XMLElement $self = $_[0];
70 0 0         return @{ $self->{children} } ? $self->{children}[0] : undef;
  0            
71             }
72              
73             sub first_element {
74 0     0 0   my DJabberd::XMLElement $self = $_[0];
75 0           foreach my $c (@{ $self->{children} }) {
  0            
76 0 0         return $c if ref $c;
77             }
78 0           return undef;
79             }
80              
81             sub inner_ns {
82 0     0 0   return $_[0]->{attrs}{'{}xmlns'};
83             }
84              
85             sub attr {
86 0     0 0   return $_[0]->{attrs}{$_[1]};
87             }
88              
89             sub set_attr {
90 0     0 0   $_[0]->{attrs}{$_[1]} = $_[2];
91             }
92              
93             sub attrs {
94 0     0 0   return $_[0]->{attrs};
95             }
96              
97             sub element {
98 0     0 0   my DJabberd::XMLElement $self = $_[0];
99 0 0         return ($self->{ns}, $self->{element}) if wantarray;
100 0           return "{$self->{ns}}$self->{element}";
101             }
102              
103             sub element_name {
104 0     0 0   my DJabberd::XMLElement $self = $_[0];
105 0           return $self->{element};
106             }
107              
108             sub namespace {
109 0     0 0   my DJabberd::XMLElement $self = $_[0];
110 0           return $self->{ns};
111             }
112              
113             sub _resolve_prefix {
114 0     0     my ($self, $nsmap, $def_ns, $uri, $attr) = @_;
115 0 0 0       if ($def_ns && $def_ns eq $uri) {
    0          
    0          
116 0           return '';
117             } elsif ($uri eq '') {
118 0           return '';
119             } elsif ($nsmap->{$uri}) {
120 0           $nsmap->{$uri} . ':';
121             } else {
122 0   0       $nsmap->{___prefix_count} ||= 0;
123 0           my $count = $nsmap->{___prefix_count}++;
124 0           my $prefix = "nsp$count";
125 0           $nsmap->{$uri} = $prefix;
126 0           $nsmap->{$prefix} = $uri;
127 0           $attr->{'{http://www.w3.org/2000/xmlns}' . $prefix} = $uri;
128 0           return $prefix . ':';
129             }
130             }
131              
132             sub as_xml {
133 0     0 0   my DJabberd::XMLElement $self = shift;
134              
135 0   0       my $nsmap = shift || { }; # localname -> uri, uri -> localname
136              
137             # tons of places call as_xml, but nobody seems to care about
138             # the default namespace. It seems, however, that it is a common
139             # usage for "jabber:client" to be this default ns.
140 0   0       my $def_ns = shift || 'jabber:client';
141              
142 0           my ($ns, $el) = ($self->{ns}, $self->{element});
143 0 0         if ($self->{prefix}) {
144 0           $nsmap->{ $self->{prefix} } = $ns;
145 0           $nsmap->{$ns} = $self->{prefix};
146             }
147              
148 0           my $attr_str = "";
149 0           my $attr = $self->{attrs};
150              
151 0           $nsmap->{xmlns} = 'http://www.w3.org/2000/xmlns';
152 0           $nsmap->{'http://www.w3.org/2000/xmlns'} = 'xmlns';
153              
154             # let's feed the nsmap...
155 0           foreach my $k (keys %$attr) {
156 0 0         if ($k =~ /^\{(.*)\}(.+)$/) {
    0          
157 0           my ($nsuri, $name) = ($1, $2);
158 0 0 0       if ($nsuri eq 'xmlns' ||
    0          
159             $nsuri eq 'http://www.w3.org/2000/xmlns/') {
160 0           $nsmap->{$name} = $attr->{$k};
161 0           $nsmap->{ $attr->{$k} } = $name;
162             } elsif ($k eq '{}xmlns') {
163 0           $def_ns = $attr->{$k};
164             }
165             } elsif ($k eq 'xmlns') {
166 0           $def_ns = $attr->{$k};
167             }
168             }
169              
170 0           my $nsprefix = $self->_resolve_prefix($nsmap, $def_ns, $ns, $attr);
171              
172 0           foreach my $k (keys %$attr) {
173 0           my $value = $attr->{$k};
174 0 0         if ($k =~ /^\{(.*)\}(.+)$/) {
175 0           my ($nsuri, $name) = ($1, $2);
176 0 0 0       if ($nsuri eq 'xmlns' ||
    0          
177             $nsuri eq 'http://www.w3.org/2000/xmlns/') {
178 0           $attr_str .= " xmlns:$name='" . DJabberd::Util::exml($value)
179             . "'";
180             } elsif ($k eq '{}xmlns') {
181 0           $attr_str .= " xmlns='" . DJabberd::Util::exml($value) . "'";
182             } else {
183 0           my $nsprefix = $self->_resolve_prefix($nsmap, $def_ns, $nsuri);
184 0           $attr_str .= " $nsprefix$name='" . DJabberd::Util::exml($value)
185             ."'";
186             }
187             } else {
188 0           $attr_str .= " $k='" . DJabberd::Util::exml($value) . "'";
189             }
190             }
191              
192 0           my $innards = $self->innards_as_xml($nsmap, $def_ns);
193 0 0 0       $innards = "..." if $DJabberd::ASXML_NO_INNARDS && $innards;
194              
195 0 0         my $result = length $innards ?
196             "<$nsprefix$el$attr_str>$innards" :
197             "<$nsprefix$el$attr_str/>";
198              
199 0           return $result;
200              
201             }
202              
203             sub innards_as_xml {
204 0     0 0   my DJabberd::XMLElement $self = shift;
205 0   0       my $nsmap = shift || {};
206 0           my $def_ns = shift;
207              
208 0 0         if ($self->{raw}) {
209 0           return $self->{raw};
210             }
211              
212 0           my $ret = "";
213 0           foreach my $c (@{ $self->{children} }) {
  0            
214 0 0         if (ref $c) {
215 0           $ret .= $c->as_xml($nsmap, $def_ns);
216             } else {
217 0 0         if ($DJabberd::ASXML_NO_TEXT) {
218 0           $ret .= "...";
219             } else {
220 0           $ret .= DJabberd::Util::exml($c);
221             }
222             }
223             }
224 0           return $ret;
225             }
226              
227             sub clone {
228 0     0 0   my $self = shift;
229 0           my $clone = fields::new(ref($self));
230 0           $clone->{ns} = $self->{ns};
231 0           $clone->{element} = $self->{element};
232 0           $clone->{attrs} = { %{ $self->{attrs} } };
  0            
233 0 0         $clone->{children} = [ map { ref($_) ? $_->clone : $_ } @{ $self->{children} } ];
  0            
  0            
234 0           $clone->{raw} = $self->{raw};
235 0           $clone->{prefix} = $self->{prefix};
236 0           return $clone;
237             }
238              
239             1;