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__ |