ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-XMPP2/lib/Net/XMPP2/Node.pm
Revision: 1.8
Committed: Wed Jul 25 13:53:33 2007 UTC (19 years, 2 months ago) by elmex
Branch: MAIN
Changes since 1.7: +1 -10 lines
Log Message:
implemented OOB and fixed bugs in Disco and further developed in band registration.

File Contents

# User Rev Content
1 elmex 1.1 package Net::XMPP2::Node;
2     use strict;
3     use Net::XMPP2::Namespaces qw/xmpp_ns/;
4    
5     use constant {
6     NS => 0,
7     NAME => 1,
8     ATTRS => 2,
9     TEXT => 3,
10     NODES => 4,
11     PARSER => 5,
12 elmex 1.6 RAW => 6
13     };
14    
15     use constant {
16     NNODE => 0,
17     NTEXT => 1,
18     NRAW => 2,
19 elmex 1.1 };
20    
21     =head1 NAME
22    
23 elmex 1.5 Net::XMPP2::Node - XML node tree helper for the parser.
24 elmex 1.1
25     =head1 SYNOPSIS
26    
27     use Net::XMPP2::Node;
28     ...
29    
30 elmex 1.4 =head1 DESCRIPTION
31    
32     This class represens a XML node. L<Net::XMPP2> should usually not
33     require messing with the parse tree, but sometimes it is neccessary.
34    
35     If you experience any need for messing with these and feel L<Net::XMPP2> should
36     rather take care of it drop me a mail, feature request or most preferably a patch!
37    
38     Every L<Net::XMPP2::Node> has a namespace, attributes, text and child nodes.
39    
40     You can access these with the following methods:
41    
42 elmex 1.1 =head1 METHODS
43    
44 elmex 1.4 =over 4
45    
46     =item B<new ($ns, $el, $attrs, $parser)>
47 elmex 1.1
48     Creates a new Net::XMPP2::Node object with the node tag name C<$el> in the
49     namespace URI C<$ns> and the attributes C<$attrs>. The C<$parser> must be
50     the instance of C<Net::XMPP2::Parser> which generated this node.
51    
52     =cut
53    
54     sub new {
55     my $this = shift;
56     my $class = ref($this) || $this;
57     my $self = [];
58     $self->[0] = $_[0];
59     $self->[1] = $_[1];
60     $self->[2] = $_[2];
61     $self->[5] = $_[3];
62 elmex 1.6 $self->[6] = '';
63 elmex 1.1 bless $self, $class;
64     return $self
65     }
66    
67 elmex 1.4 =item B<name>
68 elmex 1.1
69     The tag name of this node.
70    
71     =cut
72    
73     sub name {
74     $_[0]->[NAME]
75     }
76    
77 elmex 1.4 =item B<namespace>
78 elmex 1.1
79     Returns the namespace URI of this node.
80    
81     =cut
82    
83     sub namespace {
84     $_[0]->[NS]
85     }
86    
87 elmex 1.4 =item B<eq ($namespace_or_alias, $name) or eq ($node)>
88 elmex 1.1
89     Returns true whether the current element matches the tag name C<$name>
90     in the namespaces pointed at by C<$namespace_or_alias>.
91    
92     You can either pass an alias that was defined in L<Net::XMPP2::Namespaces>
93     or pass an namespace URI in C<$namespace_or_alias>. If no alias with the name
94     C<$namespace_or_alias> was found in L<Net::XMPP2::Namespaces> it will be
95     interpreted as namespace URI.
96    
97     The first argument to eq can also be another L<Net::XMPP2::Node> instance.
98    
99     =cut
100    
101     sub eq {
102     my ($self, $n, $name) = @_;
103     if (ref $n) {
104     return $self->[PARSER]->nseq ($n->namespace, $n->name, $self->name);
105     } else {
106     my $ns = xmpp_ns ($n);
107     return $self->[PARSER]->nseq (($ns ? $ns : $n), $name, $self->name);
108     }
109     }
110    
111 elmex 1.4 =item B<eq_ns ($namespace_or_alias) or eq_ns ($node)>
112 elmex 1.1
113     This method return true if the namespace of this instance of L<Net::XMPP2::Node>
114     matches the namespace described by C<$namespace_or_alias> or the
115     namespace of the C<$node> which has to be another L<Net::XMPP2::Node> instance.
116    
117     See C<eq> for the meaning of C<$namespace_or_alias>.
118    
119     =cut
120    
121     sub eq_ns {
122     my ($self, $n) = @_;
123     if (ref $n) {
124     return ($n->namespace eq $self->namespace);
125     } else {
126     my $ns = xmpp_ns ($n);
127     $ns ||= $n;
128     return ($ns eq $self->namespace);
129     }
130     }
131    
132 elmex 1.4 =item B<attr ($name)>
133 elmex 1.1
134     Returns the contents of the C<$name> attribute.
135    
136     =cut
137    
138     sub attr {
139     $_[0]->[ATTRS]->{$_[1]};
140     }
141    
142 elmex 1.4 =item B<add_node ($node)>
143 elmex 1.1
144     Adds a sub-node to the current node.
145    
146     =cut
147    
148     sub add_node {
149     my ($self, $node) = @_;
150 elmex 1.6 push @{$self->[NODES]}, [NNODE, $node];
151 elmex 1.1 }
152    
153 elmex 1.4 =item B<nodes>
154 elmex 1.1
155     Returns a list of sub nodes.
156    
157     =cut
158    
159     sub nodes {
160 elmex 1.6 map { $_->[1] }
161     grep { $_->[0] == NNODE }
162     @{$_[0]->[NODES] || []};
163 elmex 1.1 }
164    
165 elmex 1.4 =item B<add_text ($string)>
166 elmex 1.1
167     Adds character data to the current node.
168    
169     =cut
170    
171     sub add_text {
172     my ($self, $text) = @_;
173 elmex 1.6 push @{$self->[NODES]}, [NTEXT, $text];
174 elmex 1.1 }
175    
176 elmex 1.4 =item B<text>
177 elmex 1.1
178     Returns the text for this node.
179    
180     =cut
181    
182     sub text {
183 elmex 1.6 join '', map $_->[1], grep { $_->[0] == NTEXT } @{$_[0]->[NODES] || []}
184 elmex 1.1 }
185    
186 elmex 1.4 =item B<find_all (@path)>
187 elmex 1.1
188     This method does a recursive descent through the sub-nodes and
189     fetches all nodes that match the last element of C<@path>.
190    
191     The elements of C<@path> consist of a array reference to an array with
192     two elements: the namespace key known by the C<$parser> and the tagname
193     we search for.
194    
195     =cut
196    
197     sub find_all {
198     my ($self, @path) = @_;
199     my $cur = shift @path;
200     my @ret;
201     for my $n ($self->nodes) {
202     if ($n->eq (@$cur)) {
203     if (@path) {
204     push @ret, $n->find_all (@path);
205     } else {
206     push @ret, $n;
207     }
208     }
209     }
210     @ret
211     }
212    
213 elmex 1.4 =item B<write_on ($writer)>
214 elmex 1.2
215     This writes the current node out to the L<Net::XMPP2::Writer> object in C<$writer>.
216    
217     =cut
218    
219     sub write_on {
220     my ($self, $w) = @_;
221 elmex 1.8 $w->raw ($self->as_string);
222 elmex 1.2 }
223    
224 elmex 1.4 =back
225    
226 elmex 1.6 =item B<as_string ()>
227    
228     This method returns the original character representation of this XML element
229 elmex 1.7 (and it's children nodes). Please note that the string is a unicode string,
230     meaning: to get octets use:
231    
232     my $octets = encode ('UTF-8', $node->as_string);
233    
234     Now you can roll stunts like this:
235    
236     my $libxml = XML::LibXML->new;
237     my $doc = $libxml->parse_string (encode ('UTF-8', $node->as_string ()));
238    
239     (You can use your favorite XML parser :)
240 elmex 1.6
241     =cut
242    
243     sub as_string {
244     my ($self) = @_;
245     join '',
246     map { $_->[0] == NRAW ? $_->[1] : $_->[1]->as_string }
247     grep { $_->[0] != NTEXT }
248     @{$self->[NODES] || []};
249     }
250    
251     =item B<append_raw ($string)>
252    
253     This method is called by the parser to store original strings of this element.
254    
255     =cut
256    
257     sub append_raw {
258     my ($self, $str) = @_;
259     push @{$self->[NODES]}, [NRAW, $str];
260     }
261    
262 elmex 1.7 =item B<to_sax_events ($handler)>
263    
264     This method takes anything that can receive SAX events.
265     See also L<XML::GDOME::SAX::Builder> or L<XML::Handler::BuildDOM>
266     or L<XML::LibXML::SAX::Builder>.
267    
268     With this you can convert this node to any DOM level 2 structure you want:
269    
270     my $builder = XML::LibXML::SAX::Builder->new;
271     $node->to_sax_events ($builder);
272     my $dom = $builder->result;
273     print "Canonized: " . $dom->toStringC14N . "\n";
274    
275     =cut
276    
277     sub to_sax_events {
278     my ($self, $handler) = @_;
279     my $doc = { Parent => undef };
280     $handler->start_document ($doc);
281     $self->_to_sax_events ($handler);
282     $handler->end_document ($doc);
283     }
284    
285     sub _to_sax_events {
286     my ($self, $handler) = @_;
287     $handler->start_element ({
288     NamespaceURI => $self->namespace,
289     Name => $self->name,
290     Attributes => {
291     map {
292     ($_ => { Name => $_, Value => $self->[ATTRS]->{$_} })
293     } keys %{$self->[ATTRS]}
294     }
295     });
296     for (@{$self->[NODES]}) {
297     if ($_->[0] == NTEXT) {
298     $handler->characters ($_->[1]);
299     } elsif ($_->[0] == NNODE) {
300     $_->[1]->_to_sax_events ($handler);
301     }
302     }
303     $handler->end_element ({
304     NamespaceURI => $self->namespace,
305     Name => $self->name,
306     });
307     }
308    
309 elmex 1.1 =head1 AUTHOR
310    
311 elmex 1.4 Robin Redeker, C<< <elmex at ta-sa.org> >>, JID: C<< <elmex at jabber.org> >>
312 elmex 1.1
313     =head1 COPYRIGHT & LICENSE
314    
315     Copyright 2007 Robin Redeker, all rights reserved.
316    
317     This program is free software; you can redistribute it and/or modify it
318     under the same terms as Perl itself.
319    
320     =cut
321    
322     1; # End of Net::XMPP2