Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / excel / xepivotxml.cxx
blob1b340812cc3f3b97e82a406cd701d1bb0130035c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <xepivotxml.hxx>
11 #include <dpcache.hxx>
12 #include <dpobject.hxx>
13 #include <dpsave.hxx>
14 #include <dputil.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>
25 #include <vector>
27 using namespace oox;
28 using namespace com::sun::star;
30 namespace {
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(),
42 FSEND);
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);
50 assert(pArray);
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 )
62 switch (eOrient)
64 case sheet::DataPilotFieldOrientation_COLUMN:
65 return "axisCol";
66 case sheet::DataPilotFieldOrientation_ROW:
67 return "axisRow";
68 case sheet::DataPilotFieldOrientation_PAGE:
69 return "axisPage";
70 case sheet::DataPilotFieldOrientation_DATA:
71 return "axisValues";
72 case sheet::DataPilotFieldOrientation_HIDDEN:
73 default:
77 return "";
80 const char* toOOXMLSubtotalType( sheet::GeneralFunction eFunc )
82 switch (eFunc)
84 case sheet::GeneralFunction_SUM:
85 return "sum";
86 case sheet::GeneralFunction_COUNT:
87 return "count";
88 case sheet::GeneralFunction_AVERAGE:
89 return "average";
90 case sheet::GeneralFunction_MAX:
91 return "max";
92 case sheet::GeneralFunction_MIN:
93 return "min";
94 case sheet::GeneralFunction_PRODUCT:
95 return "product";
96 case sheet::GeneralFunction_COUNTNUMS:
97 return "countNums";
98 case sheet::GeneralFunction_STDEV:
99 return "stdDev";
100 case sheet::GeneralFunction_STDEVP:
101 return "stdDevp";
102 case sheet::GeneralFunction_VAR:
103 return "var";
104 case sheet::GeneralFunction_VARP:
105 return "varp";
106 case sheet::GeneralFunction_NONE:
107 case sheet::GeneralFunction_AUTO:
108 default:
111 return nullptr;
116 XclExpXmlPivotCaches::XclExpXmlPivotCaches( const XclExpRoot& rRoot ) :
117 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;
129 OUString aRelId;
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"),
136 &aRelId);
138 pWorkbookStrm->singleElement(XML_pivotCache,
139 XML_cacheId, OString::number(nCacheId).getStr(),
140 FSNS(XML_r, XML_id), XclXmlUtils::ToOString(aRelId).getStr(),
141 FSEND);
143 rStrm.PushStream(pPCStrm);
144 SavePivotCacheXml(rStrm, rEntry, nCacheId);
145 rStrm.PopStream();
148 pWorkbookStrm->endElement(XML_pivotCaches);
151 void XclExpXmlPivotCaches::SetCaches( const std::vector<Entry>& rCaches )
153 maCaches = rCaches;
156 bool XclExpXmlPivotCaches::HasCaches() const
158 return !maCaches.empty();
161 const XclExpXmlPivotCaches::Entry* XclExpXmlPivotCaches::GetCache( sal_Int32 nCacheId ) const
163 if (nCacheId <= 0)
164 // cache ID is 1-based.
165 return nullptr;
167 size_t nPos = nCacheId - 1;
168 if (nPos >= maCaches.size())
169 return nullptr;
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();
181 OUString aRelId;
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"),
188 &aRelId);
190 rStrm.PushStream(pRecStrm);
191 savePivotCacheRecordsXml(rStrm, rCache);
192 rStrm.PopStream();
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(),
199 FSEND);
201 if (rEntry.meType == Worksheet)
203 pDefStrm->startElement(XML_cacheSource,
204 XML_type, "worksheet",
205 FSEND);
207 OUString aSheetName;
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(),
212 FSEND);
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(),
220 FSEND);
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(),
229 FSEND);
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),
249 FSEND);
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(),
260 FSEND);
261 break;
262 case ScDPItemData::Value:
263 pDefStrm->singleElement(XML_n,
264 XML_v, OString::number(rItem.GetValue()).getStr(),
265 FSEND);
266 break;
267 case ScDPItemData::Empty:
268 pDefStrm->singleElement(XML_m, FSEND);
269 break;
270 case ScDPItemData::Error:
271 pDefStrm->singleElement(XML_e,
272 XML_v, XclXmlUtils::ToOString(rItem.GetString()).getStr(),
273 FSEND);
274 break;
275 case ScDPItemData::GroupValue:
276 case ScDPItemData::RangeStart:
277 // TODO : What do we do with these types?
278 pDefStrm->singleElement(XML_m, FSEND);
279 break;
280 default:
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.
302 return;
304 const ScDPCollection* pDPColl = rDoc.GetDPCollection();
305 if (!pDPColl)
306 return;
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);
316 if (!pCache)
317 continue;
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....
343 continue;
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)));
354 it = r.first;
357 XclExpXmlPivotTables *const p = it->second.get();
358 p->AppendTable(&rDPObj, nCacheId, i+1);
361 maCaches.SetCaches(aCaches);
364 XclExpXmlPivotCaches& XclExpXmlPivotTableManager::GetCaches()
366 return maCaches;
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);
402 rStrm.PopStream();
406 namespace {
408 struct DataField
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);
423 if (!pCacheEntry)
424 // Something is horribly wrong. Check your logic.
425 return;
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.
461 else
463 OUString aSrcName = ScDPUtil::getSourceDimensionName(rDim.GetName());
464 NameToIdMapType::iterator it = aNameToIdMap.find(aSrcName);
465 if (it != aNameToIdMap.end())
466 nPos = it->second;
468 if (nPos == -1)
469 continue;
471 if (!aCachedDims[nPos])
472 continue;
475 sheet::DataPilotFieldOrientation eOrient =
476 static_cast<sheet::DataPilotFieldOrientation>(rDim.GetOrientation());
478 switch (eOrient)
480 case sheet::DataPilotFieldOrientation_COLUMN:
481 aColFields.push_back(nPos);
482 break;
483 case sheet::DataPilotFieldOrientation_ROW:
484 aRowFields.push_back(nPos);
485 break;
486 case sheet::DataPilotFieldOrientation_PAGE:
487 aPageFields.push_back(nPos);
488 break;
489 case sheet::DataPilotFieldOrientation_DATA:
490 aDataFields.push_back(DataField(nPos, &rDim));
491 break;
492 case sheet::DataPilotFieldOrientation_HIDDEN:
493 default:
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),
515 FSEND);
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(),
539 FSEND);
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(),
555 FSEND);
557 for (const ScDPSaveDimension* pDim : aCachedDims)
559 if (!pDim)
561 pPivotStrm->singleElement(XML_pivotField,
562 XML_showAll, BS(false),
563 FSEND);
564 continue;
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),
574 FSEND);
575 continue;
578 if (eOrient == sheet::DataPilotFieldOrientation_DATA)
580 pPivotStrm->singleElement(XML_pivotField,
581 XML_dataField, BS(true),
582 XML_showAll, BS(false),
583 FSEND);
585 continue;
588 pPivotStrm->startElement(XML_pivotField,
589 XML_axis, toOOXMLAxisType(eOrient),
590 XML_showAll, BS(false),
591 FSEND);
593 // TODO : Dump field items.
595 pPivotStrm->endElement(XML_pivotField);
598 pPivotStrm->endElement(XML_pivotFields);
600 // <rowFields>
602 if (!aRowFields.empty())
604 pPivotStrm->startElement(XML_rowFields,
605 XML_count, OString::number(static_cast<long>(aRowFields.size())),
606 FSEND);
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),
613 FSEND);
616 pPivotStrm->endElement(XML_rowFields);
619 // <rowItems>
621 // <colFields>
623 if (!aColFields.empty())
625 pPivotStrm->startElement(XML_colFields,
626 XML_count, OString::number(static_cast<long>(aColFields.size())),
627 FSEND);
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),
634 FSEND);
637 pPivotStrm->endElement(XML_colFields);
640 // <colItems>
642 // <pageFields>
644 if (!aPageFields.empty())
646 pPivotStrm->startElement(XML_pageFields,
647 XML_count, OString::number(static_cast<long>(aPageFields.size())),
648 FSEND);
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.
656 FSEND);
659 pPivotStrm->endElement(XML_pageFields);
662 // <dataFields>
664 if (!aDataFields.empty())
666 pPivotStrm->startElement(XML_dataFields,
667 XML_count, OString::number(static_cast<long>(aDataFields.size())),
668 FSEND);
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);
678 if (pName)
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);
685 if (pSubtotal)
686 rStrm.WriteAttributes(XML_subtotal, pSubtotal, FSEND);
688 pPivotStrm->write("/>");
691 pPivotStrm->endElement(XML_dataFields);
694 OUStringBuffer aBuf("../pivotCache/pivotCacheDefinition");
695 aBuf.append(nCacheId);
696 aBuf.append(".xml");
698 rStrm.addRelation(
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: */