line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package XML::Writer::Compiler; |
2
|
|
|
|
|
|
|
BEGIN { |
3
|
1
|
|
|
1
|
|
1025
|
$XML::Writer::Compiler::VERSION = '1.112060'; |
4
|
|
|
|
|
|
|
} |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: produce aoa from tree |
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
8
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
39
|
|
9
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
50
|
|
10
|
1
|
|
|
1
|
|
6
|
use feature "switch"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
103
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
1097
|
use autodie; |
|
1
|
|
|
|
|
32805
|
|
|
1
|
|
|
|
|
6
|
|
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
9372
|
use Moose; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use Carp; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub buildclass { |
19
|
|
|
|
|
|
|
my ( $self, $pkg, $tree, $firstdepth, $prepend_lib, $fileheader ) = @_; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
my $rootnode = $tree->look_down( '_tag' => qr/./ ); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my $lol = __PACKAGE__->mklol( $tree, $firstdepth ); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my $pkgstr = __PACKAGE__->_mkpkg( |
26
|
|
|
|
|
|
|
$pkg => $lol, |
27
|
|
|
|
|
|
|
$prepend_lib, $fileheader, $rootnode->{_tag} |
28
|
|
|
|
|
|
|
); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
warn "PKG:$pkg"; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my @part = split '::', $pkg; |
33
|
|
|
|
|
|
|
my $file = $part[$#part]; |
34
|
|
|
|
|
|
|
warn "PART:@part"; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
use File::Spec; |
37
|
|
|
|
|
|
|
my $path = File::Spec->catdir( $prepend_lib ? $prepend_lib : (), |
38
|
|
|
|
|
|
|
@part[ 0 .. $#part - 1 ] ); |
39
|
|
|
|
|
|
|
warn "PATH:$path"; |
40
|
|
|
|
|
|
|
use File::Path; |
41
|
|
|
|
|
|
|
File::Path::make_path( $path, { verbose => 1 } ); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
$file = File::Spec->catfile( $path, "$file.pm" ); |
44
|
|
|
|
|
|
|
warn "FILE:$file"; |
45
|
|
|
|
|
|
|
open( my $fh, '>', $file ); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
$fh->print($pkgstr); |
48
|
|
|
|
|
|
|
$pkgstr; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub mklol { |
53
|
|
|
|
|
|
|
my ( $class, $tree, $firstdepth ) = @_; |
54
|
|
|
|
|
|
|
unless ($firstdepth) { |
55
|
|
|
|
|
|
|
Carp::cluck('Assuming firstdepth == 0'); |
56
|
|
|
|
|
|
|
$firstdepth = 0; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
open( my $fh, '>', \my $string ) or die "Could not open string for writing"; |
59
|
|
|
|
|
|
|
$tree->methodsfrom( $fh, 0, '', $firstdepth ); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
use Perl::Tidy; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
perltidy( source => \$string, destination => \my $dest ); |
64
|
|
|
|
|
|
|
$dest; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub _mkpkg { |
69
|
|
|
|
|
|
|
my ( $self, $pkg, $lol, $prepend_lib, $extends_string, $rootnode ) = @_; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
open( my $fh, '>', \my $pkgstr ) or die "Could not open pkg for writing"; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my $extends = $extends_string ? "extends qw($extends_string)" : ''; |
74
|
|
|
|
|
|
|
$extends =~ s/^\s+//g; |
75
|
|
|
|
|
|
|
$fh->printf( <<'EOPKG', $pkg, $extends, $lol, $rootnode ); |
76
|
|
|
|
|
|
|
package %s; |
77
|
|
|
|
|
|
|
use Moose; |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
with qw(XML::Writer::Compiler::AutoPackage); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
%s; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
use Data::Dumper; |
85
|
|
|
|
|
|
|
use HTML::Element::Library; |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
use XML::Element; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
has 'data' => ( |
93
|
|
|
|
|
|
|
is => 'rw', |
94
|
|
|
|
|
|
|
trigger => \&maybe_morph |
95
|
|
|
|
|
|
|
); |
96
|
|
|
|
|
|
|
has 'writer' => (is => 'rw', isa => 'XML::Writer'); |
97
|
|
|
|
|
|
|
has 'string' => (is => 'rw', isa => 'XML::Writer::String'); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
%s; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub xml { |
103
|
|
|
|
|
|
|
my($self)=@_; |
104
|
|
|
|
|
|
|
my $method = '_tag_%s'; |
105
|
|
|
|
|
|
|
$self->$method; |
106
|
|
|
|
|
|
|
$self->writer->end; |
107
|
|
|
|
|
|
|
$self; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
1; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
EOPKG |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
use Perl::Tidy; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
perltidy( source => \$pkgstr, destination => \my $dest ); |
118
|
|
|
|
|
|
|
$dest; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
1; |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
package XML::Element; |
125
|
|
|
|
|
|
|
BEGIN { |
126
|
|
|
|
|
|
|
$XML::Element::VERSION = '1.112060'; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub cleantag { |
130
|
|
|
|
|
|
|
my ( $self, $andattr ) = @_; |
131
|
|
|
|
|
|
|
my $tag = $self->{_tag}; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
return $tag unless $andattr; |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
my %attr = $self->all_external_attr; |
136
|
|
|
|
|
|
|
my $attr; |
137
|
|
|
|
|
|
|
if ( scalar keys %attr ) { |
138
|
|
|
|
|
|
|
use Data::Dumper; |
139
|
|
|
|
|
|
|
my $d = Data::Dumper->new( [ \%attr ] ); |
140
|
|
|
|
|
|
|
$d->Purity(1)->Terse(1); |
141
|
|
|
|
|
|
|
$attr = $d->Dump; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
$tag .= " => $attr"; |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
$tag; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub childname { |
151
|
|
|
|
|
|
|
my ($child, $M, $D) = @_; |
152
|
|
|
|
|
|
|
if ( scalar(@$D) == 0 ) { |
153
|
|
|
|
|
|
|
sprintf '$self->_tag_%s; %s', $child->{_tag}, "\n"; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
else { |
156
|
|
|
|
|
|
|
sprintf '$self->%s_%s; %s', $M, $child->{_tag}, "\n"; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub tagmethod { |
162
|
|
|
|
|
|
|
my ( $self, $tag, $divecall, $children, $derefchain ) = @_; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my $childname; |
165
|
|
|
|
|
|
|
my $methodname = do { |
166
|
|
|
|
|
|
|
if ( scalar(@$derefchain) == 0 ) { |
167
|
|
|
|
|
|
|
"_tag_$tag"; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
else { |
170
|
|
|
|
|
|
|
sprintf '_tag_%s', join '_', @$derefchain; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
}; |
173
|
|
|
|
|
|
|
warn "METHODNAME: $methodname... derefchain: @$derefchain"; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
my @children = map { ref($_) ? childname($_, $methodname, $derefchain) : () } @$children; |
177
|
|
|
|
|
|
|
my $childstr = @children ? "@children" : '$self->writer->characters($data)'; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sprintf( <<'EOSTR', $methodname, $divecall, $tag, $childstr ); |
180
|
|
|
|
|
|
|
sub %s { |
181
|
|
|
|
|
|
|
my($self)=@_; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
my $root = $self->data; |
184
|
|
|
|
|
|
|
%s; |
185
|
|
|
|
|
|
|
my ($attr, $data) = $self->EXTRACT($elementdata); |
186
|
|
|
|
|
|
|
$self->writer->startTag(%s => @$attr); |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
%s; |
189
|
|
|
|
|
|
|
$self->writer->endTag; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
EOSTR |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub divecall { |
195
|
|
|
|
|
|
|
my ( $self, $derefstring ) = @_; |
196
|
|
|
|
|
|
|
use Data::Dumper; |
197
|
|
|
|
|
|
|
my $str = Dumper($derefstring); |
198
|
|
|
|
|
|
|
sprintf( <<'EOSTR', "@$derefstring" ); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
my $elementdata = $self->DIVE( $root, qw(%s) ) ; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
EOSTR |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub methodsfrom { |
206
|
|
|
|
|
|
|
my ( $self, $fh, $depth, $derefstring, $firstdepth ) = @_; |
207
|
|
|
|
|
|
|
$fh = *STDOUT{IO} unless defined $fh; |
208
|
|
|
|
|
|
|
$depth = 0 unless defined $depth; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my @newderef; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
if ( $depth < $firstdepth ) { |
213
|
|
|
|
|
|
|
@newderef = (); |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
else { |
216
|
|
|
|
|
|
|
if ( $depth == $firstdepth ) { |
217
|
|
|
|
|
|
|
@newderef = $self->cleantag; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
if ( $depth > $firstdepth ) { |
220
|
|
|
|
|
|
|
@newderef = ( @$derefstring, $self->cleantag ); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
#warn "DEREF: @newderef"; |
225
|
|
|
|
|
|
|
my @children = @{ $self->{'_content'} }; |
226
|
|
|
|
|
|
|
my $divecall = $self->divecall( \@newderef ); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
#warn "DIVECALL: $divecall"; |
229
|
|
|
|
|
|
|
my $tagmethod = |
230
|
|
|
|
|
|
|
$self->tagmethod( $self->cleantag, $divecall, \@children, \@newderef ); |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
$fh->print($tagmethod); |
233
|
|
|
|
|
|
|
for (@children) { |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
if ( ref $_ ) { # element |
236
|
|
|
|
|
|
|
#use Data::Dumper; |
237
|
|
|
|
|
|
|
#warn Dumper($_); |
238
|
|
|
|
|
|
|
$_->methodsfrom( $fh, $depth + 1, \@newderef, $firstdepth ) |
239
|
|
|
|
|
|
|
; # recurse |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
else { # text node |
242
|
|
|
|
|
|
|
; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
1; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=head1 NAME |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
XML::Writer::Compiler - create XML::Writer based classes whose instances can generate, refine and extend sample XML |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head1 SYNOPSIS |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
ROOT=CustomerAdd |
257
|
|
|
|
|
|
|
XML_FILE=$ROOT.xml |
258
|
|
|
|
|
|
|
OUTPUT_PKG = XML::Quickbooks::$ROOT |
259
|
|
|
|
|
|
|
HASH_DEPTH=4 #counting from 0, which level of XML file should hash keys start mapping from |
260
|
|
|
|
|
|
|
OUTPATH_PREPEND=lib |
261
|
|
|
|
|
|
|
EXTENDS=XML::Quickbooks # the XML class we generate, XML::Quickbooks::CustomerAdd has the parent XML::Quickbooks |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# Now run the compiler on the XML file to produce an XML class, which produces XML when a hashref is supplied |
264
|
|
|
|
|
|
|
# Also possible to subclass the generated XML class to customize XML generation when hashrefs are inadequate |
265
|
|
|
|
|
|
|
xwc $XML_FILE $OUTPUT_PKG $HASH_DEPTH $OUTPUT_PREPEND $EXTENDS |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=head1 DESCRIPTION |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
XML::Writer::Compiler is a module which takes a sample XML document and creates a single class from it. |
270
|
|
|
|
|
|
|
This class contains methods for each tag of the XML. The instance of the class can generate XML with the content supplied via a |
271
|
|
|
|
|
|
|
hashref. Subclassing the generated class allows more precise control over how the object-oriented XML generation occurs. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
The CPAN module most similar to XML::Writer::Compiler is L<XML::Toolkit>. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=head2 Simple Example |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head3 XML |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
<note> |
280
|
|
|
|
|
|
|
<to> |
281
|
|
|
|
|
|
|
<person> |
282
|
|
|
|
|
|
|
Bob |
283
|
|
|
|
|
|
|
</person> |
284
|
|
|
|
|
|
|
</to> |
285
|
|
|
|
|
|
|
<from>Jani</from> |
286
|
|
|
|
|
|
|
<heading>Reminder</heading> |
287
|
|
|
|
|
|
|
<body>Don't forget me this weekend!</body> |
288
|
|
|
|
|
|
|
</note> |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=head3 Compile XML to Perl class |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
This step is normally done via the F<xwc> script, but you can also write Perl code to compile XML: |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
my $compiler = XML::Writer::Compiler->new; |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
my $tree = XML::TreeBuilder->new( { 'NoExpand' => 0, 'ErrorContext' => 0 } ); |
297
|
|
|
|
|
|
|
$tree->parse_file('t/sample.xml'); |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
my $pkg = XML::Note'; |
300
|
|
|
|
|
|
|
my $class = $compiler->buildclass( $pkg, $tree, 0, '' ); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=head3 Perl |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
my %data = ( |
305
|
|
|
|
|
|
|
note => { |
306
|
|
|
|
|
|
|
to => { person => 'Satan' }, |
307
|
|
|
|
|
|
|
from => [ [ via => 'postcard', russia => 'with love' ], 'moneypenny' ] |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
); |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
my $xml = XML::Note->new; |
312
|
|
|
|
|
|
|
$xml->data(\%data); |
313
|
|
|
|
|
|
|
warn $xml->xml->string->value; |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=head2 Subclassing Example |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
If a simple substitution from a hashref of data will not suffice, then you can take the methods of the generated class and |
318
|
|
|
|
|
|
|
subclass them for things like repeating or conditional content. See the test file F<repeating.t> for an example. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head1 USAGE of xwc |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
The F<xwc> script is the most common way to convert an XML file to an equivalent Perl class. The script takes the |
323
|
|
|
|
|
|
|
following arguments |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=head2 xml_file (required) |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
the full/relative path to the sample XML file |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head2 perl_pkg |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
the name of the Perl package that will represent the C<xml_file> |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=head2 hash_depth |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
An XML file has nesting levels, or depth. Oftentimes, the outer levels will never be rewritten via the data hashref you supply. |
336
|
|
|
|
|
|
|
As a result, you dont want to have to several levels of your hashref before you actually specify the data you want to bind. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
Concretely, let's take some XML from the Quickbooks SDK: |
339
|
|
|
|
|
|
|
L<https://member.developer.intuit.com/qbSDK-current/Common/newOSR/index.html> |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
For instance the CustomerAdd xml starts like this: |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
<QBXML> |
344
|
|
|
|
|
|
|
<QBXMLMsgsRq onError="stopOnError"> |
345
|
|
|
|
|
|
|
<CustomerAddRq> |
346
|
|
|
|
|
|
|
<CustomerAdd> <!-- required --> |
347
|
|
|
|
|
|
|
<Name >STRTYPE</Name> <!-- required --> |
348
|
|
|
|
|
|
|
<IsActive >BOOLTYPE</IsActive> |
349
|
|
|
|
|
|
|
.... |
350
|
|
|
|
|
|
|
</QBXML> |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Now, none of the XML from the root to the XPath C<< QBXML/QBXMLMsgsRq/CustomerAddRq/CustomerAdd >> needs any |
353
|
|
|
|
|
|
|
binding from the hashref. If you compiled this XML and had C<< hash_depth>> set to 0, then to set the name your hashref |
354
|
|
|
|
|
|
|
would have to look like: |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
my %data = ( QBXML => { QXBMLMsgsRq => { CustomerAddRq => { CustomerAdd => { Name => 'Bob Jones' }}}}} ; |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
In contrast , if you compiled this XML and had C<< hash_depth>> set to 4, then to set the name your hashref |
359
|
|
|
|
|
|
|
would only have to look like: |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
my %data = ( Name => 'Bob Jones' } ; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head2 prepend_lib |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
The generated class file has a path generated from splitting the class name on double colon. In most cases, you will want to write |
366
|
|
|
|
|
|
|
the class file to a path with 'lib' prepended and so you would set this option to 'lib' |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=head2 extends |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
The XML class file is a L<Moose> class and can extend any superclass. E.g., in the L<XML::Quickbooks> distribution, each |
371
|
|
|
|
|
|
|
XML class file extends C<< XML::Quickbooks >>. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head1 SEE ALSO |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head2 Source code repository |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
L<https://github.com/metaperl/xml-writer-compiler> |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head2 Related modules |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head3 XML::Toolkit |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
L<XML::Toolkit> |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head3 XML::Element::Tolol |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
L<XML::Element::Tolol> |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=head2 Relevant links |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head3 Moose, the tree structure of XML and object-oriented inheritance hiearchies |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
L<http://perlmonks.org/index.pl?node_id=910617> |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=head3 Control Windows Quickbooks with Win32::OLE |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
L<http://perlmonks.org/index.pl?node_id=909187> |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head3 generating XML with data structures and Perl classes - the XML::Element::Tolol approach |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
L<http://perlmonks.org/index.pl?node_id=913713> |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head1 COPYRIGHT |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Copyright C<< RANGE('2011-07-25', NOW()) >> Terrence Brannon. |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
411
|
|
|
|
|
|
|
but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=head1 AUTHOR |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
Terrence Brannon <tbone@cpan.org> |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
|