1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
7
8 #include "xlsx_pivot_context.hpp"
9 #include "ooxml_namespace_types.hpp"
10 #include "ooxml_token_constants.hpp"
11 #include "xml_context_global.hpp"
12 #include "session_context.hpp"
13 #include "xlsx_types.hpp"
14
15 #include "orcus/measurement.hpp"
16 #include "orcus/spreadsheet/import_interface_pivot.hpp"
17
18 #include <iostream>
19 #include <boost/optional.hpp>
20 #include <mdds/sorted_string_map.hpp>
21
22 using namespace std;
23
24 namespace orcus {
25
26 namespace {
27
28 typedef mdds::sorted_string_map<xlsx_pivot_cache_def_context::source_type> pc_source_type;
29
30 // Keys must be sorted.
31 pc_source_type::entry pc_source_entries[] = {
32 { ORCUS_ASCII("consolidation"), xlsx_pivot_cache_def_context::source_type::consolidation },
33 { ORCUS_ASCII("external"), xlsx_pivot_cache_def_context::source_type::external },
34 { ORCUS_ASCII("scenario"), xlsx_pivot_cache_def_context::source_type::scenario },
35 { ORCUS_ASCII("worksheet"), xlsx_pivot_cache_def_context::source_type::worksheet },
36 };
37
get_pc_source_map()38 const pc_source_type& get_pc_source_map()
39 {
40 static pc_source_type source_map(
41 pc_source_entries,
42 sizeof(pc_source_entries)/sizeof(pc_source_entries[0]),
43 xlsx_pivot_cache_def_context::source_type::unknown);
44
45 return source_map;
46 }
47
48 }
49
xlsx_pivot_cache_def_context(session_context & cxt,const tokens & tokens,spreadsheet::iface::import_pivot_cache_definition & pcache,spreadsheet::pivot_cache_id_t pcache_id)50 xlsx_pivot_cache_def_context::xlsx_pivot_cache_def_context(
51 session_context& cxt, const tokens& tokens,
52 spreadsheet::iface::import_pivot_cache_definition& pcache,
53 spreadsheet::pivot_cache_id_t pcache_id) :
54 xml_context_base(cxt, tokens), m_pcache(pcache), m_pcache_id(pcache_id) {}
55
can_handle_element(xmlns_id_t,xml_token_t) const56 bool xlsx_pivot_cache_def_context::can_handle_element(xmlns_id_t /*ns*/, xml_token_t /*name*/) const
57 {
58 return true;
59 }
60
create_child_context(xmlns_id_t,xml_token_t)61 xml_context_base* xlsx_pivot_cache_def_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
62 {
63 return nullptr;
64 }
65
end_child_context(xmlns_id_t,xml_token_t,xml_context_base *)66 void xlsx_pivot_cache_def_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
67 {
68 }
69
start_element(xmlns_id_t ns,xml_token_t name,const::std::vector<xml_token_attr_t> & attrs)70 void xlsx_pivot_cache_def_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs)
71 {
72 xml_token_pair_t parent = push_stack(ns, name);
73 if (ns != NS_ooxml_xlsx)
74 return;
75
76 switch (name)
77 {
78 case XML_pivotCacheDefinition:
79 {
80 xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
81
82 pstring refreshed_by;
83 pstring rid;
84 long record_count = -1;
85
86 for_each(attrs.begin(), attrs.end(),
87 [&](const xml_token_attr_t& attr)
88 {
89 if (!attr.ns || attr.ns == NS_ooxml_xlsx)
90 {
91 switch (attr.name)
92 {
93 case XML_refreshedBy:
94 refreshed_by = attr.value;
95 break;
96 case XML_recordCount:
97 record_count = to_long(attr.value);
98 break;
99 default:
100 ;
101 }
102 }
103 else if (attr.ns == NS_ooxml_r)
104 {
105 switch (attr.name)
106 {
107 case XML_id:
108 // relation id for its cache record.
109 rid = attr.value;
110 break;
111 default:
112 ;
113 }
114 }
115 }
116 );
117
118 if (get_config().debug)
119 {
120 cout << "---" << endl;
121 cout << "pivot cache definition" << endl;
122 cout << "refreshed by: " << refreshed_by << endl;
123 cout << "record count: " << record_count << endl;
124 cout << "rid: " << rid << endl;
125 }
126
127 if (!rid.empty())
128 {
129 // The rid string here must be persistent beyond the current
130 // context.
131 rid = get_session_context().m_string_pool.intern(rid).first;
132
133 m_pcache_info.data.insert(
134 opc_rel_extras_t::map_type::value_type(
135 rid, orcus::make_unique<xlsx_rel_pivot_cache_record_info>(m_pcache_id)));
136 }
137
138 break;
139 }
140 case XML_cacheSource:
141 {
142 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotCacheDefinition);
143
144 pstring source_type_s;
145
146 for_each(attrs.begin(), attrs.end(),
147 [&](const xml_token_attr_t& attr)
148 {
149 if (attr.ns && attr.ns != NS_ooxml_xlsx)
150 return;
151
152 switch (attr.name)
153 {
154 case XML_type:
155 m_source_type =
156 get_pc_source_map().find(attr.value.get(), attr.value.size());
157
158 source_type_s = attr.value;
159 break;
160 default:
161 ;
162 }
163 }
164 );
165
166 if (get_config().debug)
167 cout << "type: " << source_type_s << endl;
168
169 break;
170 }
171 case XML_worksheetSource:
172 {
173 xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheSource);
174 if (m_source_type != source_type::worksheet)
175 throw xml_structure_error(
176 "worksheetSource element encountered while the source type is not worksheet.");
177
178 pstring ref, sheet_name, table_name;
179
180 for_each(attrs.begin(), attrs.end(),
181 [&](const xml_token_attr_t& attr)
182 {
183 if (attr.ns && attr.ns != NS_ooxml_xlsx)
184 return;
185
186 switch (attr.name)
187 {
188 case XML_ref:
189 ref = attr.value;
190 break;
191 case XML_sheet:
192 sheet_name = attr.value;
193 break;
194 case XML_name:
195 table_name = attr.value;
196 break;
197 default:
198 ;
199 }
200 }
201 );
202
203 if (get_config().debug)
204 {
205 cout << "table: " << table_name << endl;
206 cout << "ref: " << ref << endl;
207 cout << "sheet: " << sheet_name << endl;
208 }
209
210 if (!table_name.empty())
211 m_pcache.set_worksheet_source(table_name.data(), table_name.size());
212 else
213 m_pcache.set_worksheet_source(
214 ref.get(), ref.size(), sheet_name.get(), sheet_name.size());
215 break;
216 }
217 case XML_cacheFields:
218 {
219 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotCacheDefinition);
220 single_long_attr_getter func(NS_ooxml_xlsx, XML_count);
221 long field_count = for_each(attrs.begin(), attrs.end(), func).get_value();
222
223 if (get_config().debug)
224 cout << "field count: " << field_count << endl;
225
226 if (field_count < 0)
227 throw xml_structure_error("field count of a pivot cache must be positive.");
228
229 m_pcache.set_field_count(field_count);
230 break;
231 }
232 case XML_cacheField:
233 {
234 xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheFields);
235
236 pstring field_name;
237 long numfmt_id = -1;
238
239 for_each(attrs.begin(), attrs.end(),
240 [&](const xml_token_attr_t& attr)
241 {
242 if (attr.ns && attr.ns != NS_ooxml_xlsx)
243 return;
244
245 switch (attr.name)
246 {
247 case XML_name:
248 field_name = attr.value;
249 break;
250 case XML_numFmtId:
251 numfmt_id = to_long(attr.value);
252 break;
253 default:
254 ;
255 }
256 }
257 );
258
259 // TODO : Handle number format ID here.
260 m_pcache.set_field_name(field_name.get(), field_name.size());
261
262 if (get_config().debug)
263 {
264 cout << "* name: " << field_name << endl;
265 cout << " number format id: " << numfmt_id << endl;
266 }
267 break;
268 }
269 case XML_fieldGroup:
270 {
271 xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheField);
272 long group_parent = -1;
273 long group_base = -1;
274
275 for_each(attrs.begin(), attrs.end(),
276 [&](const xml_token_attr_t& attr)
277 {
278 if (attr.ns && attr.ns != NS_ooxml_xlsx)
279 return;
280
281 switch (attr.name)
282 {
283 case XML_par:
284 group_parent = to_long(attr.value);
285 break;
286 case XML_base:
287 group_base = to_long(attr.value);
288 break;
289 default:
290 ;
291 }
292 }
293 );
294
295 if (get_config().debug)
296 {
297 if (group_parent >= 0)
298 cout << " * group parent index: " << group_parent << endl;
299 if (group_base >= 0)
300 cout << " * group base index: " << group_base << endl;
301 }
302
303 if (group_base >= 0)
304 {
305 // This is a group field.
306 m_pcache_field_group = m_pcache.create_field_group(group_base);
307 }
308 break;
309 }
310 case XML_discretePr:
311 {
312 xml_element_expected(parent, NS_ooxml_xlsx, XML_fieldGroup);
313
314 long count = -1;
315
316 for_each(attrs.begin(), attrs.end(),
317 [&](const xml_token_attr_t& attr)
318 {
319 if (attr.ns && attr.ns != NS_ooxml_xlsx)
320 return;
321
322 switch (attr.name)
323 {
324 case XML_count:
325 count = to_long(attr.value);
326 break;
327 default:
328 ;
329 }
330 }
331 );
332
333 if (get_config().debug)
334 cout << " * group child member count: " << count << endl;
335
336 break;
337 }
338 case XML_rangePr:
339 {
340 xml_element_expected(parent, NS_ooxml_xlsx, XML_fieldGroup);
341
342 bool auto_start = true;
343 bool auto_end = true;
344 double start = 0.0;
345 double end = 0.0;
346 double interval = 1.0;
347
348 boost::optional<date_time_t> start_date;
349 boost::optional<date_time_t> end_date;
350
351 // Default group-by type appears to be 'range'.
352 spreadsheet::pivot_cache_group_by_t group_by =
353 spreadsheet::pivot_cache_group_by_t::range;
354
355 for_each(attrs.begin(), attrs.end(),
356 [&](const xml_token_attr_t& attr)
357 {
358 if (attr.ns && attr.ns != NS_ooxml_xlsx)
359 return;
360
361 switch (attr.name)
362 {
363 case XML_autoStart:
364 auto_start = to_bool(attr.value);
365 break;
366 case XML_autoEnd:
367 auto_end = to_bool(attr.value);
368 break;
369 case XML_startNum:
370 start = to_double(attr.value);
371 break;
372 case XML_endNum:
373 end = to_double(attr.value);
374 break;
375 case XML_groupInterval:
376 interval = to_double(attr.value);
377 break;
378 case XML_startDate:
379 start_date = to_date_time(attr.value);
380 break;
381 case XML_endDate:
382 end_date = to_date_time(attr.value);
383 break;
384 case XML_groupBy:
385 group_by = spreadsheet::to_pivot_cache_group_by_enum(
386 attr.value.get(), attr.value.size());
387 break;
388 default:
389 ;
390 }
391 }
392 );
393
394 // Pass the values to the interface.
395 m_pcache_field_group->set_range_grouping_type(group_by);
396 m_pcache_field_group->set_range_auto_start(auto_start);
397 m_pcache_field_group->set_range_auto_end(auto_end);
398 m_pcache_field_group->set_range_start_number(start);
399 m_pcache_field_group->set_range_end_number(end);
400 m_pcache_field_group->set_range_interval(interval);
401
402 if (start_date)
403 m_pcache_field_group->set_range_start_date(*start_date);
404 if (end_date)
405 m_pcache_field_group->set_range_end_date(*end_date);
406
407 if (get_config().debug)
408 {
409 cout << " auto start: " << auto_start << endl;
410 cout << " auto end: " << auto_end << endl;
411 cout << " start: " << start << endl;
412 cout << " end: " << end << endl;
413 cout << " interval: " << interval << endl;
414
415 if (start_date)
416 cout << "start date: " << *start_date << endl;
417 if (end_date)
418 cout << "end date: " << *end_date << endl;
419 }
420
421 break;
422 }
423 case XML_sharedItems:
424 {
425 start_element_shared_items(parent, attrs);
426 break;
427 }
428 case XML_groupItems:
429 {
430 xml_element_expected(parent, NS_ooxml_xlsx, XML_fieldGroup);
431
432 long count = -1;
433
434 for_each(attrs.begin(), attrs.end(),
435 [&](const xml_token_attr_t& attr)
436 {
437 if (attr.ns && attr.ns != NS_ooxml_xlsx)
438 return;
439
440 switch (attr.name)
441 {
442 case XML_count:
443 count = to_long(attr.value);
444 break;
445 default:
446 ;
447 }
448 }
449 );
450
451 if (get_config().debug)
452 cout << " * group member count: " << count << endl;
453
454 break;
455 }
456 case XML_s:
457 {
458 start_element_s(parent, attrs);
459 break;
460 }
461 case XML_n:
462 {
463 start_element_n(parent, attrs);
464 break;
465 }
466 case XML_d:
467 {
468 start_element_d(parent, attrs);
469 break;
470 }
471 case XML_e:
472 {
473 start_element_e(parent, attrs);
474 break;
475 }
476 case XML_x:
477 {
478 const xml_elem_set_t expected = {
479 { NS_ooxml_xlsx, XML_discretePr },
480 { NS_ooxml_xlsx, XML_reference },
481 };
482 xml_element_expected(parent, expected);
483
484 long index = -1;
485
486 for_each(attrs.begin(), attrs.end(),
487 [&](const xml_token_attr_t& attr)
488 {
489 if (attr.ns && attr.ns != NS_ooxml_xlsx)
490 return;
491
492 switch (attr.name)
493 {
494 case XML_v:
495 index = to_long(attr.value);
496 break;
497 default:
498 ;
499 }
500 }
501 );
502
503 if (index < 0)
504 throw xml_structure_error("element 'x' without a required attribute 'v'.");
505
506 if (get_config().debug)
507 cout << " * index = " << index << endl;
508
509 if (m_pcache_field_group)
510 m_pcache_field_group->link_base_to_group_items(index);
511
512 break;
513 }
514 default:
515 warn_unhandled();
516 }
517 }
518
end_element(xmlns_id_t ns,xml_token_t name)519 bool xlsx_pivot_cache_def_context::end_element(xmlns_id_t ns, xml_token_t name)
520 {
521 if (ns == NS_ooxml_xlsx)
522 {
523 switch (name)
524 {
525 case XML_pivotCacheDefinition:
526 {
527 m_pcache.commit();
528 break;
529 }
530 case XML_cacheField:
531 {
532 m_pcache.commit_field();
533 m_pcache_field_group = nullptr;
534 break;
535 }
536 case XML_discretePr:
537 {
538 break;
539 }
540 case XML_fieldGroup:
541 {
542 if (m_pcache_field_group)
543 m_pcache_field_group->commit();
544 break;
545 }
546 case XML_s:
547 end_element_s();
548 break;
549 case XML_n:
550 end_element_n();
551 break;
552 case XML_d:
553 end_element_d();
554 break;
555 case XML_e:
556 end_element_e();
557 break;
558 default:
559 ;
560 }
561 }
562
563 return pop_stack(ns, name);
564 }
565
characters(const pstring &,bool)566 void xlsx_pivot_cache_def_context::characters(const pstring& /*str*/, bool /*transient*/)
567 {
568 }
569
pop_rel_extras()570 opc_rel_extras_t xlsx_pivot_cache_def_context::pop_rel_extras()
571 {
572 return std::move(m_pcache_info);
573 }
574
start_element_s(const xml_token_pair_t & parent,const std::vector<xml_token_attr_t> & attrs)575 void xlsx_pivot_cache_def_context::start_element_s(
576 const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
577 {
578 if (parent.first != NS_ooxml_xlsx)
579 {
580 warn_unhandled();
581 return;
582 }
583
584 pstring value;
585
586 for_each(attrs.begin(), attrs.end(),
587 [&](const xml_token_attr_t& attr)
588 {
589 if (attr.ns && attr.ns != NS_ooxml_xlsx)
590 return;
591
592 switch (attr.name)
593 {
594 case XML_v:
595 value = attr.value;
596 break;
597 default:
598 ;
599 }
600 }
601 );
602
603 switch (parent.second)
604 {
605 case XML_sharedItems:
606 {
607 // regular (non-group) field member name.
608
609 if (get_config().debug)
610 cout << " * field member: " << value << endl;
611
612 m_field_item_used = true;
613 m_pcache.set_field_item_string(value.get(), value.size());
614 break;
615 }
616 case XML_groupItems:
617 {
618 // group field member name.
619
620 if (get_config().debug)
621 cout << " * group field member: " << value << endl;
622
623 m_field_item_used = true;
624 if (m_pcache_field_group)
625 m_pcache_field_group->set_field_item_string(value.get(), value.size());
626 break;
627 }
628 default:
629 warn_unhandled();
630 }
631 }
632
end_element_s()633 void xlsx_pivot_cache_def_context::end_element_s()
634 {
635 const xml_token_pair_t& parent = get_parent_element();
636 if (parent.first != NS_ooxml_xlsx)
637 return;
638
639 switch (parent.second)
640 {
641 case XML_sharedItems:
642 {
643 if (m_field_item_used)
644 m_pcache.commit_field_item();
645 break;
646 }
647 case XML_groupItems:
648 {
649 if (m_pcache_field_group && m_field_item_used)
650 m_pcache_field_group->commit_field_item();
651 break;
652 }
653 default:
654 ;
655 }
656 }
657
start_element_n(const xml_token_pair_t & parent,const std::vector<xml_token_attr_t> & attrs)658 void xlsx_pivot_cache_def_context::start_element_n(
659 const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
660 {
661 if (parent.first != NS_ooxml_xlsx)
662 {
663 warn_unhandled();
664 return;
665 }
666
667 switch (parent.second)
668 {
669 case XML_sharedItems:
670 {
671 // numeric item of a cache field.
672 double value = 0.0;
673 m_field_item_used = true;
674
675 for_each(attrs.begin(), attrs.end(),
676 [&](const xml_token_attr_t& attr)
677 {
678 if (attr.ns && attr.ns != NS_ooxml_xlsx)
679 return;
680
681 switch (attr.name)
682 {
683 case XML_v:
684 value = to_double(attr.value);
685 break;
686 case XML_u:
687 // flag for unused item.
688 m_field_item_used = !to_bool(attr.value);
689 default:
690 ;
691 }
692 }
693 );
694
695 if (get_config().debug)
696 {
697 cout << " * n: " << value;
698 if (!m_field_item_used)
699 cout << " (unused)";
700 cout << endl;
701
702 }
703
704 if (m_field_item_used)
705 m_pcache.set_field_item_numeric(value);
706
707 break;
708 }
709 default:
710 warn_unhandled();
711 }
712 }
713
end_element_n()714 void xlsx_pivot_cache_def_context::end_element_n()
715 {
716 const xml_token_pair_t& parent = get_parent_element();
717 if (parent.first != NS_ooxml_xlsx)
718 return;
719
720 switch (parent.second)
721 {
722 case XML_sharedItems:
723 {
724 if (m_field_item_used)
725 m_pcache.commit_field_item();
726 break;
727 }
728 default:
729 ;
730 }
731 }
732
start_element_d(const xml_token_pair_t & parent,const std::vector<xml_token_attr_t> & attrs)733 void xlsx_pivot_cache_def_context::start_element_d(
734 const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
735 {
736 if (parent.first != NS_ooxml_xlsx)
737 {
738 warn_unhandled();
739 return;
740 }
741
742 switch (parent.second)
743 {
744 case XML_sharedItems:
745 {
746 // date item of a cache field.
747 date_time_t dt;
748 m_field_item_used = true;
749
750 for_each(attrs.begin(), attrs.end(),
751 [&](const xml_token_attr_t& attr)
752 {
753 if (attr.ns && attr.ns != NS_ooxml_xlsx)
754 return;
755
756 switch (attr.name)
757 {
758 case XML_v:
759 dt = to_date_time(attr.value);
760 break;
761 case XML_u:
762 // flag for unused item.
763 m_field_item_used = !to_bool(attr.value);
764 default:
765 ;
766 }
767 }
768 );
769
770 if (get_config().debug)
771 {
772 cout << " * d: " << dt;
773 if (!m_field_item_used)
774 cout << " (unused)";
775 cout << endl;
776
777 }
778
779 if (m_field_item_used)
780 m_pcache.set_field_item_date_time(dt);
781
782 break;
783 }
784 default:
785 ;
786 }
787 }
788
end_element_d()789 void xlsx_pivot_cache_def_context::end_element_d()
790 {
791 const xml_token_pair_t& parent = get_parent_element();
792 if (parent.first != NS_ooxml_xlsx)
793 return;
794
795 switch (parent.second)
796 {
797 case XML_sharedItems:
798 {
799 if (m_field_item_used)
800 m_pcache.commit_field_item();
801 break;
802 }
803 default:
804 ;
805 }
806 }
807
start_element_e(const xml_token_pair_t & parent,const std::vector<xml_token_attr_t> & attrs)808 void xlsx_pivot_cache_def_context::start_element_e(
809 const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
810 {
811 if (parent.first != NS_ooxml_xlsx)
812 {
813 warn_unhandled();
814 return;
815 }
816
817 switch (parent.second)
818 {
819 case XML_sharedItems:
820 {
821 // error value item of a cache field.
822 spreadsheet::error_value_t ev = spreadsheet::error_value_t::unknown;
823 m_field_item_used = true;
824
825 for_each(attrs.begin(), attrs.end(),
826 [&](const xml_token_attr_t& attr)
827 {
828 if (attr.ns && attr.ns != NS_ooxml_xlsx)
829 return;
830
831 switch (attr.name)
832 {
833 case XML_v:
834 ev = spreadsheet::to_error_value_enum(attr.value.get(), attr.value.size());
835 break;
836 case XML_u:
837 // flag for unused item.
838 m_field_item_used = !to_bool(attr.value);
839 default:
840 ;
841 }
842 }
843 );
844
845 if (get_config().debug)
846 {
847 cout << " * e: " << ev;
848 if (!m_field_item_used)
849 cout << " (unused)";
850 cout << endl;
851 }
852
853 if (m_field_item_used)
854 m_pcache.set_field_item_error(ev);
855
856 break;
857 }
858 default:
859 ;
860 }
861 }
862
end_element_e()863 void xlsx_pivot_cache_def_context::end_element_e()
864 {
865 const xml_token_pair_t& parent = get_parent_element();
866 if (parent.first != NS_ooxml_xlsx)
867 return;
868
869 switch (parent.second)
870 {
871 case XML_sharedItems:
872 {
873 if (m_field_item_used)
874 m_pcache.commit_field_item();
875 break;
876 }
877 default:
878 ;
879 }
880 }
881
start_element_shared_items(const xml_token_pair_t & parent,const std::vector<xml_token_attr_t> & attrs)882 void xlsx_pivot_cache_def_context::start_element_shared_items(
883 const xml_token_pair_t& parent, const std::vector<xml_token_attr_t>& attrs)
884 {
885 xml_element_expected(parent, NS_ooxml_xlsx, XML_cacheField);
886
887 // If "semi-mixed types" is set, the field contains text values and at
888 // least one other type.
889 bool semi_mixed_types = true;
890
891 bool has_non_date = true;
892 bool has_date = false;
893 bool has_string = true;
894 bool has_blank = false;
895
896 // If "mixed types" is set, the field contains more than one data types.
897 bool mixed_types = false;
898
899 bool has_number = false;
900 bool has_integer = false;
901 bool has_long_text = false;
902
903 long count = -1;
904 boost::optional<double> min_value;
905 boost::optional<double> max_value;
906 boost::optional<date_time_t> min_date;
907 boost::optional<date_time_t> max_date;
908
909 for_each(attrs.begin(), attrs.end(),
910 [&](const xml_token_attr_t& attr)
911 {
912 if (attr.ns && attr.ns != NS_ooxml_xlsx)
913 return;
914
915 switch (attr.name)
916 {
917 case XML_count:
918 count = to_long(attr.value);
919 break;
920 case XML_containsMixedTypes:
921 mixed_types = to_bool(attr.value);
922 break;
923 case XML_containsSemiMixedTypes:
924 semi_mixed_types = to_bool(attr.value);
925 break;
926 case XML_containsNonDate:
927 has_non_date = to_bool(attr.value);
928 break;
929 case XML_containsString:
930 has_string = to_bool(attr.value);
931 break;
932 case XML_containsBlank:
933 has_blank = to_bool(attr.value);
934 break;
935 case XML_containsNumber:
936 has_number = to_bool(attr.value);
937 break;
938 case XML_containsInteger:
939 has_integer = to_bool(attr.value);
940 break;
941 case XML_minValue:
942 min_value = to_double(attr.value);
943 break;
944 case XML_maxValue:
945 max_value = to_double(attr.value);
946 break;
947 case XML_minDate:
948 min_date = to_date_time(attr.value);
949 break;
950 case XML_maxDate:
951 max_date = to_date_time(attr.value);
952 break;
953 case XML_longText:
954 has_long_text = to_bool(attr.value);
955 break;
956 default:
957 ;
958 }
959 }
960 );
961
962 if (min_value)
963 m_pcache.set_field_min_value(*min_value);
964
965 if (max_value)
966 m_pcache.set_field_max_value(*max_value);
967
968 if (min_date)
969 m_pcache.set_field_min_date(*min_date);
970
971 if (max_date)
972 m_pcache.set_field_max_date(*max_date);
973
974 if (get_config().debug)
975 {
976 cout << " contains semi-mixed types: " << semi_mixed_types << endl;
977 cout << " contains non-date: " << has_non_date << endl;
978 cout << " contains date: " << has_date << endl;
979 cout << " contains string: " << has_string << endl;
980 cout << " contains blank: " << has_blank << endl;
981 cout << " contains mixed types: " << mixed_types << endl;
982 cout << " contains number: " << has_number << endl;
983 cout << " contains integer: " << has_integer << endl;
984 cout << " contains long text: " << has_long_text << endl;
985 cout << " count: " << count << endl;
986
987 if (min_value)
988 cout << " min value: " << *min_value << endl;
989 if (max_value)
990 cout << " max value: " << *max_value << endl;
991 if (min_date)
992 cout << " min date: " << *min_date << endl;
993 if (max_date)
994 cout << " max date: " << *max_date << endl;
995 }
996 }
997
xlsx_pivot_cache_rec_context(session_context & cxt,const tokens & tokens,spreadsheet::iface::import_pivot_cache_records & pc_records)998 xlsx_pivot_cache_rec_context::xlsx_pivot_cache_rec_context(
999 session_context& cxt, const tokens& tokens,
1000 spreadsheet::iface::import_pivot_cache_records& pc_records) :
1001 xml_context_base(cxt, tokens),
1002 m_pc_records(pc_records) {}
1003
can_handle_element(xmlns_id_t,xml_token_t) const1004 bool xlsx_pivot_cache_rec_context::can_handle_element(xmlns_id_t /*ns*/, xml_token_t /*name*/) const
1005 {
1006 return true;
1007 }
1008
create_child_context(xmlns_id_t,xml_token_t)1009 xml_context_base* xlsx_pivot_cache_rec_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
1010 {
1011 return nullptr;
1012 }
1013
end_child_context(xmlns_id_t,xml_token_t,xml_context_base *)1014 void xlsx_pivot_cache_rec_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
1015 {
1016 }
1017
start_element(xmlns_id_t ns,xml_token_t name,const::std::vector<xml_token_attr_t> & attrs)1018 void xlsx_pivot_cache_rec_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs)
1019 {
1020 xml_token_pair_t parent = push_stack(ns, name);
1021
1022 if (ns != NS_ooxml_xlsx)
1023 return;
1024
1025 switch (name)
1026 {
1027 case XML_pivotCacheRecords:
1028 {
1029 xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
1030 long count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1031
1032 if (get_config().debug)
1033 {
1034 cout << "---" << endl;
1035 cout << "pivot cache record (count: " << count << ")" << endl;
1036 }
1037
1038 m_pc_records.set_record_count(count);
1039 break;
1040 }
1041 case XML_r: // record
1042 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotCacheRecords);
1043 if (get_config().debug)
1044 cout << "* record" << endl;
1045
1046 break;
1047 case XML_s: // character value
1048 {
1049 xml_element_expected(parent, NS_ooxml_xlsx, XML_r);
1050
1051 pstring cv = single_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
1052
1053 if (get_config().debug)
1054 cout << " * s = '" << cv << "'" << endl;
1055
1056 m_pc_records.append_record_value_character(cv.get(), cv.size());
1057 break;
1058 }
1059 case XML_x: // shared item index
1060 {
1061 xml_element_expected(parent, NS_ooxml_xlsx, XML_r);
1062 long v = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
1063 if (get_config().debug)
1064 cout << " * x = " << v << endl;
1065
1066 m_pc_records.append_record_value_shared_item(v);
1067 break;
1068 }
1069 case XML_n: // numeric
1070 {
1071 xml_element_expected(parent, NS_ooxml_xlsx, XML_r);
1072 double val = single_double_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
1073 if (get_config().debug)
1074 cout << " * n = " << val << endl;
1075
1076 m_pc_records.append_record_value_numeric(val);
1077 break;
1078 }
1079 case XML_e: // error value
1080 {
1081 pstring cv = single_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
1082
1083 if (get_config().debug)
1084 cout << " * e = " << cv << endl;
1085
1086 break;
1087 }
1088 case XML_b: // boolean
1089 case XML_d: // date time
1090 case XML_m: // no value
1091 default:
1092 warn_unhandled();
1093 }
1094 }
1095
end_element(xmlns_id_t ns,xml_token_t name)1096 bool xlsx_pivot_cache_rec_context::end_element(xmlns_id_t ns, xml_token_t name)
1097 {
1098 if (ns == NS_ooxml_xlsx)
1099 {
1100 switch (name)
1101 {
1102 case XML_pivotCacheRecords:
1103 m_pc_records.commit();
1104 break;
1105 case XML_r: // record
1106 m_pc_records.commit_record();
1107 break;
1108 default:
1109 ;
1110 }
1111 }
1112
1113 return pop_stack(ns, name);
1114 }
1115
characters(const pstring &,bool)1116 void xlsx_pivot_cache_rec_context::characters(const pstring& /*str*/, bool /*transient*/)
1117 {
1118 }
1119
xlsx_pivot_table_context(session_context & cxt,const tokens & tokens)1120 xlsx_pivot_table_context::xlsx_pivot_table_context(session_context& cxt, const tokens& tokens) :
1121 xml_context_base(cxt, tokens) {}
1122
can_handle_element(xmlns_id_t,xml_token_t) const1123 bool xlsx_pivot_table_context::can_handle_element(xmlns_id_t /*ns*/, xml_token_t /*name*/) const
1124 {
1125 return true;
1126 }
1127
create_child_context(xmlns_id_t,xml_token_t)1128 xml_context_base* xlsx_pivot_table_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
1129 {
1130 return nullptr;
1131 }
1132
end_child_context(xmlns_id_t,xml_token_t,xml_context_base *)1133 void xlsx_pivot_table_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
1134 {
1135 }
1136
start_element(xmlns_id_t ns,xml_token_t name,const::std::vector<xml_token_attr_t> & attrs)1137 void xlsx_pivot_table_context::start_element(xmlns_id_t ns, xml_token_t name, const::std::vector<xml_token_attr_t>& attrs)
1138 {
1139 xml_token_pair_t parent = push_stack(ns, name);
1140 if (ns == NS_ooxml_xlsx)
1141 {
1142 switch (name)
1143 {
1144 case XML_pivotTableDefinition:
1145 {
1146 xml_element_expected(parent, XMLNS_UNKNOWN_ID, XML_UNKNOWN_TOKEN);
1147 if (get_config().debug)
1148 cout << "---" << endl;
1149 for (const xml_token_attr_t& attr : attrs)
1150 {
1151 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1152 continue;
1153
1154 long v = 0;
1155 bool b = false;
1156
1157 switch (attr.name)
1158 {
1159 case XML_name:
1160 if (get_config().debug)
1161 cout << "name: " << attr.value << endl;
1162 break;
1163 case XML_cacheId:
1164 v = to_long(attr.value);
1165 if (get_config().debug)
1166 cout << "cache ID: " << v << endl;
1167 break;
1168 case XML_applyNumberFormats:
1169 b = to_bool(attr.value);
1170 if (get_config().debug)
1171 cout << "apply number formats: " << b << endl;
1172 break;
1173 case XML_applyBorderFormats:
1174 b = to_bool(attr.value);
1175 if (get_config().debug)
1176 cout << "apply border formats: " << b << endl;
1177 break;
1178 case XML_applyFontFormats:
1179 b = to_bool(attr.value);
1180 if (get_config().debug)
1181 cout << "apply font formats: " << b << endl;
1182 break;
1183 case XML_applyPatternFormats:
1184 b = to_bool(attr.value);
1185 if (get_config().debug)
1186 cout << "apply pattern formats: " << b << endl;
1187 break;
1188 case XML_applyAlignmentFormats:
1189 b = to_bool(attr.value);
1190 if (get_config().debug)
1191 cout << "apply alignment formats: " << b << endl;
1192 break;
1193 case XML_applyWidthHeightFormats:
1194 b = to_bool(attr.value);
1195 if (get_config().debug)
1196 cout << "apply width/height formats: " << b << endl;
1197 break;
1198 case XML_dataCaption:
1199 if (get_config().debug)
1200 cout << "data caption: " << attr.value << endl;
1201 break;
1202 case XML_updatedVersion:
1203 v = to_long(attr.value);
1204 if (get_config().debug)
1205 cout << "updated version: " << v << endl;
1206 break;
1207 case XML_minRefreshableVersion:
1208 v = to_long(attr.value);
1209 if (get_config().debug)
1210 cout << "minimum refreshable version: " << v << endl;
1211 break;
1212 case XML_showCalcMbrs:
1213 b = to_bool(attr.value);
1214 if (get_config().debug)
1215 cout << "show calc members (?): " << b << endl;
1216 break;
1217 case XML_useAutoFormatting:
1218 b = to_bool(attr.value);
1219 if (get_config().debug)
1220 cout << "use auto formatting: " << b << endl;
1221 break;
1222 case XML_itemPrintTitles:
1223 b = to_bool(attr.value);
1224 if (get_config().debug)
1225 cout << "item print titles (?): " << b << endl;
1226 break;
1227 case XML_createdVersion:
1228 v = to_long(attr.value);
1229 if (get_config().debug)
1230 cout << "created version: " << v << endl;
1231 break;
1232 case XML_indent:
1233 b = to_bool(attr.value);
1234 if (get_config().debug)
1235 cout << "indent: " << b << endl;
1236 break;
1237 case XML_compact:
1238 b = to_bool(attr.value);
1239 if (get_config().debug)
1240 cout << "compact: " << b << endl;
1241 break;
1242 case XML_compactData:
1243 b = to_bool(attr.value);
1244 if (get_config().debug)
1245 cout << "compact data: " << b << endl;
1246 break;
1247 case XML_outline:
1248 b = to_bool(attr.value);
1249 if (get_config().debug)
1250 cout << "outline: " << b << endl;
1251 break;
1252 case XML_outlineData:
1253 b = to_bool(attr.value);
1254 if (get_config().debug)
1255 cout << "outline data: " << b << endl;
1256 break;
1257 case XML_gridDropZones:
1258 b = to_bool(attr.value);
1259 if (get_config().debug)
1260 cout << "grid drop zones: " << b << endl;
1261 break;
1262 case XML_multipleFieldFilters:
1263 b = to_bool(attr.value);
1264 if (get_config().debug)
1265 cout << "multiple field filters: " << b << endl;
1266 break;
1267 default:
1268 ;
1269 }
1270 }
1271 }
1272 break;
1273 case XML_location:
1274 {
1275 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1276
1277 for (const xml_token_attr_t& attr : attrs)
1278 {
1279 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1280 continue;
1281
1282 long v = -1;
1283 switch (attr.name)
1284 {
1285 case XML_ref:
1286 if (get_config().debug)
1287 cout << "ref: " << attr.value << endl;
1288 break;
1289 case XML_firstHeaderRow:
1290 v = to_long(attr.value);
1291 if (get_config().debug)
1292 cout << "first header row: " << v << endl;
1293 break;
1294 case XML_firstDataRow:
1295 v = to_long(attr.value);
1296 if (get_config().debug)
1297 cout << "first data row: " << v << endl;
1298 break;
1299 case XML_firstDataCol:
1300 v = to_long(attr.value);
1301 if (get_config().debug)
1302 cout << "first data column: " << v << endl;
1303 break;
1304 default:
1305 ;
1306 }
1307 }
1308 }
1309 break;
1310 case XML_pivotFields:
1311 {
1312 // pivotFields and its child elements represent the visual
1313 // appearances of the fields inside pivot table.
1314 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1315 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1316 if (get_config().debug)
1317 cout << "field count: " << count << endl;
1318 }
1319 break;
1320 case XML_pivotField:
1321 {
1322 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotFields);
1323
1324 if (get_config().debug)
1325 cout << "---" << endl;
1326
1327 for (const xml_token_attr_t& attr : attrs)
1328 {
1329 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1330 continue;
1331
1332 switch (attr.name)
1333 {
1334 case XML_axis:
1335 if (get_config().debug)
1336 cout << " * axis: " << attr.value << endl;
1337 break;
1338 case XML_compact:
1339 {
1340 bool b = to_bool(attr.value);
1341 if (get_config().debug)
1342 cout << " * compact: " << b << endl;
1343 }
1344 break;
1345 case XML_outline:
1346 {
1347 bool b = to_bool(attr.value);
1348 if (get_config().debug)
1349 cout << " * outline: " << b << endl;
1350 }
1351 break;
1352 case XML_showAll:
1353 {
1354 bool b = to_bool(attr.value);
1355 if (get_config().debug)
1356 cout << " * show all: " << b << endl;
1357 }
1358 break;
1359 case XML_dataField:
1360 {
1361 bool b = to_bool(attr.value);
1362 if (get_config().debug)
1363 cout << " * data field: " << b << endl;
1364 }
1365 break;
1366 default:
1367 ;
1368 }
1369 }
1370 }
1371 break;
1372 case XML_items:
1373 {
1374 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotField);
1375 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1376 if (get_config().debug)
1377 cout << " * item count: " << count << endl;
1378 }
1379 break;
1380 case XML_item:
1381 {
1382 xml_element_expected(parent, NS_ooxml_xlsx, XML_items);
1383
1384 for (const xml_token_attr_t& attr : attrs)
1385 {
1386 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1387 continue;
1388
1389 switch (attr.name)
1390 {
1391 case XML_x:
1392 {
1393 // field item index as defined in the pivot cache.
1394 long idx = to_long(attr.value);
1395 if (get_config().debug)
1396 cout << " * x = " << idx << endl;
1397 }
1398 break;
1399 case XML_t:
1400 {
1401 // When the <item> element has attribute 't', it's subtotal or
1402 // some sort of function item. See 3.18.45 ST_ItemType
1403 // (PivotItem Type) for possible values.
1404 if (get_config().debug)
1405 cout << " * type = " << attr.value << endl;
1406 }
1407 break;
1408 default:
1409 ;
1410 }
1411 }
1412 }
1413 break;
1414 case XML_rowFields:
1415 {
1416 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1417 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1418 if (get_config().debug)
1419 {
1420 cout << "---" << endl;
1421 cout << "row field count: " << count << endl;
1422 }
1423 }
1424 break;
1425 case XML_colFields:
1426 {
1427 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1428 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1429 if (get_config().debug)
1430 {
1431 cout << "---" << endl;
1432 cout << "column field count: " << count << endl;
1433 }
1434 }
1435 break;
1436 case XML_pageFields:
1437 {
1438 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1439 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1440 if (get_config().debug)
1441 {
1442 cout << "---" << endl;
1443 cout << "page field count: " << count << endl;
1444 }
1445 }
1446 break;
1447 case XML_pageField:
1448 {
1449 xml_element_expected(parent, NS_ooxml_xlsx, XML_pageFields);
1450
1451 if (get_config().debug)
1452 cout << " * page field:";
1453
1454 for (const xml_token_attr_t& attr : attrs)
1455 {
1456 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1457 continue;
1458
1459 switch (attr.name)
1460 {
1461 case XML_fld:
1462 {
1463 long fld = to_long(attr.value);
1464 if (get_config().debug)
1465 cout << "field index = " << fld << "; ";
1466 break;
1467 }
1468 case XML_item:
1469 {
1470 long item = to_long(attr.value);
1471 if (get_config().debug)
1472 cout << "item index = " << item << "; ";
1473 break;
1474 }
1475 case XML_hier:
1476 {
1477 long hier = to_long(attr.value);
1478 // -1 if not applicable.
1479 if (get_config().debug)
1480 cout << "OLAP hierarchy index = " << hier << "; ";
1481 break;
1482 }
1483 default:
1484 ;
1485 }
1486 }
1487
1488 if (get_config().debug)
1489 cout << endl;
1490 break;
1491 }
1492 case XML_field:
1493 {
1494 xml_elem_stack_t expected;
1495 expected.reserve(3);
1496 expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_rowFields));
1497 expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_colFields));
1498 xml_element_expected(parent, expected);
1499
1500 // Index into the list of <pivotField> collection which is
1501 // given earlier under the <pivotFields> element. The value
1502 // of -2 represents a special field that displays the list of
1503 // data fields when the pivot table contains more than one
1504 // data field.
1505 long idx = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_x);
1506 if (get_config().debug)
1507 cout << " * x = " << idx << endl;
1508 }
1509 break;
1510 case XML_dataFields:
1511 {
1512 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1513 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1514 if (get_config().debug)
1515 {
1516 cout << "---" << endl;
1517 cout << "data field count: " << count << endl;
1518 }
1519 }
1520 break;
1521 case XML_dataField:
1522 {
1523 xml_element_expected(parent, NS_ooxml_xlsx, XML_dataFields);
1524
1525 if (get_config().debug)
1526 cout << " * data field: ";
1527
1528 for (const xml_token_attr_t& attr : attrs)
1529 {
1530 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1531 continue;
1532
1533 switch (attr.name)
1534 {
1535 case XML_name:
1536 {
1537 if (get_config().debug)
1538 cout << "name = " << attr.value << "; ";
1539 break;
1540 }
1541 case XML_fld:
1542 {
1543 long fld = to_long(attr.value);
1544 if (get_config().debug)
1545 cout << "field = " << fld << "; ";
1546 break;
1547 }
1548 case XML_baseField:
1549 {
1550 long fld = to_long(attr.value);
1551 if (get_config().debug)
1552 cout << "base field = " << fld << "; ";
1553 break;
1554 }
1555 case XML_baseItem:
1556 {
1557 long fld = to_long(attr.value);
1558 if (get_config().debug)
1559 cout << "base item = " << fld << "; ";
1560 break;
1561 }
1562 case XML_subtotal:
1563 {
1564 if (get_config().debug)
1565 cout << "subtotal = " << attr.value << "; ";
1566 break;
1567 }
1568 default:
1569 ;
1570 }
1571 }
1572
1573 if (get_config().debug)
1574 cout << endl;
1575 }
1576 break;
1577 case XML_rowItems:
1578 {
1579 // <rowItems> structure describes the displayed content of
1580 // cells in the row field area. Each <i> child element
1581 // represents a single row.
1582 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1583 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1584 if (get_config().debug)
1585 {
1586 cout << "---" << endl;
1587 cout << "row item count: " << count << endl;
1588 }
1589 }
1590 break;
1591 case XML_colItems:
1592 {
1593 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1594 size_t count = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_count);
1595 if (get_config().debug)
1596 {
1597 cout << "---" << endl;
1598 cout << "column item count: " << count << endl;
1599 }
1600 }
1601 break;
1602 case XML_i:
1603 {
1604 xml_elem_stack_t expected;
1605 expected.reserve(2);
1606 expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_rowItems));
1607 expected.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_colItems));
1608 xml_element_expected(parent, expected);
1609
1610 if (get_config().debug)
1611 cout << "---" << endl;
1612
1613 for (const xml_token_attr_t& attr : attrs)
1614 {
1615 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1616 continue;
1617
1618 switch (attr.name)
1619 {
1620 case XML_t:
1621 {
1622 // total or subtotal function type.
1623 if (get_config().debug)
1624 cout << " * type = " << attr.value << endl;
1625 }
1626 break;
1627 case XML_r:
1628 {
1629 // "repeated item count" which basically is the number of
1630 // blank cells that occur after the preivous non-empty cell on
1631 // the same row (in the classic layout mode).
1632 long v = to_long(attr.value);
1633 if (get_config().debug)
1634 cout << " * repeat item count = " << v << endl;
1635 }
1636 break;
1637 case XML_i:
1638 {
1639 // zero-based data field index in case of multiple data fields.
1640 long v = to_long(attr.value);
1641 if (get_config().debug)
1642 cout << " * data field index = " << v << endl;
1643 }
1644 break;
1645 default:
1646 ;
1647 }
1648 }
1649 }
1650 break;
1651 case XML_x:
1652 {
1653 if (parent.first != NS_ooxml_xlsx)
1654 {
1655 warn_unhandled();
1656 break;
1657 }
1658
1659 if (parent.second == XML_i)
1660 {
1661 long idx = single_long_attr_getter::get(attrs, NS_ooxml_xlsx, XML_v);
1662 if (idx < 0)
1663 // 0 is default when not set.
1664 idx = 0;
1665
1666 if (get_config().debug)
1667 cout << " * v = " << idx << endl;
1668 break;
1669 }
1670
1671 warn_unhandled();
1672 }
1673 break;
1674 case XML_pivotTableStyleInfo:
1675 {
1676 xml_element_expected(parent, NS_ooxml_xlsx, XML_pivotTableDefinition);
1677
1678 if (get_config().debug)
1679 {
1680 cout << "---" << endl;
1681 cout << "* style info: ";
1682 }
1683
1684 for (const xml_token_attr_t& attr : attrs)
1685 {
1686 if (attr.ns && attr.ns != NS_ooxml_xlsx)
1687 continue;
1688
1689 bool b = false;
1690
1691 switch (attr.name)
1692 {
1693 case XML_name:
1694 if (get_config().debug)
1695 cout << "name='" << attr.value << "'; ";
1696 break;
1697 case XML_showRowHeaders:
1698 b = to_bool(attr.value);
1699 if (get_config().debug)
1700 cout << "show row headers=" << b << "; ";
1701 break;
1702 case XML_showColHeaders:
1703 b = to_bool(attr.value);
1704 if (get_config().debug)
1705 cout << "show column headers=" << b << "; ";
1706 break;
1707 case XML_showRowStripes:
1708 b = to_bool(attr.value);
1709 if (get_config().debug)
1710 cout << "show row stripes=" << b << "; ";
1711 break;
1712 case XML_showColStripes:
1713 b = to_bool(attr.value);
1714 if (get_config().debug)
1715 cout << "show column stripes=" << b << "; ";
1716 break;
1717 case XML_showLastColumn:
1718 b = to_bool(attr.value);
1719 if (get_config().debug)
1720 cout << "show last column=" << b << "; ";
1721 break;
1722 default:
1723 ;
1724 }
1725 }
1726
1727 if (get_config().debug)
1728 cout << endl;
1729 break;
1730 }
1731 default:
1732 warn_unhandled();
1733 }
1734 }
1735 else
1736 warn_unhandled();
1737 }
1738
end_element(xmlns_id_t ns,xml_token_t name)1739 bool xlsx_pivot_table_context::end_element(xmlns_id_t ns, xml_token_t name)
1740 {
1741 return pop_stack(ns, name);
1742 }
1743
characters(const pstring &,bool)1744 void xlsx_pivot_table_context::characters(const pstring& /*str*/, bool /*transient*/)
1745 {
1746 }
1747
1748 }
1749
1750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1751