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>
26 using namespace com::sun::star
;
30 void savePivotCacheRecordsXml( XclExpXmlStream
& rStrm
, const ScDPCache
& rCache
)
32 SCROW nCount
= rCache
.GetDataSize();
33 size_t nFieldCount
= rCache
.GetFieldCount();
35 sax_fastparser::FSHelperPtr
& pRecStrm
= rStrm
.GetCurrentStream();
36 pRecStrm
->startElement(XML_pivotCacheRecords
,
37 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
38 FSNS(XML_xmlns
, XML_r
), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
39 XML_count
, OString::number(static_cast<long>(nCount
)).getStr(),
42 for (SCROW i
= 0; i
< nCount
; ++i
)
44 pRecStrm
->startElement(XML_r
, FSEND
);
45 for (size_t nField
= 0; nField
< nFieldCount
; ++nField
)
47 const ScDPCache::IndexArrayType
* pArray
= rCache
.GetFieldIndexArray(nField
);
49 assert(static_cast<size_t>(i
) < pArray
->size());
50 pRecStrm
->singleElement(XML_x
, XML_v
, OString::number((*pArray
)[i
]), FSEND
);
52 pRecStrm
->endElement(XML_r
);
55 pRecStrm
->endElement(XML_pivotCacheRecords
);
58 const char* toOOXMLAxisType( sheet::DataPilotFieldOrientation eOrient
)
62 case sheet::DataPilotFieldOrientation_COLUMN
:
64 case sheet::DataPilotFieldOrientation_ROW
:
66 case sheet::DataPilotFieldOrientation_PAGE
:
68 case sheet::DataPilotFieldOrientation_DATA
:
70 case sheet::DataPilotFieldOrientation_HIDDEN
:
78 const char* toOOXMLSubtotalType( sheet::GeneralFunction eFunc
)
82 case sheet::GeneralFunction_SUM
:
84 case sheet::GeneralFunction_COUNT
:
86 case sheet::GeneralFunction_AVERAGE
:
88 case sheet::GeneralFunction_MAX
:
90 case sheet::GeneralFunction_MIN
:
92 case sheet::GeneralFunction_PRODUCT
:
94 case sheet::GeneralFunction_COUNTNUMS
:
96 case sheet::GeneralFunction_STDEV
:
98 case sheet::GeneralFunction_STDEVP
:
100 case sheet::GeneralFunction_VAR
:
102 case sheet::GeneralFunction_VARP
:
104 case sheet::GeneralFunction_NONE
:
105 case sheet::GeneralFunction_AUTO
:
114 XclExpXmlPivotCaches::XclExpXmlPivotCaches( const XclExpRoot
& rRoot
) :
117 void XclExpXmlPivotCaches::SaveXml( XclExpXmlStream
& rStrm
)
119 sax_fastparser::FSHelperPtr
& pWorkbookStrm
= rStrm
.GetCurrentStream();
120 pWorkbookStrm
->startElement(XML_pivotCaches
, FSEND
);
122 for (size_t i
= 0, n
= maCaches
.size(); i
< n
; ++i
)
124 const Entry
& rEntry
= maCaches
[i
];
126 sal_Int32 nCacheId
= i
+ 1;
128 sax_fastparser::FSHelperPtr pPCStrm
= rStrm
.CreateOutputStream(
129 XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheDefinition", nCacheId
),
130 XclXmlUtils::GetStreamName(NULL
, "pivotCache/pivotCacheDefinition", nCacheId
),
131 rStrm
.GetCurrentStream()->getOutputStream(),
132 CREATE_XL_CONTENT_TYPE("pivotCacheDefinition"),
133 CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
136 pWorkbookStrm
->singleElement(XML_pivotCache
,
137 XML_cacheId
, OString::number(nCacheId
).getStr(),
138 FSNS(XML_r
, XML_id
), XclXmlUtils::ToOString(aRelId
).getStr(),
141 rStrm
.PushStream(pPCStrm
);
142 SavePivotCacheXml(rStrm
, rEntry
, nCacheId
);
146 pWorkbookStrm
->endElement(XML_pivotCaches
);
149 void XclExpXmlPivotCaches::SetCaches( const std::vector
<Entry
>& rCaches
)
154 bool XclExpXmlPivotCaches::HasCaches() const
156 return !maCaches
.empty();
159 const XclExpXmlPivotCaches::Entry
* XclExpXmlPivotCaches::GetCache( sal_Int32 nCacheId
) const
162 // cache ID is 1-based.
165 size_t nPos
= nCacheId
- 1;
166 if (nPos
>= maCaches
.size())
169 return &maCaches
[nPos
];
172 void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream
& rStrm
, const Entry
& rEntry
, sal_Int32 nCounter
)
174 assert(rEntry
.mpCache
);
175 const ScDPCache
& rCache
= *rEntry
.mpCache
;
177 sax_fastparser::FSHelperPtr
& pDefStrm
= rStrm
.GetCurrentStream();
180 sax_fastparser::FSHelperPtr pRecStrm
= rStrm
.CreateOutputStream(
181 XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheRecords", nCounter
),
182 XclXmlUtils::GetStreamName(NULL
, "pivotCacheRecords", nCounter
),
183 pDefStrm
->getOutputStream(),
184 CREATE_XL_CONTENT_TYPE("pivotCacheRecords"),
185 CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheRecords"),
188 rStrm
.PushStream(pRecStrm
);
189 savePivotCacheRecordsXml(rStrm
, rCache
);
192 pDefStrm
->startElement(XML_pivotCacheDefinition
,
193 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
194 FSNS(XML_xmlns
, XML_r
), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
195 FSNS(XML_r
, XML_id
), XclXmlUtils::ToOString(aRelId
).getStr(),
196 XML_recordCount
, OString::number(rEntry
.mpCache
->GetDataSize()).getStr(),
199 if (rEntry
.meType
== Worksheet
)
201 pDefStrm
->startElement(XML_cacheSource
,
202 XML_type
, "worksheet",
206 GetDoc().GetName(rEntry
.maSrcRange
.aStart
.Tab(), aSheetName
);
207 pDefStrm
->singleElement(XML_worksheetSource
,
208 XML_ref
, XclXmlUtils::ToOString(rEntry
.maSrcRange
).getStr(),
209 XML_sheet
, XclXmlUtils::ToOString(aSheetName
).getStr(),
212 pDefStrm
->endElement(XML_cacheSource
);
215 size_t nCount
= rCache
.GetFieldCount();
216 pDefStrm
->startElement(XML_cacheFields
,
217 XML_count
, OString::number(static_cast<long>(nCount
)).getStr(),
220 for (size_t i
= 0; i
< nCount
; ++i
)
222 OUString aName
= rCache
.GetDimensionName(i
);
224 pDefStrm
->startElement(XML_cacheField
,
225 XML_name
, XclXmlUtils::ToOString(aName
).getStr(),
226 XML_numFmtId
, OString::number(0).getStr(),
229 const ScDPCache::ItemsType
& rFieldItems
= rCache
.GetDimMemberValues(i
);
231 pDefStrm
->startElement(XML_sharedItems
,
232 XML_count
, OString::number(static_cast<long>(rFieldItems
.size())).getStr(),
235 ScDPCache::ItemsType::const_iterator it
= rFieldItems
.begin(), itEnd
= rFieldItems
.end();
236 for (; it
!= itEnd
; ++it
)
238 const ScDPItemData
& rItem
= *it
;
239 switch (rItem
.GetType())
241 case ScDPItemData::String
:
242 pDefStrm
->singleElement(XML_s
,
243 XML_v
, XclXmlUtils::ToOString(rItem
.GetString()).getStr(),
246 case ScDPItemData::Value
:
247 pDefStrm
->singleElement(XML_n
,
248 XML_v
, OString::number(rItem
.GetValue()).getStr(),
251 case ScDPItemData::Empty
:
252 pDefStrm
->singleElement(XML_m
, FSEND
);
254 case ScDPItemData::Error
:
255 pDefStrm
->singleElement(XML_e
,
256 XML_v
, XclXmlUtils::ToOString(rItem
.GetString()).getStr(),
259 case ScDPItemData::GroupValue
:
260 case ScDPItemData::RangeStart
:
261 // TODO : What do we do with these types?
262 pDefStrm
->singleElement(XML_m
, FSEND
);
269 pDefStrm
->endElement(XML_sharedItems
);
270 pDefStrm
->endElement(XML_cacheField
);
273 pDefStrm
->endElement(XML_cacheFields
);
275 pDefStrm
->endElement(XML_pivotCacheDefinition
);
278 XclExpXmlPivotTableManager::XclExpXmlPivotTableManager( const XclExpRoot
& rRoot
) :
279 XclExpRoot(rRoot
), maCaches(rRoot
) {}
281 void XclExpXmlPivotTableManager::Initialize()
283 const ScDocument
& rDoc
= GetDoc();
284 if (!rDoc
.HasPivotTable())
285 // No pivot table to export.
288 const ScDPCollection
* pDPColl
= rDoc
.GetDPCollection();
292 // Go through the caches first.
294 std::vector
<XclExpXmlPivotCaches::Entry
> aCaches
;
295 const ScDPCollection::SheetCaches
& rSheetCaches
= pDPColl
->GetSheetCaches();
296 const std::vector
<ScRange
>& rRanges
= rSheetCaches
.getAllRanges();
297 for (size_t i
= 0, n
= rRanges
.size(); i
< n
; ++i
)
299 const ScDPCache
* pCache
= rSheetCaches
.getExistingCache(rRanges
[i
]);
303 // Get all pivot objects that reference this cache, and set up an
304 // object to cache ID mapping.
305 const ScDPCache::ObjectSetType
& rRefs
= pCache
->GetAllReferences();
306 ScDPCache::ObjectSetType::const_iterator it
= rRefs
.begin(), itEnd
= rRefs
.end();
307 for (; it
!= itEnd
; ++it
)
308 maCacheIdMap
.insert(CacheIdMapType::value_type(*it
, aCaches
.size()+1));
310 XclExpXmlPivotCaches::Entry aEntry
;
311 aEntry
.meType
= XclExpXmlPivotCaches::Worksheet
;
312 aEntry
.mpCache
= pCache
;
313 aEntry
.maSrcRange
= rRanges
[i
];
314 aCaches
.push_back(aEntry
); // Cache ID equals position + 1.
317 // TODO : Handle name and database caches as well.
319 for (size_t i
= 0, n
= pDPColl
->GetCount(); i
< n
; ++i
)
321 const ScDPObject
* pDPObj
= (*pDPColl
)[i
];
322 assert(pDPObj
); // We don't store NULL here.
324 // Get the cache ID for this pivot table.
325 CacheIdMapType::iterator itCache
= maCacheIdMap
.find(pDPObj
);
326 if (itCache
== maCacheIdMap
.end())
327 // No cache ID found. Something is wrong here....
330 sal_Int32 nCacheId
= itCache
->second
;
331 SCTAB nTab
= pDPObj
->GetOutRange().aStart
.Tab();
333 TablesType::iterator it
= maTables
.find(nTab
);
334 if (it
== maTables
.end())
336 // Insert a new instance for this sheet index.
337 std::pair
<TablesType::iterator
, bool> r
=
338 maTables
.insert(nTab
, new XclExpXmlPivotTables(GetRoot(), maCaches
));
342 XclExpXmlPivotTables
* p
= it
->second
;
343 p
->AppendTable(pDPObj
, nCacheId
, i
+1);
346 maCaches
.SetCaches(aCaches
);
349 XclExpXmlPivotCaches
& XclExpXmlPivotTableManager::GetCaches()
354 XclExpXmlPivotTables
* XclExpXmlPivotTableManager::GetTablesBySheet( SCTAB nTab
)
356 TablesType::iterator it
= maTables
.find(nTab
);
357 return it
== maTables
.end() ? NULL
: it
->second
;
360 XclExpXmlPivotTables::Entry::Entry( const ScDPObject
* pTable
, sal_Int32 nCacheId
, sal_Int32 nPivotId
) :
361 mpTable(pTable
), mnCacheId(nCacheId
), mnPivotId(nPivotId
) {}
363 XclExpXmlPivotTables::XclExpXmlPivotTables( const XclExpRoot
& rRoot
, const XclExpXmlPivotCaches
& rCaches
) :
364 XclExpRoot(rRoot
), mrCaches(rCaches
) {}
366 void XclExpXmlPivotTables::SaveXml( XclExpXmlStream
& rStrm
)
368 sax_fastparser::FSHelperPtr
& pWSStrm
= rStrm
.GetCurrentStream(); // worksheet stream
370 sal_Int32 nCounter
= 1; // 1-based
371 TablesType::iterator it
= maTables
.begin(), itEnd
= maTables
.end();
372 for (; it
!= itEnd
; ++it
, ++nCounter
)
374 const ScDPObject
& rObj
= *it
->mpTable
;
375 sal_Int32 nCacheId
= it
->mnCacheId
;
376 sal_Int32 nPivotId
= it
->mnPivotId
;
378 sax_fastparser::FSHelperPtr pPivotStrm
= rStrm
.CreateOutputStream(
379 XclXmlUtils::GetStreamName("xl/pivotTables/", "pivotTable", nPivotId
),
380 XclXmlUtils::GetStreamName(NULL
, "../pivotTables/pivotTable", nPivotId
),
381 pWSStrm
->getOutputStream(),
382 CREATE_XL_CONTENT_TYPE("pivotTable"),
383 CREATE_OFFICEDOC_RELATION_TYPE("pivotTable"),
386 rStrm
.PushStream(pPivotStrm
);
387 SavePivotTableXml(rStrm
, rObj
, nCacheId
);
396 long mnPos
; // field index in pivot cache.
397 const ScDPSaveDimension
* mpDim
;
399 DataField( long nPos
, const ScDPSaveDimension
* pDim
) : mnPos(nPos
), mpDim(pDim
) {}
404 void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream
& rStrm
, const ScDPObject
& rDPObj
, sal_Int32 nCacheId
)
406 typedef std::unordered_map
<OUString
, long, OUStringHash
> NameToIdMapType
;
408 const XclExpXmlPivotCaches::Entry
* pCacheEntry
= mrCaches
.GetCache(nCacheId
);
410 // Something is horribly wrong. Check your logic.
413 const ScDPCache
& rCache
= *pCacheEntry
->mpCache
;
415 const ScDPSaveData
& rSaveData
= *rDPObj
.GetSaveData();
417 size_t nFieldCount
= rCache
.GetFieldCount();
418 std::vector
<const ScDPSaveDimension
*> aCachedDims
;
419 NameToIdMapType aNameToIdMap
;
421 aCachedDims
.reserve(nFieldCount
);
422 for (size_t i
= 0; i
< nFieldCount
; ++i
)
424 OUString aName
= rCache
.GetDimensionName(i
);
425 aNameToIdMap
.insert(NameToIdMapType::value_type(aName
, aCachedDims
.size()));
426 const ScDPSaveDimension
* pDim
= rSaveData
.GetExistingDimensionByName(aName
);
427 aCachedDims
.push_back(pDim
);
430 std::vector
<long> aRowFields
;
431 std::vector
<long> aColFields
;
432 std::vector
<long> aPageFields
;
433 std::vector
<DataField
> aDataFields
;
435 // Use dimensions in the save data to get their correct ordering.
436 // Dimension order here is significant as they specify the order of
437 // appearance in each axis.
438 const ScDPSaveData::DimsType
& rDims
= rSaveData
.GetDimensions();
440 for (size_t i
= 0, n
= rDims
.size(); i
< n
; ++i
)
442 const ScDPSaveDimension
& rDim
= rDims
[i
];
444 long nPos
= -1; // position in cache
445 if (rDim
.IsDataLayout())
446 nPos
= -2; // Excel uses an index of -2 to indicate a data layout field.
449 OUString aSrcName
= ScDPUtil::getSourceDimensionName(rDim
.GetName());
450 NameToIdMapType::iterator it
= aNameToIdMap
.find(aSrcName
);
451 if (it
!= aNameToIdMap
.end())
457 if (!aCachedDims
[nPos
])
461 sheet::DataPilotFieldOrientation eOrient
=
462 static_cast<sheet::DataPilotFieldOrientation
>(rDim
.GetOrientation());
466 case sheet::DataPilotFieldOrientation_COLUMN
:
467 aColFields
.push_back(nPos
);
469 case sheet::DataPilotFieldOrientation_ROW
:
470 aRowFields
.push_back(nPos
);
472 case sheet::DataPilotFieldOrientation_PAGE
:
473 aPageFields
.push_back(nPos
);
475 case sheet::DataPilotFieldOrientation_DATA
:
476 aDataFields
.push_back(DataField(nPos
, &rDim
));
478 case sheet::DataPilotFieldOrientation_HIDDEN
:
484 sax_fastparser::FSHelperPtr
& pPivotStrm
= rStrm
.GetCurrentStream();
485 pPivotStrm
->startElement(XML_pivotTableDefinition
,
486 XML_xmlns
, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
487 XML_name
, XclXmlUtils::ToOString(rDPObj
.GetName()).getStr(),
488 XML_cacheId
, OString::number(nCacheId
).getStr(),
489 XML_applyNumberFormats
, BS(false),
490 XML_applyBorderFormats
, BS(false),
491 XML_applyFontFormats
, BS(false),
492 XML_applyPatternFormats
, BS(false),
493 XML_applyAlignmentFormats
, BS(false),
494 XML_applyWidthHeightFormats
, BS(false),
495 XML_dataCaption
, "Values",
496 XML_useAutoFormatting
, BS(false),
497 XML_itemPrintTitles
, BS(true),
498 XML_indent
, BS(false),
499 XML_outline
, BS(true),
500 XML_outlineData
, BS(true),
503 // NB: Excel's range does not include page field area (if any).
504 ScRange aOutRange
= rDPObj
.GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE
);
506 sal_Int32 nFirstHeaderRow
= aColFields
.size();
507 sal_Int32 nFirstDataRow
= 2;
508 sal_Int32 nFirstDataCol
= 1;
509 ScRange aResRange
= rDPObj
.GetOutputRangeByType(sheet::DataPilotOutputRangeType::RESULT
);
510 if (aOutRange
.IsValid() && aResRange
.IsValid())
512 nFirstDataRow
= aResRange
.aStart
.Row() - aOutRange
.aStart
.Row();
513 nFirstDataCol
= aResRange
.aStart
.Col() - aOutRange
.aStart
.Col();
516 if (!aOutRange
.IsValid())
517 aOutRange
= rDPObj
.GetOutRange();
519 pPivotStrm
->write("<")->writeId(XML_location
);
520 rStrm
.WriteAttributes(XML_ref
,
521 XclXmlUtils::ToOString(aOutRange
),
522 XML_firstHeaderRow
, OString::number(nFirstHeaderRow
).getStr(),
523 XML_firstDataRow
, OString::number(nFirstDataRow
).getStr(),
524 XML_firstDataCol
, OString::number(nFirstDataCol
).getStr(),
527 if (!aPageFields
.empty())
529 rStrm
.WriteAttributes(XML_rowPageCount
, OString::number(static_cast<long>(aPageFields
.size())).getStr(), FSEND
);
530 rStrm
.WriteAttributes(XML_colPageCount
, OString::number(1).getStr(), FSEND
);
533 pPivotStrm
->write("/>");
535 // <pivotFields> - It must contain all fields in the pivot cache even if
536 // only some of them are used in the pivot table. The order must be as
537 // they appear in the cache.
539 pPivotStrm
->startElement(XML_pivotFields
,
540 XML_count
, OString::number(static_cast<long>(aCachedDims
.size())).getStr(),
543 for (size_t i
= 0, n
= aCachedDims
.size(); i
< n
; ++i
)
545 const ScDPSaveDimension
* pDim
= aCachedDims
[i
];
548 pPivotStrm
->singleElement(XML_pivotField
,
549 XML_showAll
, BS(false),
554 sheet::DataPilotFieldOrientation eOrient
=
555 static_cast<sheet::DataPilotFieldOrientation
>(pDim
->GetOrientation());
557 if (eOrient
== sheet::DataPilotFieldOrientation_HIDDEN
)
559 pPivotStrm
->singleElement(XML_pivotField
,
560 XML_showAll
, BS(false),
565 if (eOrient
== sheet::DataPilotFieldOrientation_DATA
)
567 pPivotStrm
->singleElement(XML_pivotField
,
568 XML_dataField
, BS(true),
569 XML_showAll
, BS(false),
575 pPivotStrm
->startElement(XML_pivotField
,
576 XML_axis
, toOOXMLAxisType(eOrient
),
577 XML_showAll
, BS(false),
580 // TODO : Dump field items.
582 pPivotStrm
->endElement(XML_pivotField
);
585 pPivotStrm
->endElement(XML_pivotFields
);
589 if (!aRowFields
.empty())
591 pPivotStrm
->startElement(XML_rowFields
,
592 XML_count
, OString::number(static_cast<long>(aRowFields
.size())),
595 std::vector
<long>::iterator it
= aRowFields
.begin(), itEnd
= aRowFields
.end();
596 for (; it
!= itEnd
; ++it
)
598 pPivotStrm
->singleElement(XML_field
,
599 XML_x
, OString::number(*it
),
603 pPivotStrm
->endElement(XML_rowFields
);
610 if (!aColFields
.empty())
612 pPivotStrm
->startElement(XML_colFields
,
613 XML_count
, OString::number(static_cast<long>(aColFields
.size())),
616 std::vector
<long>::iterator it
= aColFields
.begin(), itEnd
= aColFields
.end();
617 for (; it
!= itEnd
; ++it
)
619 pPivotStrm
->singleElement(XML_field
,
620 XML_x
, OString::number(*it
),
624 pPivotStrm
->endElement(XML_colFields
);
631 if (!aPageFields
.empty())
633 pPivotStrm
->startElement(XML_pageFields
,
634 XML_count
, OString::number(static_cast<long>(aPageFields
.size())),
637 std::vector
<long>::iterator it
= aPageFields
.begin(), itEnd
= aPageFields
.end();
638 for (; it
!= itEnd
; ++it
)
640 pPivotStrm
->singleElement(XML_pageField
,
641 XML_fld
, OString::number(*it
),
642 XML_hier
, OString::number(-1), // TODO : handle this correctly.
646 pPivotStrm
->endElement(XML_pageFields
);
651 if (!aDataFields
.empty())
653 pPivotStrm
->startElement(XML_dataFields
,
654 XML_count
, OString::number(static_cast<long>(aDataFields
.size())),
657 std::vector
<DataField
>::iterator it
= aDataFields
.begin(), itEnd
= aDataFields
.end();
658 for (; it
!= itEnd
; ++it
)
660 long nDimIdx
= it
->mnPos
;
661 assert(aCachedDims
[nDimIdx
]); // the loop above should have screened for NULL's.
662 const ScDPSaveDimension
& rDim
= *it
->mpDim
;
663 const OUString
* pName
= rDim
.GetLayoutName();
664 pPivotStrm
->write("<")->writeId(XML_dataField
);
666 rStrm
.WriteAttributes(XML_name
, XclXmlUtils::ToOString(*pName
), FSEND
);
668 rStrm
.WriteAttributes(XML_fld
, OString::number(nDimIdx
).getStr(), FSEND
);
670 sheet::GeneralFunction eFunc
= static_cast<sheet::GeneralFunction
>(rDim
.GetFunction());
671 const char* pSubtotal
= toOOXMLSubtotalType(eFunc
);
673 rStrm
.WriteAttributes(XML_subtotal
, pSubtotal
, FSEND
);
675 pPivotStrm
->write("/>");
678 pPivotStrm
->endElement(XML_dataFields
);
681 OUStringBuffer
aBuf("../pivotCache/pivotCacheDefinition");
682 aBuf
.append(nCacheId
);
686 pPivotStrm
->getOutputStream(),
687 CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
688 aBuf
.makeStringAndClear());
690 pPivotStrm
->endElement(XML_pivotTableDefinition
);
693 void XclExpXmlPivotTables::AppendTable( const ScDPObject
* pTable
, sal_Int32 nCacheId
, sal_Int32 nPivotId
)
695 maTables
.push_back(Entry(pTable
, nCacheId
, nPivotId
));
698 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */