3 package XML::Atom::Base;
5 use base qw( XML::Atom::ErrorHandler Class::Data::Inheritable );
9 use XML::Atom::Util qw( set_ns first nodelist childlist create_element );
11 __PACKAGE__->mk_classdata('__attributes', []);
15 my $obj = bless {}, $class;
16 $obj->init(@_) or return $class->error($obj->errstr);
23 if (!exists $param{Namespace} and my $ns = $obj->element_ns) {
24 $param{Namespace} = $ns;
26 $obj->set_ns(\%param);
28 unless ($elem = $param{Elem}) {
30 my $doc = XML::LibXML::Document->createDocument('1.0', 'utf-8');
32 my ($ns_uri, $ns_prefix);
33 if ( ref $ns and $ns->isa('XML::Atom::Namespace') ) {
35 $ns_prefix = $ns->{prefix};
39 if ( $ns_uri and $ns_prefix ) {
40 $elem = $doc->createElement($obj->element_name);
41 $elem->setNamespace( $ns_uri, $ns_prefix, 1 );
43 $elem = $doc->createElementNS($obj->ns, $obj->element_name);
45 $doc->setDocumentElement($elem);
47 $elem = XML::XPath::Node::Element->new($obj->element_name);
48 my $ns = XML::XPath::Node::Namespace->new('#default' => $obj->ns);
49 $elem->appendNamespace($ns);
59 sub ns { $_[0]->{ns} }
60 sub elem { $_[0]->{elem} }
64 XML::Atom::Util::ns_to_version($atom->ns);
69 if ($atom->version >= 1.0) {
70 return "application/atom+xml";
72 return "application/x.atom+xml";
79 my @list = $obj->getlist($ns, $name);
86 my $ns_uri = ref($ns) eq 'XML::Atom::Namespace' ? $ns->{uri} : $ns;
87 my @node = nodelist($obj->elem, $ns_uri, $name);
89 my $val = LIBXML ? $_->textContent : $_->string_value;
92 Encode::_utf8_off($val) unless $XML::Atom::ForceUnicode;
100 my($ns, $name, $val, $attr) = @_;
101 return $obj->set($ns, $name, $val, $attr, 1);
106 my($ns, $name, $val, $attr, $add) = @_;
107 my $ns_uri = ref $ns eq 'XML::Atom::Namespace' ? $ns->{uri} : $ns;
108 my @elem = childlist($obj->elem, $ns_uri, $name);
109 if (!$add && @elem) {
110 $obj->elem->removeChild($_) for @elem;
112 my $elem = create_element($ns, $name);
113 if (UNIVERSAL::isa($val, 'XML::Atom::Base')) {
115 for my $child ($val->elem->childNodes) {
116 $elem->appendChild($child->cloneNode(1));
118 for my $attr ($val->elem->attributes) {
119 next unless ref($attr) eq 'XML::LibXML::Attr';
120 $elem->setAttribute($attr->getName, $attr->getValue);
123 for my $child ($val->elem->getChildNodes) {
124 $elem->appendChild($child);
126 for my $attr ($val->elem->getAttributes) {
127 $elem->appendAttribute($attr);
132 $elem->appendChild(XML::LibXML::Text->new($val));
134 $elem->appendChild(XML::XPath::Node::Text->new($val));
137 $obj->elem->appendChild($elem);
139 while (my($k, $v) = each %$attr) {
140 $elem->setAttribute($k, $v);
149 my $val = $obj->elem->getAttribute($attr);
152 Encode::_utf8_off($val) unless $XML::Atom::ForceUnicode;
160 my($attr, $val) = @_;
161 $obj->elem->setAttribute($attr => $val);
163 my($ns, $attr, $val) = @_;
164 my $attribute = "$ns->{prefix}:$attr";
166 $obj->elem->setAttributeNS($ns->{uri}, $attribute, $val);
168 my $ns = XML::XPath::Node::Namespace->new(
169 $ns->{prefix} => $ns->{uri}
171 $obj->elem->appendNamespace($ns);
172 $obj->elem->setAttribute($attribute => $val);
179 my($ns, $name, $class) = @_;
180 my $ns_uri = ref($ns) eq 'XML::Atom::Namespace' ? $ns->{uri} : $ns;
181 my @elem = childlist($obj->elem, $ns_uri, $name) or return;
182 my @obj = map { $class->new( Elem => $_, Namespace => $ns ) } @elem;
183 return wantarray ? @obj : $obj[0];
186 sub mk_elem_accessors {
191 if ( ref $list[-1] ) {
192 my $ns_list = pop @list;
193 if ( ref $ns_list eq 'ARRAY' ) {
194 $ns_list = $ns_list->[0];
196 if ( ref($ns_list) =~ /Namespace/ ) {
197 $override_ns = $ns_list;
199 if ( ref $ns_list eq 'HASH' ) {
200 $override_ns = XML::Atom::Namespace->new(%$ns_list);
202 elsif ( not ref $ns_list and $ns_list ) {
203 $override_ns = $ns_list;
209 for my $elem ( @list ) {
210 (my $meth = $elem) =~ tr/\-/_/;
211 *{"${class}::$meth"} = sub {
214 return $obj->set( $override_ns || $obj->ns, $elem, $_[0]);
216 return $obj->get( $override_ns || $obj->ns, $elem);
222 sub mk_attr_accessors {
226 for my $attr (@list) {
227 (my $meth = $attr) =~ tr/\-/_/;
228 *{"${class}::$meth"} = sub {
231 return $obj->set_attr($attr => $_[0]);
233 return $obj->get_attr($attr);
236 $class->_add_attribute($attr);
241 my($class, $attr) = @_;
242 push @{$class->__attributes}, $attr;
247 @{ $class->__attributes };
250 sub mk_xml_attr_accessors {
251 my($class, @list) = @_;
253 for my $attr (@list) {
254 (my $meth = $attr) =~ tr/\-/_/;
255 *{"${class}::$meth"} = sub {
258 my $elem = $obj->elem;
260 $elem->setAttributeNS('http://www.w3.org/XML/1998/namespace',
263 return $elem->getAttribute("xml:$attr");
266 $obj->elem->setAttribute("xml:$attr", $_[0]);
268 return $obj->elem->getAttribute("xml:$attr");
274 sub mk_object_accessor {
276 my($name, $ext_class) = @_;
278 (my $meth = $name) =~ tr/\-/_/;
279 *{"${class}::$meth"} = sub {
281 my $ns_uri = $ext_class->element_ns || $obj->ns;
283 return $obj->set($ns_uri, $name, $_[0]);
285 return $obj->get_object($ns_uri, $name, $ext_class);
291 sub mk_object_list_accessor {
293 my($name, $ext_class, $moniker) = @_;
297 *{"$class\::$name"} = sub {
300 my $ns_uri = $ext_class->element_ns || $obj->ns;
302 # setter: clear existent elements first
303 my @elem = childlist($obj->elem, $ns_uri, $name);
305 $obj->elem->removeChild($el);
308 # add the new elements for each
309 my $adder = "add_$name";
310 for my $add_elem (@_) {
311 $obj->$adder($add_elem);
314 # getter: just call get_object which is a context aware
315 return $obj->get_object($ns_uri, $name, $ext_class);
319 # moniker returns always list: array ref in a scalar context
321 *{"$class\::$moniker"} = sub {
324 return $obj->$name(@_);
326 my @obj = $obj->$name;
327 return wantarray ? @obj : \@obj;
333 *{"$class\::add_$name"} = sub {
337 my $ns_uri = $ext_class->element_ns || $obj->ns;
338 my $elem = (ref $stuff && UNIVERSAL::isa($stuff, $ext_class)) ?
339 $stuff->elem : create_element($ns_uri, $name);
340 $obj->elem->appendChild($elem);
342 if (ref($stuff) eq 'HASH') {
343 for my $k ( $ext_class->attributes ) {
344 defined $stuff->{$k} or next;
345 $elem->setAttribute($k, $stuff->{$k});
354 my $doc = XML::LibXML::Document->new('1.0', 'utf-8');
355 $doc->setDocumentElement($obj->elem->cloneNode(1));
356 return $doc->toString(1);
358 return '<?xml version="1.0" encoding="utf-8"?>' . "\n" .
359 $obj->elem->toString;
365 my $xml = $obj->as_xml;
366 if (utf8::is_utf8($xml)) {
367 return Encode::encode_utf8($xml);