1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <xepivotxml.hxx>
11 #include <dpcache.hxx>
12 #include <dpobject.hxx>
15 #include <document.hxx>
17 #include <oox/export/utils.hxx>
19 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
20 #include <com/sun/star/sheet/DataPilotOutputRangeType.hpp>
21 #include <com/sun/star/sheet/GeneralFunction.hpp>
23 #include <o3tl/make_unique.hxx>
28 using namespace com::sun::star
;
32 void savePivotCacheRecordsXml( XclExpXmlStream
& rStrm
, const ScDPCache
& rCache
)
34 SCROW nCount
= rCache
.GetDataSize();
35 size_t nFieldCount
= rCache
.GetFieldCount();
37 sax_fastparser::FSHelperPtr
& pRecStrm
= rStrm
.GetCurrentStream();
38 pRecStrm
->startElement(XML_pivotCacheRecords
,
39 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
40 FSNS(XML_xmlns
, XML_r
), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
41 XML_count
, OString::number(static_cast<long>(nCount
)).getStr(),
44 for (SCROW i
= 0; i
< nCount
; ++i
)
46 pRecStrm
->startElement(XML_r
, FSEND
);
47 for (size_t nField
= 0; nField
< nFieldCount
; ++nField
)
49 const ScDPCache::IndexArrayType
* pArray
= rCache
.GetFieldIndexArray(nField
);
51 assert(static_cast<size_t>(i
) < pArray
->size());
52 pRecStrm
->singleElement(XML_x
, XML_v
, OString::number((*pArray
)[i
]), FSEND
);
54 pRecStrm
->endElement(XML_r
);
57 pRecStrm
->endElement(XML_pivotCacheRecords
);
60 const char* toOOXMLAxisType( sheet::DataPilotFieldOrientation eOrient
)
64 case sheet::DataPilotFieldOrientation_COLUMN
:
66 case sheet::DataPilotFieldOrientation_ROW
:
68 case sheet::DataPilotFieldOrientation_PAGE
:
70 case sheet::DataPilotFieldOrientation_DATA
:
72 case sheet::DataPilotFieldOrientation_HIDDEN
:
80 const char* toOOXMLSubtotalType( sheet::GeneralFunction eFunc
)
84 case sheet::GeneralFunction_SUM
:
86 case sheet::GeneralFunction_COUNT
:
88 case sheet::GeneralFunction_AVERAGE
:
90 case sheet::GeneralFunction_MAX
:
92 case sheet::GeneralFunction_MIN
:
94 case sheet::GeneralFunction_PRODUCT
:
96 case sheet::GeneralFunction_COUNTNUMS
:
98 case sheet::GeneralFunction_STDEV
:
100 case sheet::GeneralFunction_STDEVP
:
102 case sheet::GeneralFunction_VAR
:
104 case sheet::GeneralFunction_VARP
:
106 case sheet::GeneralFunction_NONE
:
107 case sheet::GeneralFunction_AUTO
:
116 XclExpXmlPivotCaches::XclExpXmlPivotCaches( const XclExpRoot
& rRoot
) :
119 void XclExpXmlPivotCaches::SaveXml( XclExpXmlStream
& rStrm
)
121 sax_fastparser::FSHelperPtr
& pWorkbookStrm
= rStrm
.GetCurrentStream();
122 pWorkbookStrm
->startElement(XML_pivotCaches
, FSEND
);
124 for (size_t i
= 0, n
= maCaches
.size(); i
< n
; ++i
)
126 const Entry
& rEntry
= maCaches
[i
];
128 sal_Int32 nCacheId
= i
+ 1;
130 sax_fastparser::FSHelperPtr pPCStrm
= rStrm
.CreateOutputStream(
131 XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheDefinition", nCacheId
),
132 XclXmlUtils::GetStreamName(nullptr, "pivotCache/pivotCacheDefinition", nCacheId
),
133 rStrm
.GetCurrentStream()->getOutputStream(),
134 CREATE_XL_CONTENT_TYPE("pivotCacheDefinition"),
135 CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
138 pWorkbookStrm
->singleElement(XML_pivotCache
,
139 XML_cacheId
, OString::number(nCacheId
).getStr(),
140 FSNS(XML_r
, XML_id
), XclXmlUtils::ToOString(aRelId
).getStr(),
143 rStrm
.PushStream(pPCStrm
);
144 SavePivotCacheXml(rStrm
, rEntry
, nCacheId
);
148 pWorkbookStrm
->endElement(XML_pivotCaches
);
151 void XclExpXmlPivotCaches::SetCaches( const std::vector
<Entry
>& rCaches
)
156 bool XclExpXmlPivotCaches::HasCaches() const
158 return !maCaches
.empty();
161 const XclExpXmlPivotCaches::Entry
* XclExpXmlPivotCaches::GetCache( sal_Int32 nCacheId
) const
164 // cache ID is 1-based.
167 size_t nPos
= nCacheId
- 1;
168 if (nPos
>= maCaches
.size())
171 return &maCaches
[nPos
];
174 void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream
& rStrm
, const Entry
& rEntry
, sal_Int32 nCounter
)
176 assert(rEntry
.mpCache
);
177 const ScDPCache
& rCache
= *rEntry
.mpCache
;
179 sax_fastparser::FSHelperPtr
& pDefStrm
= rStrm
.GetCurrentStream();
182 sax_fastparser::FSHelperPtr pRecStrm
= rStrm
.CreateOutputStream(
183 XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheRecords", nCounter
),
184 XclXmlUtils::GetStreamName(nullptr, "pivotCacheRecords", nCounter
),
185 pDefStrm
->getOutputStream(),
186 CREATE_XL_CONTENT_TYPE("pivotCacheRecords"),
187 CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheRecords"),
190 rStrm
.PushStream(pRecStrm
);
191 savePivotCacheRecordsXml(rStrm
, rCache
);
194 pDefStrm
->startElement(XML_pivotCacheDefinition
,
195 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
196 FSNS(XML_xmlns
, XML_r
), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
197 FSNS(XML_r
, XML_id
), XclXmlUtils::ToOString(aRelId
).getStr(),
198 XML_recordCount
, OString::number(rEntry
.mpCache
->GetDataSize()).getStr(),
201 if (rEntry
.meType
== Worksheet
)
203 pDefStrm
->startElement(XML_cacheSource
,
204 XML_type
, "worksheet",
208 GetDoc().GetName(rEntry
.maSrcRange
.aStart
.Tab(), aSheetName
);
209 pDefStrm
->singleElement(XML_worksheetSource
,
210 XML_ref
, XclXmlUtils::ToOString(rEntry
.maSrcRange
).getStr(),
211 XML_sheet
, XclXmlUtils::ToOString(aSheetName
).getStr(),
214 pDefStrm
->endElement(XML_cacheSource
);
217 size_t nCount
= rCache
.GetFieldCount();
218 pDefStrm
->startElement(XML_cacheFields
,
219 XML_count
, OString::number(static_cast<long>(nCount
)).getStr(),
222 for (size_t i
= 0; i
< nCount
; ++i
)
224 OUString aName
= rCache
.GetDimensionName(i
);
226 pDefStrm
->startElement(XML_cacheField
,
227 XML_name
, XclXmlUtils::ToOString(aName
).getStr(),
228 XML_numFmtId
, OString::number(0).getStr(),
231 const ScDPCache::ScDPItemDataVec
& rFieldItems
= rCache
.GetDimMemberValues(i
);
233 ScDPCache::ScDPItemDataVec::const_iterator it
= rFieldItems
.begin(), itEnd
= rFieldItems
.end();
235 std::set
<ScDPItemData::Type
> aDPTypes
;
236 for (; it
!= itEnd
; ++it
)
238 aDPTypes
.insert(it
->GetType());
241 auto aDPTypeEnd
= aDPTypes
.cend();
243 pDefStrm
->startElement(XML_sharedItems
,
244 XML_count
, OString::number(static_cast<long>(rFieldItems
.size())).getStr(),
245 XML_containsMixedTypes
, XclXmlUtils::ToPsz10(aDPTypes
.size() > 1),
246 XML_containsSemiMixedTypes
, XclXmlUtils::ToPsz10(aDPTypes
.size() > 1),
247 XML_containsString
, XclXmlUtils::ToPsz10(aDPTypes
.find(ScDPItemData::String
) != aDPTypeEnd
),
248 XML_containsNumber
, XclXmlUtils::ToPsz10(aDPTypes
.find(ScDPItemData::Value
) != aDPTypeEnd
),
251 it
= rFieldItems
.begin();
252 for (; it
!= itEnd
; ++it
)
254 const ScDPItemData
& rItem
= *it
;
255 switch (rItem
.GetType())
257 case ScDPItemData::String
:
258 pDefStrm
->singleElement(XML_s
,
259 XML_v
, XclXmlUtils::ToOString(rItem
.GetString()).getStr(),
262 case ScDPItemData::Value
:
263 pDefStrm
->singleElement(XML_n
,
264 XML_v
, OString::number(rItem
.GetValue()).getStr(),
267 case ScDPItemData::Empty
:
268 pDefStrm
->singleElement(XML_m
, FSEND
);
270 case ScDPItemData::Error
:
271 pDefStrm
->singleElement(XML_e
,
272 XML_v
, XclXmlUtils::ToOString(rItem
.GetString()).getStr(),
275 case ScDPItemData::GroupValue
:
276 case ScDPItemData::RangeStart
:
277 // TODO : What do we do with these types?
278 pDefStrm
->singleElement(XML_m
, FSEND
);
285 pDefStrm
->endElement(XML_sharedItems
);
286 pDefStrm
->endElement(XML_cacheField
);
289 pDefStrm
->endElement(XML_cacheFields
);
291 pDefStrm
->endElement(XML_pivotCacheDefinition
);
294 XclExpXmlPivotTableManager::XclExpXmlPivotTableManager( const XclExpRoot
& rRoot
) :
295 XclExpRoot(rRoot
), maCaches(rRoot
) {}
297 void XclExpXmlPivotTableManager::Initialize()
299 const ScDocument
& rDoc
= GetDoc();
300 if (!rDoc
.HasPivotTable())
301 // No pivot table to export.
304 const ScDPCollection
* pDPColl
= rDoc
.GetDPCollection();
308 // Go through the caches first.
310 std::vector
<XclExpXmlPivotCaches::Entry
> aCaches
;
311 const ScDPCollection::SheetCaches
& rSheetCaches
= pDPColl
->GetSheetCaches();
312 const std::vector
<ScRange
>& rRanges
= rSheetCaches
.getAllRanges();
313 for (const auto & rRange
: rRanges
)
315 const ScDPCache
* pCache
= rSheetCaches
.getExistingCache(rRange
);
319 // Get all pivot objects that reference this cache, and set up an
320 // object to cache ID mapping.
321 const ScDPCache::ScDPObjectSet
& rRefs
= pCache
->GetAllReferences();
322 ScDPCache::ScDPObjectSet::const_iterator it
= rRefs
.begin(), itEnd
= rRefs
.end();
323 for (; it
!= itEnd
; ++it
)
324 maCacheIdMap
.insert(CacheIdMapType::value_type(*it
, aCaches
.size()+1));
326 XclExpXmlPivotCaches::Entry aEntry
;
327 aEntry
.meType
= XclExpXmlPivotCaches::Worksheet
;
328 aEntry
.mpCache
= pCache
;
329 aEntry
.maSrcRange
= rRange
;
330 aCaches
.push_back(aEntry
); // Cache ID equals position + 1.
333 // TODO : Handle name and database caches as well.
335 for (size_t i
= 0, n
= pDPColl
->GetCount(); i
< n
; ++i
)
337 const ScDPObject
& rDPObj
= (*pDPColl
)[i
];
339 // Get the cache ID for this pivot table.
340 CacheIdMapType::iterator itCache
= maCacheIdMap
.find(&rDPObj
);
341 if (itCache
== maCacheIdMap
.end())
342 // No cache ID found. Something is wrong here....
345 sal_Int32 nCacheId
= itCache
->second
;
346 SCTAB nTab
= rDPObj
.GetOutRange().aStart
.Tab();
348 TablesType::iterator it
= m_Tables
.find(nTab
);
349 if (it
== m_Tables
.end())
351 // Insert a new instance for this sheet index.
352 std::pair
<TablesType::iterator
, bool> r
=
353 m_Tables
.insert(std::make_pair(nTab
, o3tl::make_unique
<XclExpXmlPivotTables
>(GetRoot(), maCaches
)));
357 XclExpXmlPivotTables
*const p
= it
->second
.get();
358 p
->AppendTable(&rDPObj
, nCacheId
, i
+1);
361 maCaches
.SetCaches(aCaches
);
364 XclExpXmlPivotCaches
& XclExpXmlPivotTableManager::GetCaches()
369 XclExpXmlPivotTables
* XclExpXmlPivotTableManager::GetTablesBySheet( SCTAB nTab
)
371 TablesType::iterator
const it
= m_Tables
.find(nTab
);
372 return it
== m_Tables
.end() ? nullptr : it
->second
.get();
375 XclExpXmlPivotTables::Entry::Entry( const ScDPObject
* pTable
, sal_Int32 nCacheId
, sal_Int32 nPivotId
) :
376 mpTable(pTable
), mnCacheId(nCacheId
), mnPivotId(nPivotId
) {}
378 XclExpXmlPivotTables::XclExpXmlPivotTables( const XclExpRoot
& rRoot
, const XclExpXmlPivotCaches
& rCaches
) :
379 XclExpRoot(rRoot
), mrCaches(rCaches
) {}
381 void XclExpXmlPivotTables::SaveXml( XclExpXmlStream
& rStrm
)
383 sax_fastparser::FSHelperPtr
& pWSStrm
= rStrm
.GetCurrentStream(); // worksheet stream
385 sal_Int32 nCounter
= 1; // 1-based
386 TablesType::iterator it
= maTables
.begin(), itEnd
= maTables
.end();
387 for (; it
!= itEnd
; ++it
, ++nCounter
)
389 const ScDPObject
& rObj
= *it
->mpTable
;
390 sal_Int32 nCacheId
= it
->mnCacheId
;
391 sal_Int32 nPivotId
= it
->mnPivotId
;
393 sax_fastparser::FSHelperPtr pPivotStrm
= rStrm
.CreateOutputStream(
394 XclXmlUtils::GetStreamName("xl/pivotTables/", "pivotTable", nPivotId
),
395 XclXmlUtils::GetStreamName(nullptr, "../pivotTables/pivotTable", nPivotId
),
396 pWSStrm
->getOutputStream(),
397 CREATE_XL_CONTENT_TYPE("pivotTable"),
398 CREATE_OFFICEDOC_RELATION_TYPE("pivotTable"));
400 rStrm
.PushStream(pPivotStrm
);
401 SavePivotTableXml(rStrm
, rObj
, nCacheId
);
410 long mnPos
; // field index in pivot cache.
411 const ScDPSaveDimension
* mpDim
;
413 DataField( long nPos
, const ScDPSaveDimension
* pDim
) : mnPos(nPos
), mpDim(pDim
) {}
418 void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream
& rStrm
, const ScDPObject
& rDPObj
, sal_Int32 nCacheId
)
420 typedef std::unordered_map
<OUString
, long, OUStringHash
> NameToIdMapType
;
422 const XclExpXmlPivotCaches::Entry
* pCacheEntry
= mrCaches
.GetCache(nCacheId
);
424 // Something is horribly wrong. Check your logic.
427 const ScDPCache
& rCache
= *pCacheEntry
->mpCache
;
429 const ScDPSaveData
& rSaveData
= *rDPObj
.GetSaveData();
431 size_t nFieldCount
= rCache
.GetFieldCount();
432 std::vector
<const ScDPSaveDimension
*> aCachedDims
;
433 NameToIdMapType aNameToIdMap
;
435 aCachedDims
.reserve(nFieldCount
);
436 for (size_t i
= 0; i
< nFieldCount
; ++i
)
438 OUString aName
= rCache
.GetDimensionName(i
);
439 aNameToIdMap
.insert(NameToIdMapType::value_type(aName
, aCachedDims
.size()));
440 const ScDPSaveDimension
* pDim
= rSaveData
.GetExistingDimensionByName(aName
);
441 aCachedDims
.push_back(pDim
);
444 std::vector
<long> aRowFields
;
445 std::vector
<long> aColFields
;
446 std::vector
<long> aPageFields
;
447 std::vector
<DataField
> aDataFields
;
449 // Use dimensions in the save data to get their correct ordering.
450 // Dimension order here is significant as they specify the order of
451 // appearance in each axis.
452 const ScDPSaveData::DimsType
& rDims
= rSaveData
.GetDimensions();
454 for (const auto & i
: rDims
)
456 const ScDPSaveDimension
& rDim
= *i
;
458 long nPos
= -1; // position in cache
459 if (rDim
.IsDataLayout())
460 nPos
= -2; // Excel uses an index of -2 to indicate a data layout field.
463 OUString aSrcName
= ScDPUtil::getSourceDimensionName(rDim
.GetName());
464 NameToIdMapType::iterator it
= aNameToIdMap
.find(aSrcName
);
465 if (it
!= aNameToIdMap
.end())
471 if (!aCachedDims
[nPos
])
475 sheet::DataPilotFieldOrientation eOrient
=
476 static_cast<sheet::DataPilotFieldOrientation
>(rDim
.GetOrientation());
480 case sheet::DataPilotFieldOrientation_COLUMN
:
481 aColFields
.push_back(nPos
);
483 case sheet::DataPilotFieldOrientation_ROW
:
484 aRowFields
.push_back(nPos
);
486 case sheet::DataPilotFieldOrientation_PAGE
:
487 aPageFields
.push_back(nPos
);
489 case sheet::DataPilotFieldOrientation_DATA
:
490 aDataFields
.push_back(DataField(nPos
, &rDim
));
492 case sheet::DataPilotFieldOrientation_HIDDEN
:
498 sax_fastparser::FSHelperPtr
& pPivotStrm
= rStrm
.GetCurrentStream();
499 pPivotStrm
->startElement(XML_pivotTableDefinition
,
500 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
501 XML_name
, XclXmlUtils::ToOString(rDPObj
.GetName()).getStr(),
502 XML_cacheId
, OString::number(nCacheId
).getStr(),
503 XML_applyNumberFormats
, BS(false),
504 XML_applyBorderFormats
, BS(false),
505 XML_applyFontFormats
, BS(false),
506 XML_applyPatternFormats
, BS(false),
507 XML_applyAlignmentFormats
, BS(false),
508 XML_applyWidthHeightFormats
, BS(false),
509 XML_dataCaption
, "Values",
510 XML_useAutoFormatting
, BS(false),
511 XML_itemPrintTitles
, BS(true),
512 XML_indent
, BS(false),
513 XML_outline
, BS(true),
514 XML_outlineData
, BS(true),
517 // NB: Excel's range does not include page field area (if any).
518 ScRange aOutRange
= rDPObj
.GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE
);
520 sal_Int32 nFirstHeaderRow
= aColFields
.size();
521 sal_Int32 nFirstDataRow
= 2;
522 sal_Int32 nFirstDataCol
= 1;
523 ScRange aResRange
= rDPObj
.GetOutputRangeByType(sheet::DataPilotOutputRangeType::RESULT
);
524 if (aOutRange
.IsValid() && aResRange
.IsValid())
526 nFirstDataRow
= aResRange
.aStart
.Row() - aOutRange
.aStart
.Row();
527 nFirstDataCol
= aResRange
.aStart
.Col() - aOutRange
.aStart
.Col();
530 if (!aOutRange
.IsValid())
531 aOutRange
= rDPObj
.GetOutRange();
533 pPivotStrm
->write("<")->writeId(XML_location
);
534 rStrm
.WriteAttributes(XML_ref
,
535 XclXmlUtils::ToOString(aOutRange
),
536 XML_firstHeaderRow
, OString::number(nFirstHeaderRow
).getStr(),
537 XML_firstDataRow
, OString::number(nFirstDataRow
).getStr(),
538 XML_firstDataCol
, OString::number(nFirstDataCol
).getStr(),
541 if (!aPageFields
.empty())
543 rStrm
.WriteAttributes(XML_rowPageCount
, OString::number(static_cast<long>(aPageFields
.size())).getStr(), FSEND
);
544 rStrm
.WriteAttributes(XML_colPageCount
, OString::number(1).getStr(), FSEND
);
547 pPivotStrm
->write("/>");
549 // <pivotFields> - It must contain all fields in the pivot cache even if
550 // only some of them are used in the pivot table. The order must be as
551 // they appear in the cache.
553 pPivotStrm
->startElement(XML_pivotFields
,
554 XML_count
, OString::number(static_cast<long>(aCachedDims
.size())).getStr(),
557 for (const ScDPSaveDimension
* pDim
: aCachedDims
)
561 pPivotStrm
->singleElement(XML_pivotField
,
562 XML_showAll
, BS(false),
567 sheet::DataPilotFieldOrientation eOrient
=
568 static_cast<sheet::DataPilotFieldOrientation
>(pDim
->GetOrientation());
570 if (eOrient
== sheet::DataPilotFieldOrientation_HIDDEN
)
572 pPivotStrm
->singleElement(XML_pivotField
,
573 XML_showAll
, BS(false),
578 if (eOrient
== sheet::DataPilotFieldOrientation_DATA
)
580 pPivotStrm
->singleElement(XML_pivotField
,
581 XML_dataField
, BS(true),
582 XML_showAll
, BS(false),
588 pPivotStrm
->startElement(XML_pivotField
,
589 XML_axis
, toOOXMLAxisType(eOrient
),
590 XML_showAll
, BS(false),
593 // TODO : Dump field items.
595 pPivotStrm
->endElement(XML_pivotField
);
598 pPivotStrm
->endElement(XML_pivotFields
);
602 if (!aRowFields
.empty())
604 pPivotStrm
->startElement(XML_rowFields
,
605 XML_count
, OString::number(static_cast<long>(aRowFields
.size())),
608 std::vector
<long>::iterator it
= aRowFields
.begin(), itEnd
= aRowFields
.end();
609 for (; it
!= itEnd
; ++it
)
611 pPivotStrm
->singleElement(XML_field
,
612 XML_x
, OString::number(*it
),
616 pPivotStrm
->endElement(XML_rowFields
);
623 if (!aColFields
.empty())
625 pPivotStrm
->startElement(XML_colFields
,
626 XML_count
, OString::number(static_cast<long>(aColFields
.size())),
629 std::vector
<long>::iterator it
= aColFields
.begin(), itEnd
= aColFields
.end();
630 for (; it
!= itEnd
; ++it
)
632 pPivotStrm
->singleElement(XML_field
,
633 XML_x
, OString::number(*it
),
637 pPivotStrm
->endElement(XML_colFields
);
644 if (!aPageFields
.empty())
646 pPivotStrm
->startElement(XML_pageFields
,
647 XML_count
, OString::number(static_cast<long>(aPageFields
.size())),
650 std::vector
<long>::iterator it
= aPageFields
.begin(), itEnd
= aPageFields
.end();
651 for (; it
!= itEnd
; ++it
)
653 pPivotStrm
->singleElement(XML_pageField
,
654 XML_fld
, OString::number(*it
),
655 XML_hier
, OString::number(-1), // TODO : handle this correctly.
659 pPivotStrm
->endElement(XML_pageFields
);
664 if (!aDataFields
.empty())
666 pPivotStrm
->startElement(XML_dataFields
,
667 XML_count
, OString::number(static_cast<long>(aDataFields
.size())),
670 std::vector
<DataField
>::iterator it
= aDataFields
.begin(), itEnd
= aDataFields
.end();
671 for (; it
!= itEnd
; ++it
)
673 long nDimIdx
= it
->mnPos
;
674 assert(aCachedDims
[nDimIdx
]); // the loop above should have screened for NULL's.
675 const ScDPSaveDimension
& rDim
= *it
->mpDim
;
676 const OUString
* pName
= rDim
.GetLayoutName();
677 pPivotStrm
->write("<")->writeId(XML_dataField
);
679 rStrm
.WriteAttributes(XML_name
, XclXmlUtils::ToOString(*pName
), FSEND
);
681 rStrm
.WriteAttributes(XML_fld
, OString::number(nDimIdx
).getStr(), FSEND
);
683 sheet::GeneralFunction eFunc
= static_cast<sheet::GeneralFunction
>(rDim
.GetFunction());
684 const char* pSubtotal
= toOOXMLSubtotalType(eFunc
);
686 rStrm
.WriteAttributes(XML_subtotal
, pSubtotal
, FSEND
);
688 pPivotStrm
->write("/>");
691 pPivotStrm
->endElement(XML_dataFields
);
694 OUStringBuffer
aBuf("../pivotCache/pivotCacheDefinition");
695 aBuf
.append(nCacheId
);
699 pPivotStrm
->getOutputStream(),
700 CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
701 aBuf
.makeStringAndClear());
703 pPivotStrm
->endElement(XML_pivotTableDefinition
);
706 void XclExpXmlPivotTables::AppendTable( const ScDPObject
* pTable
, sal_Int32 nCacheId
, sal_Int32 nPivotId
)
708 maTables
.push_back(Entry(pTable
, nCacheId
, nPivotId
));
711 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */