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