File Coverage

blib/lib/Class/DBI/AsXML.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Class::DBI::AsXML;
2             # $Id: AsXML.pm,v 1.2 2005/01/15 15:32:32 cwest Exp $
3 1     1   359965 use strict;
  1         2  
  1         42  
4              
5             =head1 NAME
6              
7             Class::DBI::AsXML - Format CDBI Objects as XML
8              
9             =head1 SYNOPSIS
10              
11             # As you do...
12             package MyApp::User;
13             use base qw[Class::DBI];
14            
15             __PACKAGE__->connection('dbi:SQLite:dbfile', '', '');
16             __PACKAGE__->table(q[users]);
17             __PACKAGE__->columns(Primary => 'id');
18             __PACKAGE__->columns(Essential => qw[username password]);
19             __PACKAGE__->columns(Others => qw[email zip_code phone]);
20             __PACKAGE__->has_a(pref => 'MyApp::Pref');
21              
22             # Enter XML Support!
23             use Class::DBI::AsXML;
24             __PACKAGE__->to_xml_columns([qw[username email zip_code]]);
25              
26             # Elsewhere...
27             my $user = MyApp::User->retrieve(shift);
28             my $user_and_prefs_xml = $user->to_xml(depth => 1);
29              
30             # Or... override defaults
31             my $uname_pwd_xml = $user->to_xml( columns => {
32             ref($user) => [qw[username password]],
33             });
34            
35             # Create from XML
36             my $new_user = MyApp::User->create_from_xml(<<__XML__);
37            
38             new_user
39             new_pass
40             <casey@geeknest.com%gt;
41            
42             __XML__
43              
44             =cut
45              
46 1     1   6 use base qw[Exporter];
  1         2  
  1         70  
47 1     1   5 use vars qw[@EXPORT $VERSION];
  1         6  
  1         107  
48             $VERSION = sprintf "%d.%02d", split m/\./, (qw$Revision: 1.2 $)[1];
49             @EXPORT = qw[to_xml create_from_xml _to_xml_stringify];
50              
51 1     1   439 use XML::Simple;
  0            
  0            
52             use overload;
53              
54             =head1 DESCRIPTION
55              
56             This software adds XML output support to C based objects.
57              
58             =head2 to_xml_columns
59              
60             Class->to_xml_columns([qw[columns to dump with xml]]);
61              
62             This class method sets the default columns this class should dump
63             when calling C on an object. The single parameter is a
64             list reference with column names listed.
65              
66             =head2 to_xml
67              
68             my $xml = $object->to_xml(
69             columns => {
70             MyApp::User => [ qw[username email zip_code] ],
71             MyApp::File => [ qw[user filename size] ],
72             MyApp::Pref => [ MyApp::Pref->columns ],
73             },
74             depth => 10,
75             xml => {
76             NoAttr => 0,
77             },
78             );
79              
80             All arguments are optional.
81              
82             C - A hash reference containing key/value pairs associating
83             class names to a list of columns to dump as XML when the class is
84             serialized. They keys are class names and values are list references
85             containing column names, just as they'd be sent to C.
86             Passing a C parameter to this instance method will override
87             any defaults associated with this object. Failing that, C
88             is checked and failing that, the C and C columns
89             are dumped by default.
90              
91             Each column requested for XML output will go through an attempt to
92             be stringified. If the column value is an object with stringification
93             overloaded (using C) then it is stringified in that manner.
94             If the column is an object and its interface supports either C
95             or C methods, those method will be called and the results
96             returned. Finally, if the value is defined then it is stringified and
97             returned (this means references will become ugly). If the value is
98             undefined then an empty string is used in its place.
99              
100             C - Depth to dump to. Depth of zero, the default, will not
101             recurse. Column values are interogated to determine if they should
102             be recursed down. If the column value is an object whose API supports
103             the C method, then that method will be called and the resulting
104             XML will be parsed via C from C. The root node
105             will not be kept when converting the XML back into a data structure.
106              
107             C - Hash reference of XML::Simple options. Change these only
108             if you really know what you're doing. By default the following
109             options are set.
110              
111             NoAttr => 1,
112             RootName => $self->moniker,
113             XMLDecl => 0,
114              
115             =head2 create_from_xml
116              
117             my $new_user = MyApp::User->create_from_xml($xml);
118              
119             Creates a new user from an XML document. The document is parsed with
120             C and the root node is thrown away. All information passed in
121             to this method is ignored except the tags that match column names.
122              
123             =head1 EXPORTS
124              
125             This module is implemented as a mixin and therefore exports the
126             functions C, C, and C<_to_xml_stringify> into
127             the caller's namespace. If you don't want these to be exported, then
128             load this module using C.
129              
130             =cut
131              
132             Class::DBI->mk_classdata('to_xml_columns');
133             Class::DBI->to_xml_columns([]);
134              
135             sub to_xml {
136             my ($self, %args) = @_;
137              
138             my @keys = ($args{columns} && $args{columns}->{ref($self)})
139             ? @{$args{columns}->{ref($self)}}
140             : @{$self->to_xml_columns}
141             ? @{$self->to_xml_columns}
142             : (map $self->columns($_), qw[Primary Essential]);
143             my @vals = $self->get(@keys);
144            
145             my %hash;
146             foreach my $col ( @keys ) {
147             my $val = $self->$col;
148             if ( $args{depth} && $val && ref($val) && $val->can('to_xml')) {
149             $hash{$col} = XMLin $val->to_xml(%args, depth => $args{depth} - 1);
150             } else {
151             $hash{$col} = $self->_to_xml_stringify($val);
152             }
153             }
154              
155             my %xml_simple = $args{xml} ? %{$args{xml}} : ();
156             my $xml = XMLout \%hash,
157             NoAttr => 1,
158             RootName => $self->moniker,
159             XMLDecl => 0,
160             %xml_simple;
161            
162             return $xml;
163             }
164              
165             sub create_from_xml {
166             my ($class, $xml) = @_;
167            
168             my $data = XMLin $xml;
169              
170             my %args;
171             foreach ( $class->columns ) {
172             next unless exists $data->{$_};
173             $args{$_} = $data->{$_};
174             }
175             return $class->create(\%args);
176             }
177              
178             sub _to_xml_stringify {
179             my ($self, $val) = @_;
180              
181             if ($val && ref($val)) {
182             return "$val" if overload::Overloaded($val)
183             && overload::Method($val, '""');
184             return $val->as_string if $val->can('as_string');
185             return $val->as_text if $val->can('as_text');
186             }
187              
188             return "$val" if defined $val;
189             return '';
190             }
191              
192             1;
193              
194             __END__