-
Notifications
You must be signed in to change notification settings - Fork 2
/
Styles.pm
655 lines (554 loc) · 24.7 KB
/
Styles.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
package Spreadsheet::XLSX::Reader::LibXML::XMLReader::Styles;
use version; our $VERSION = qv('v0.36.24');
use 5.010;
use Moose;
use MooseX::StrictConstructor;
use MooseX::HasDefaults::RO;
use Carp qw( confess );
use Types::Standard qw(
InstanceOf HashRef Str
Int Bool
);
use lib '../../../../../../lib',;
###LogSD use Log::Shiras::Telephone;
###LogSD use Log::Shiras::UnhideDebug;
extends 'Spreadsheet::XLSX::Reader::LibXML::XMLReader';
with 'Spreadsheet::XLSX::Reader::LibXML::XMLReader::XMLToPerlData',
;
###LogSD with 'Log::Shiras::LogSpace';
#########1 Dispatch Tables & Package Variables 5#########6#########7#########8#########9
my $element_lookup ={
numFmts => 'numFmt',
fonts => 'font',
borders => 'border',
fills => 'fill',
cellStyleXfs => 'xf',
cellXfs => 'xf',
cellStyles => 'cellStyle',
tableStyles => 'tableStyle',
};
my $id_lookup ={
numFmts => 'numFmtId',
fonts => 'fontId',
borders => 'borderId',
fills => 'fillId',
cellStyleXfs => 'xfId',
};
#########1 Public Attributes 3#########4#########5#########6#########7#########8#########9
#########1 Public Methods 3#########4#########5#########6#########7#########8#########9
sub get_format_position{
my( $self, $position, $header ) = @_;
###LogSD my $phone = Log::Shiras::Telephone->new(
###LogSD name_space => $self->get_log_space . '::get_format_position', );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Get defined formats at position: $position",
###LogSD (($self->_has_sub_translation) ? '..against current stored translation: ' . $self->_get_sub_translation : undef),
###LogSD (($self->_has_sub_position) ? '..against current stored position: ' . $self->_get_sub_position : undef),
###LogSD (($header) ? "For header: $header" : undef),
###LogSD (($self->_has_current_header) ? "..against stored header: " . $self->_get_current_header : undef) , ] );
# Check header request
if( $header and !exists( $id_lookup->{$header} ) ){
$self->set_error( "requested header -$header- does not match the lookup list - maybe it's got a typo? ( " . join( ' - ', keys %$id_lookup ) . ')' );
}
# Check for stored final value - this only works if the target header is all that is returned
my $already_got_it = 0;
if( $header and $self->_has_current_header and
$header eq $self->_get_current_header and
$self->_get_sub_translation == $position ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Already collected this header: $header", "..and position: $position" ] );
$already_got_it = 1;
}elsif( !$header and $self->_has_current_header and
$self->_get_current_header eq 'cellXfs' and
$self->_get_sub_position == $position ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Already collected this general format at position: $position" ] );
$already_got_it = 1;
}
return $self->_get_sub_position_ref if $already_got_it;
# build from scratch
my $result = $self->_get_header_and_position( 'cellXfs', $position );
return $result if ! $result;
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "The ref at position -$position- is:", $result ] );
$result = $self->_add_sub_refs( $result, $header, $position, 'cellXfs' );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "The ref at position -$position- is:", $result ] );
return $result;
}
sub get_default_format_position{
my( $self, $header ) = @_;
###LogSD my $phone = Log::Shiras::Telephone->new(
###LogSD name_space => $self->get_log_space . '::get_default_format_position', );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Get default format set ...", ] );
###LogSD $phone->talk( level => 'debug', message => [ "For header: $header" ] ) if $header;
# Check header request
if( $header and !exists( $id_lookup->{$header} ) ){
$self->set_error( "requested header -$header- does not match the lookup list - maybe it's got a typo? ( " . join( ' - ', keys %$id_lookup ) . ')' );
}
# Get base ref
my $result = $self->_get_header_and_position( 'cellStyleXfs', 0 );
return $result if ! $result;
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Default formats:", $result ] );
$result = $self->_add_sub_refs( $result, $header, 0, 'cellStyleXfs' );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Final formats:", $result ] );
return $result;
}
sub get_sub_format_position{
my( $self, $position, $header ) = @_;
###LogSD my $phone = Log::Shiras::Telephone->new(
###LogSD name_space => $self->get_log_space . '::get_sub_format_position', );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Get sub format for -$header- at position: $position",
###LogSD (($self->_has_sub_position) ? '..against current stored position: ' . $self->_get_sub_position : undef),
###LogSD (($header) ? "For header: $header" : undef),
###LogSD (($self->_has_current_header) ? "..against stored header: " . $self->_get_current_header : undef) , ] );
# Check the validaty of the request
my $has_required = 1;
if( !defined $header ){
$has_required = 0;
$self->set_error( '$header is a required value for the method - get_sub_format_position( $position, $header )' );
}elsif( !defined $position ){
$has_required = 0;
$self->set_error( '$position is a required value for the method - get_sub_format_position( $position, $header )' );
}elsif( !exists( $id_lookup->{$header} ) ){
$has_required = 0;
$self->set_error( "requested header -$header- does not match the lookup list - maybe it's got a typo? ( " . join( ' - ', keys %$id_lookup ) . ')' );
}
return undef if !$has_required;
# Check for stored final value - this only works if the target header is all that is returned
if( $self->_has_current_header and
$header eq $self->_get_current_header and
$self->_get_sub_position == $position ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Already collected this header: $header", "..and position: $position" ] );
return $self->_get_sub_position_ref;
}
# build from scratch
my $result = $self->_get_header_and_position( $header, $position );
return $result if ! $result;
$self->_set_current_header( $header );
$self->_set_sub_position_ref( { $header => $result } );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "The ref at position -$position- is:", $result ] );
return { $header => $result };
}
#########1 Private Attributes 3#########4#########5#########6#########7#########8#########9
has _style_block_size =>(
isa => HashRef,
traits => ['Hash'],
writer => '_set_style_block_size',
handles =>{
_get_block_size => 'get',
},
);
has _current_header =>(
isa => Str,
writer => '_set_current_header',
reader => '_get_current_header',
clearer => '_clear_current_header',
predicate => '_has_current_header',
trigger => \&_clear_sub_translation,
);
has _sub_translation =>(
isa => Int,
writer => '_set_sub_translation',
reader => '_get_sub_translation',
clearer => '_clear_sub_translation',
predicate => '_has_sub_translation',
trigger => \&_clear_sub_position_ref,
);
has _sub_position =>(
isa => Int,
writer => '_set_sub_position',
reader => '_get_sub_position',
clearer => '_clear_sub_position',
predicate => '_has_sub_position',
trigger => \&_clear_current_header,
);
has _sub_position_ref =>(
isa => HashRef,
writer => '_set_sub_position_ref',
reader => '_get_sub_position_ref',
clearer => '_clear_sub_position_ref',
predicate => '_has_sub_position_ref',
);
has _last_recorded =>(
isa => Bool,
writer => '_set_last_recorded',
reader => '_get_last_recorded',
default => 0,
);
#########1 Private Methods 3#########4#########5#########6#########7#########8#########9
sub _load_unique_bits{
my( $self, ) = @_;
###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
###LogSD $self->get_log_space . '::_load_unique_bits', );
###LogSD $phone->talk( level => 'trace', message => [ 'self:', $self ] );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Loading the counts and attributes of all the style types",
###LogSD 'bytes consumed: ' . $self->byte_consumed, 'At node: ' . ($self->node_name//'') ] );
if( !$self->node_name ){
if( $self->byte_consumed > 0 ){
###LogSD $phone->talk( level => 'trace', message => [
###LogSD 'The file is probably at the end - restting the file' ] );
$self->start_the_file_over;
}
$self->next_element( 'styleSheet' );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Loading the counts and attributes of all the style types",
###LogSD 'bytes consumed: ' . $self->byte_consumed, 'At node: ' . ($self->node_name//'') ] );
}elsif( $self->node_name ne 'styleSheet' ){
$self->next_element( 'styleSheet' );
###LogSD $phone->talk( level => 'trace', message => [
###LogSD 'bytes consumed: ' . $self->byte_consumed, 'At node: ' . $self->node_name ] );
}
###LogSD $phone->talk( level => 'trace', message => [
###LogSD 'lower level ? bytes consumed: ' . $self->byte_consumed, 'At node: ' . ($self->node_name//'') ] );
if( !$self->node_name or $self->node_name ne 'styleSheet' ){
confess "Can't find the styleSheet node in the xml file / section";
}
my $top_level_ref = $self->parse_element( 2 );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Resulting parse:", $top_level_ref ] );
$self->_set_style_block_size( $top_level_ref );
$self->start_the_file_over;
$self->next_element( 'numFmts' );
my $number_ref = $self->parse_element;
if( ref $number_ref ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Adding sheet defined translations:", $number_ref ] );
my $translations = $self->get_defined_excel_format_list;
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Defined excel format list:", $translations ] );
#~ if( $number_ref->{count} == 1 ){
#~ $translations->[$number_ref->{numFmt}->{numFmtId}] = "$number_ref->{numFmt}->{formatCode}";
#~ ###LogSD $phone->talk( level => 'debug', message => [
#~ ###LogSD 'loaded format: ' . $translations->[$number_ref->{numFmt}->{numFmtId}] ] );
#~ }else{
for my $format ( @{$number_ref->{list}} ){
$translations->[$format->{numFmtId}] = "$format->{formatCode}";
###LogSD $phone->talk( level => 'debug', message => [
###LogSD 'loaded format: ' . $translations->[$format->{numFmtId}] ] );
}
#~ }
$self->set_defined_excel_format_list( $translations );
}
}
sub _get_header_and_position{
my( $self, $target_header, $target_position ) = @_;
###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
###LogSD $self->get_log_space . '::_get_header_and_position', );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "getting the ref for target header: $target_header",
###LogSD "..and position: $target_position" ] );
if( $target_header eq 'numFmts' ){
my $format_string = $self->get_defined_excel_format( $target_position );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Special numFmts call: $target_position", "..returned: " .
###LogSD (($format_string) ? $format_string : ''), ] );
my $conversion = $self->parse_excel_format_string( $format_string, "Excel__$target_position" );
return $conversion;
}
my $test_ref = $self->_get_block_size( $target_header );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Recorded size of -$target_header- is:", $test_ref ] );
if( !$test_ref ){
$self->set_error( "Target header -$target_header- not found in the loaded Styles sheet" );
return undef;
}elsif( $test_ref->{count} < $target_position + 1 ){
$self->set_error( "Header -$target_header- does not extend to position: $target_position" );
return undef;
}
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "The target data should exist" ] );
if( $self->_has_current_header ){
if( $self->_get_current_header ne $target_header or
$target_header eq 'cellXfs' or
$self->_get_sub_position > $target_position ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "a bridge to far - reset" ] );
$self->_set_last_recorded( 0 );
$self->_clear_current_header;
$self->_clear_sub_position;
$self->_clear_sub_position_ref;
$self->_clear_sub_translation;
$self->start_the_file_over;
}
}
my $element_name = $element_lookup->{$target_header};
my ( $sub_position, $last_recorded, );# $changed_position
###LogSD $phone->talk( level => 'trace', message => [
###LogSD "Getting to the right header" ] );
if( $self->_has_current_header and $self->_get_current_header eq $target_header ){
$sub_position = $self->_get_sub_position;
###LogSD $phone->talk( level => 'trace', message => [
###LogSD "Already at: $target_header", "..and sub position: $sub_position" ] );
}else{
my $result = $self->next_element( $target_header );
if( !$result ){
###LogSD $phone->talk( level => 'trace', message => [
###LogSD "Failed to find the node resetting the file" ] );
$self->start_the_file_over;
$result = $self->next_element( $target_header );
$self->_set_last_recorded( 0 );
}
###LogSD $phone->talk( level => 'trace', message => [
###LogSD "Arrived at: " . $self->node_name,
###LogSD "Result of advancing to -$target_header- : $result" ] );
$result = $self->next_element( $element_name );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Result of advancing to the first element -$element_name- is: $result",
###LogSD '..at node: ' . $self->node_name, '..and byte position: ' . $self->byte_consumed ] );
$sub_position = 0;
#~ $changed_position = 1;
}
###LogSD $phone->talk( level => 'trace', message => [
###LogSD "Getting to the right element position from sub position: $sub_position" ] );
if( $target_position > $sub_position ){
$sub_position++ if $self->_get_last_recorded == 1;
$self->_set_last_recorded( 0 );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Sub position now: $sub_position",] );
while( $target_position > $sub_position ){
my $result = $self->next_element( $element_name );
$sub_position++;
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Result of advancing to the next element -$element_name- is: $result",
###LogSD '..at node: ' . $self->node_name,
###LogSD '..and byte position: ' . $self->byte_consumed, "..for positon: $sub_position" ] );
}
}
$self->_set_sub_position( $sub_position );
###LogSD $phone->talk( level => 'trace', message => [
###LogSD "pulling the element for the position: $sub_position" ] );
my $position_definition = $self->parse_element;#( 5 );
$self->_set_last_recorded( 1 ) if $self->node_name eq $element_name;
###LogSD $phone->talk( level => 'trace', message => [
###LogSD "Returning position ref:", $position_definition ] );
return $position_definition;
}
sub _add_sub_refs{
my( $self, $base_ref, $header, $super_position, $base_header ) = @_;
###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
###LogSD $self->get_log_space . '::_build_sub_refs', );
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Building the sub ref for:", $base_ref,
###LogSD (($header) ? "..focused on header: $header" : undef), ] );
if( $header ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "The call is to add data for just one specific header: $header", ] );
if( exists( $base_ref->{$id_lookup->{$header}} ) ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Collecting subdata for position: $base_ref->{$id_lookup->{$header}}", ] );
my $sub_result = $self->_get_header_and_position( $header, $base_ref->{$id_lookup->{$header}} );
return undef if !$sub_result;
$self->_set_current_header( $header );
$self->_set_sub_translation( $super_position );
###LogSD $phone->talk( level => 'trace', message => [
###LogSD 'Setting subref:', $sub_result, ] );
$self->_set_sub_position_ref( { $header => $sub_result } );
$base_ref = { $header => $sub_result };
}else{
$self->set_error( "requested header -$header- generally exists but has no pointer to a sub definition in the Styles file." );
$self->_set_sub_position( 0 );
$self->_clear_sub_position;
return undef;
}
}else{
for my $header ( keys %$id_lookup ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Checking for subdata of header: $header" ] );
if( exists( $base_ref->{$id_lookup->{$header}} ) ){
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "Retreiving the data at subposition: $base_ref->{$id_lookup->{$header}}" ] );
$base_ref->{$header} = $self->_get_header_and_position( $header, $base_ref->{$id_lookup->{$header}} );
}
}
$self->_set_sub_position( $super_position );
$self->_set_current_header( $base_header );
$self->_set_sub_position_ref( $base_ref);
}
###LogSD $phone->talk( level => 'debug', message => [
###LogSD "The final ref is:", $base_ref ] );
return $base_ref;
}
#########1 Phinish 3#########4#########5#########6#########7#########8#########9
no Moose;
__PACKAGE__->meta->make_immutable;
1;
#########1 Documentation 3#########4#########5#########6#########7#########8#########9
__END__
=head1 NAME
Spreadsheet::XLSX::Reader::LibXML::XMLReader::Styles - A LibXML::Reader styles base class
=head1 SYNOPSIS
#!/usr/bin/env perl
$|=1;
use Data::Dumper;
use MooseX::ShortCut::BuildInstance qw( build_instance );
use Spreadsheet::XLSX::Reader::LibXML::Error;
use Spreadsheet::XLSX::Reader::LibXML::XMLReader::Styles;
my $file_instance = build_instance(
package => 'StylesInstance',
superclasses => ['Spreadsheet::XLSX::Reader::LibXML::XMLReader::Styles'],
file => 'styles.xml',
error_inst => Spreadsheet::XLSX::Reader::LibXML::Error->new,
add_roles_in_sequence => [qw(
Spreadsheet::XLSX::Reader::LibXML::FmtDefault
Spreadsheet::XLSX::Reader::LibXML::ParseExcelFormatStrings
)],
);
print Dumper( $file_instance->get_format_position( 2 ) );
#######################################
# SYNOPSIS Screen Output
# 01: $VAR1 = {
# 02: 'applyNumberFormat' => '1',
# 03: 'fontId' => '0',
# 04: 'fonts' => {
# 05: 'color' => {
# 06: 'theme' => '1'
# 07: },
# 08: 'sz' => '11',
# 09: 'name' => 'Calibri',
# 10: 'scheme' => 'minor',
# 11: 'family' => '2'
# 12: },
# 13: 'numFmtId' => '164',
# 14: 'fillId' => '0',
# 15: 'xfId' => '0',
# 16: 'borders' => {
# 17: 'left' => 1,
# 18: 'right' => 1,
# 19: 'top' => 1,
# 20: 'diagonal' => 1,
# 21: 'bottom' => 1
# 22: },
# 23: 'borderId' => '0',
# 24: 'cellStyleXfs' => {
# 25: 'fillId' => '0',
# 26: 'fontId' => '0',
# 27: 'borderId' => '0',
# 28: 'numFmtId' => '0'
# 29: },
# 30: 'fills' => {
# 31: 'patternFill' => {
# 32: 'patternType' => 'none'
# 33: }
# 34: },
# 35: 'numFmts' => bless( {
# 36: 'name' => 'Excel_date_164',
# 37: 'uniq' => 86,
# 38: 'coercion' => bless( {
~ 180 lines hidden ~
# 219: }, 'Type::Coercion' )
# 220: }, 'Type::Tiny' )
# 221: };
#######################################
=head1 DESCRIPTION
This documentation is written to explain ways to use this module. To use the general
package for excel parsing out of the box please review the documentation for L<Workbooks
|Spreadsheet::XLSX::Reader::LibXML>, L<Worksheets
|Spreadsheet::XLSX::Reader::LibXML::Worksheet>, and
L<Cells|Spreadsheet::XLSX::Reader::LibXML::Cell>.
This class is written to get useful data from the sub file 'styles.xml' that is
a member of a zipped (.xlsx) archive or a stand alone XML text file of the same format.
The styles.xml file contains the format and display options used by Excel for showing
the stored data. To unzip an Excel file manually change the \.xlsx extention to \.zip
and windows should do (most) of the rest. For linux use an unzip utility. (
L<Archive::Zip> for instance :)
This documentation is the explanation of this specific module. For a general explanation
of the class and how to to add or adjust its place in the larger package see the L<Styles
|Spreadsheet::XLSX::Reader::LibXML::Styles> POD.
This module is the simplified way to extract information from the styles file needed when
doing high level reading of an Excel spread sheet. In order to do so it subclasses the module
L<Spreadsheet::XLSX::Reader::LibXML::XMLReader> and leverages one hard coded role
L<Spreadsheet::XLSX::Reader::LibXML::XMLReader::XMLToPerlData> Additionally the module will
error if not built with roles that supply two additional methods. The methods are
L<get_defined_excel_format|Spreadsheet::XLSX::Reader::LibXML::FmtDefault/get_defined_excel_format( $integer )>
and L<parse_excel_format_string
|Spreadsheet::XLSX::Reader::LibXML::ParseExcelFormatStrings/parse_excel_format_string( $string )>.
The links lead to the default source of these methods in the package. I<These methods are
intentionally not hard coded to this class so that the user can change them at run time. See
the attributes L<Spreadsheet::XLSX::Reader::LibXML/default_format_list> and
L<Spreadsheet::XLSX::Reader::LibXML/format_string_parser> for more explanation.> Read about
the function of each when replacing them. If you want to use the roles as-is, one way to
integrate them is with L<MooseX::ShortCut::BuildInstance>. The 'on-the-fly' roles also
add other methods (not documented here) to this class. Look at the documentation for those
modules to see what else comes with them.
=head2 Method(s)
These are the methods just provided by this class. Look at the documentation for the the two
modules consumed by this class for their elements. L<Spreadsheet::XLSX::Reader::LibXML::XMLReader>
and L<Spreadsheet::XLSX::Reader::LibXML::XMLReader::XMLToPerlData>
=head3 get_format_position( $position, [$header] )
=over
B<Definition:> This will return the styles information from the identified $position
(Counting from zero). the target position is usually drawn from the cell data stored in
the worksheet. The information is returned as a perl hash ref. Since the styles
data is in two tiers it finds all the subtier information for each indicated piece and
appends them to the hash ref as values for each type key. If you only want a specific
branch then you can add the branch $header key and the returned value will only contain
that leg. If you know the second level position for that header then call
L<get_sub_format_position|/get_sub_format_position( $position, $header )> as a quicker
substitute.
B<Accepts:> $position = an integer for the styles $position. (required)
B<Accepts:> $header = the target header key (optional)
B<Returns:> a hash ref of data
=back
=head3 get_sub_format_position( $position, $header )
=over
B<Definition:> This will return the styles information from the identified $position
(Counting from zero) for the specific $header. The information is returned as a perl
hash ref. This call will not seek a second level just return the data from that header.
B<Accepts:> $position = an integer for the styles $position (required)
B<Accepts:> $header = a string for the header key (required)
B<Returns:> a hash ref of data
=back
=head3 get_default_format_position( $position, $header )
=over
B<Definition:> For any cell that does not have a unquely identified format excel generally
stores a default format for the remainder of the sheet. This will return the two
tiered default styles information. If you only want the default from a specific header
then add the $header string to the method call. The information is returned as a perl
hash ref.
B<Accepts:> $header = a string for the header key (optional)
B<Returns:> a hash ref of data
=back
=head1 SUPPORT
=over
L<github Spreadsheet::XLSX::Reader::LibXML/issues
|https://github.com/jandrew/Spreadsheet-XLSX-Reader-LibXML/issues>
=back
=head1 TODO
=over
B<2.> This was one of the first XMLReader parsers I wrote and the XML parsing is crufty (needs a scrub)
=back
=head1 AUTHOR
=over
=item Jed Lund
=item jandrew@cpan.org
=back
=head1 COPYRIGHT
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
This software is copyrighted (c) 2014, 2015 by Jed Lund
=head1 DEPENDENCIES
=over
L<Spreadsheet::XLSX::Reader::LibXML>
=back
=head1 SEE ALSO
=over
L<Spreadsheet::ParseExcel> - Excel 2003 and earlier
L<Spreadsheet::XLSX> - 2007+
L<Spreadsheet::ParseXLSX> - 2007+
L<Log::Shiras|https://github.com/jandrew/Log-Shiras>
=over
All lines in this package that use Log::Shiras are commented out
=back
=back
=cut
#########1#########2 main pod documentation end 5#########6#########7#########8#########9