root/trunk/lib/DJabberd/XMLElement.pm @ 65

Revision 65, 2.7 kB (checked in by bradfitz, 4 years ago)

start of processing roster adds/updates/deletes. this add hook chain call, but not pretty half, the easy implementation in RosterStorage.pm

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1package DJabberd::XMLElement;
2use strict;
3use fields (
4            'ns',        # namespace name
5            'element',   # element name
6            'attrs',     # hashref of {namespace}attr => value
7            'children',  # arrayref of child elements of this same type, or scalars for text nodes
8            );
9
10use DJabberd::Util;
11
12sub new {
13    my $class = shift;
14    if (ref $_[0]) {
15        # the down-classer that subclasses can inherit
16        return bless $_[0], $class;
17    }
18
19    # constructing a new XMLElement:
20    my ($ns, $elementname, $attrs, $children) = @_;
21
22    Carp::confess("children isn't an arrayref, is: $children") unless ref $children eq "ARRAY";
23
24    my $self = fields::new($class);
25    $self->{ns}       = $ns;
26    $self->{element}  = $elementname;
27    $self->{attrs}    = $attrs;
28    $self->{children} = $children;
29
30    return $self;
31}
32
33sub children_elements {
34    my DJabberd::XMLElement $self = shift;
35    return grep { ref $_ } @{ $self->{children} };
36}
37
38sub children {
39    my DJabberd::XMLElement $self = shift;
40    return @{ $self->{children} };
41}
42
43sub first_child {
44    my $self = shift;
45    return @{ $self->{children} } ? $self->{children}[0] : undef;
46}
47
48sub first_element {
49    my $self = shift;
50    foreach my $c (@{ $self->{children} }) {
51        return $c if ref $c;
52    }
53    return undef;
54}
55
56sub attr {
57    return $_[0]->{attrs}{$_[1]};
58}
59
60sub set_attr {
61    $_[0]->{attrs}{$_[1]} = $_[2];
62}
63
64sub attrs {
65    return $_[0]->{attrs};
66}
67
68sub element {
69    my $self = shift;
70    return ($self->{ns}, $self->{element}) if wantarray;
71    return "{$self->{ns}}$self->{element}";
72}
73
74sub element_name {
75    my $self = shift;
76    return $self->{element};
77}
78
79sub namespace {
80    my $self = shift;
81    return $self->{ns};
82}
83
84sub as_xml {
85    my $self = shift;
86    my $nsmap = shift || {};  # localname -> uri, uri -> localname
87    my $def_ns = shift;
88
89    my ($ns, $el) = $self->element;
90
91    # FIXME: escaping
92    my $attr_str = "";
93    my $attr = $self->attrs;
94    foreach my $k (keys %$attr) {
95        my $value = $attr->{$k};
96        $k =~ s!^\{(.+)\}!!;
97        my $ns = $1;
98        $attr_str .= " $k='" . DJabberd::Util::exml($value) . "'";
99    }
100
101    my $xmlns = $ns eq $def_ns ? "" : " xmlns='$ns'";
102    my $innards = $self->innards_as_xml($nsmap, $ns);
103    return length $innards ?
104        "<$el$xmlns$attr_str>$innards</$el>" :
105        "<$el$xmlns$attr_str/>";
106}
107
108sub innards_as_xml {
109    my $self = shift;
110    my $nsmap = shift || {};
111    my $def_ns = shift;
112
113    my $ret = "";
114    foreach my $c ($self->children) {
115        if (ref $c) {
116            $ret .= $c->as_xml($nsmap, $def_ns);
117        } else {
118            $ret .= DJabberd::Util::exml($c);
119        }
120    }
121    return $ret;
122}
123
1241;
Note: See TracBrowser for help on using the browser.