1 | /*******************************************************************************
|
---|
2 | * You may amend and distribute as you like, but don't remove this header!
|
---|
3 | *
|
---|
4 | * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
|
---|
5 | * See http://www.codeplex.com/EPPlus for details.
|
---|
6 | *
|
---|
7 | * Copyright (C) 2011 Jan Källman
|
---|
8 | *
|
---|
9 | * This library is free software; you can redistribute it and/or
|
---|
10 | * modify it under the terms of the GNU Lesser General Public
|
---|
11 | * License as published by the Free Software Foundation; either
|
---|
12 | * version 2.1 of the License, or (at your option) any later version.
|
---|
13 |
|
---|
14 | * This library is distributed in the hope that it will be useful,
|
---|
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
---|
17 | * See the GNU Lesser General Public License for more details.
|
---|
18 | *
|
---|
19 | * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
|
---|
20 | * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
|
---|
21 | *
|
---|
22 | * All code and executables are provided "as is" with no warranty either express or implied.
|
---|
23 | * The author accepts no liability for any damage or loss of business that this product may cause.
|
---|
24 | *
|
---|
25 | * Code change notes:
|
---|
26 | *
|
---|
27 | * Author Change Date
|
---|
28 | * ******************************************************************************
|
---|
29 | * Jan Källman Added 21-MAR-2011
|
---|
30 | * Jan Källman License changed GPL-->LGPL 2011-12-16
|
---|
31 | *******************************************************************************/
|
---|
32 | using System;
|
---|
33 | using System.Collections.Generic;
|
---|
34 | using System.Text;
|
---|
35 | using System.Xml;
|
---|
36 | using System.IO.Packaging;
|
---|
37 | using System.Linq;
|
---|
38 | namespace OfficeOpenXml.Table.PivotTable
|
---|
39 | {
|
---|
40 | public enum eSourceType
|
---|
41 | {
|
---|
42 | /// <summary>
|
---|
43 | /// Indicates that the cache contains data that consolidates ranges.
|
---|
44 | /// </summary>
|
---|
45 | Consolidation,
|
---|
46 | /// <summary>
|
---|
47 | /// Indicates that the cache contains data from an external data source.
|
---|
48 | /// </summary>
|
---|
49 | External,
|
---|
50 | /// <summary>
|
---|
51 | /// Indicates that the cache contains a scenario summary report
|
---|
52 | /// </summary>
|
---|
53 | Scenario,
|
---|
54 | /// <summary>
|
---|
55 | /// Indicates that the cache contains worksheet data
|
---|
56 | /// </summary>
|
---|
57 | Worksheet
|
---|
58 | }
|
---|
59 | /// <summary>
|
---|
60 | /// Cache definition. This class defines the source data. Note that one cache definition can be shared between many pivot tables.
|
---|
61 | /// </summary>
|
---|
62 | public class ExcelPivotCacheDefinition : XmlHelper
|
---|
63 | {
|
---|
64 | internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable) :
|
---|
65 | base(ns, null)
|
---|
66 | {
|
---|
67 | foreach (var r in pivotTable.Part.GetRelationshipsByType(ExcelPackage.schemaRelationships + "/pivotCacheDefinition"))
|
---|
68 | {
|
---|
69 | Relationship = r;
|
---|
70 | }
|
---|
71 | CacheDefinitionUri = PackUriHelper.ResolvePartUri(Relationship.SourceUri, Relationship.TargetUri);
|
---|
72 |
|
---|
73 | var pck = pivotTable.WorkSheet._package.Package;
|
---|
74 | Part = pck.GetPart(CacheDefinitionUri);
|
---|
75 | CacheDefinitionXml = new XmlDocument();
|
---|
76 | LoadXmlSafe(CacheDefinitionXml, Part.GetStream());
|
---|
77 |
|
---|
78 | TopNode = CacheDefinitionXml.DocumentElement;
|
---|
79 | PivotTable = pivotTable;
|
---|
80 | if (CacheSource == eSourceType.Worksheet)
|
---|
81 | {
|
---|
82 | var worksheetName = GetXmlNodeString(_sourceWorksheetPath);
|
---|
83 | if (pivotTable.WorkSheet.Workbook.Worksheets.Any(t => t.Name == worksheetName))
|
---|
84 | {
|
---|
85 | _sourceRange = pivotTable.WorkSheet.Workbook.Worksheets[worksheetName].Cells[GetXmlNodeString(_sourceAddressPath)];
|
---|
86 | }
|
---|
87 | }
|
---|
88 | }
|
---|
89 | internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable, ExcelRangeBase sourceAddress, int tblId) :
|
---|
90 | base(ns, null)
|
---|
91 | {
|
---|
92 | PivotTable = pivotTable;
|
---|
93 |
|
---|
94 | var pck = pivotTable.WorkSheet._package.Package;
|
---|
95 |
|
---|
96 | //CacheDefinition
|
---|
97 | CacheDefinitionXml = new XmlDocument();
|
---|
98 | LoadXmlSafe(CacheDefinitionXml, GetStartXml(sourceAddress), Encoding.UTF8);
|
---|
99 | CacheDefinitionUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheDefinition{0}.xml", tblId);
|
---|
100 | Part = pck.CreatePart(CacheDefinitionUri, ExcelPackage.schemaPivotCacheDefinition);
|
---|
101 | TopNode = CacheDefinitionXml.DocumentElement;
|
---|
102 |
|
---|
103 | //CacheRecord. Create an empty one.
|
---|
104 | CacheRecordUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheRecords{0}.xml", tblId);
|
---|
105 | var cacheRecord = new XmlDocument();
|
---|
106 | cacheRecord.LoadXml("<pivotCacheRecords xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" count=\"0\" />");
|
---|
107 | var recPart = pck.CreatePart(CacheRecordUri, ExcelPackage.schemaPivotCacheRecords);
|
---|
108 | cacheRecord.Save(recPart.GetStream());
|
---|
109 |
|
---|
110 | RecordRelationship = Part.CreateRelationship(PackUriHelper.ResolvePartUri(CacheDefinitionUri, CacheRecordUri), TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotCacheRecords");
|
---|
111 | RecordRelationshipID = RecordRelationship.Id;
|
---|
112 |
|
---|
113 | CacheDefinitionXml.Save(Part.GetStream());
|
---|
114 | }
|
---|
115 | /// <summary>
|
---|
116 | /// Reference to the internal package part
|
---|
117 | /// </summary>
|
---|
118 | internal PackagePart Part
|
---|
119 | {
|
---|
120 | get;
|
---|
121 | set;
|
---|
122 | }
|
---|
123 | /// <summary>
|
---|
124 | /// Provides access to the XML data representing the cache definition in the package.
|
---|
125 | /// </summary>
|
---|
126 | public XmlDocument CacheDefinitionXml { get; private set; }
|
---|
127 | /// <summary>
|
---|
128 | /// The package internal URI to the pivottable cache definition Xml Document.
|
---|
129 | /// </summary>
|
---|
130 | public Uri CacheDefinitionUri
|
---|
131 | {
|
---|
132 | get;
|
---|
133 | internal set;
|
---|
134 | }
|
---|
135 | internal Uri CacheRecordUri
|
---|
136 | {
|
---|
137 | get;
|
---|
138 | set;
|
---|
139 | }
|
---|
140 | internal PackageRelationship Relationship
|
---|
141 | {
|
---|
142 | get;
|
---|
143 | set;
|
---|
144 | }
|
---|
145 | internal PackageRelationship RecordRelationship
|
---|
146 | {
|
---|
147 | get;
|
---|
148 | set;
|
---|
149 | }
|
---|
150 | internal string RecordRelationshipID
|
---|
151 | {
|
---|
152 | get
|
---|
153 | {
|
---|
154 | return GetXmlNodeString("@r:id");
|
---|
155 | }
|
---|
156 | set
|
---|
157 | {
|
---|
158 | SetXmlNodeString("@r:id", value);
|
---|
159 | }
|
---|
160 | }
|
---|
161 | /// <summary>
|
---|
162 | /// Referece to the PivoTable object
|
---|
163 | /// </summary>
|
---|
164 | public ExcelPivotTable PivotTable
|
---|
165 | {
|
---|
166 | get;
|
---|
167 | private set;
|
---|
168 | }
|
---|
169 |
|
---|
170 | const string _sourceWorksheetPath="d:cacheSource/d:worksheetSource/@sheet";
|
---|
171 | const string _sourceAddressPath = "d:cacheSource/d:worksheetSource/@ref";
|
---|
172 | internal ExcelRangeBase _sourceRange = null;
|
---|
173 | /// <summary>
|
---|
174 | /// The source data range when the pivottable has a worksheet datasource.
|
---|
175 | /// The number of columns in the range must be intact if this property is changed.
|
---|
176 | /// The range must be in the same workbook as the pivottable.
|
---|
177 | /// </summary>
|
---|
178 | public ExcelRangeBase SourceRange
|
---|
179 | {
|
---|
180 | get
|
---|
181 | {
|
---|
182 | if (_sourceRange == null)
|
---|
183 | {
|
---|
184 | if (CacheSource == eSourceType.Worksheet)
|
---|
185 | {
|
---|
186 | var ws = PivotTable.WorkSheet.Workbook.Worksheets[GetXmlNodeString(_sourceWorksheetPath)];
|
---|
187 | if (ws != null)
|
---|
188 | {
|
---|
189 | _sourceRange = ws.Cells[GetXmlNodeString(_sourceAddressPath)];
|
---|
190 | }
|
---|
191 | }
|
---|
192 | else
|
---|
193 | {
|
---|
194 | throw (new ArgumentException("The cachesource is not a worksheet"));
|
---|
195 | }
|
---|
196 | }
|
---|
197 | return _sourceRange;
|
---|
198 | }
|
---|
199 | set
|
---|
200 | {
|
---|
201 | if (PivotTable.WorkSheet.Workbook != value.Worksheet.Workbook)
|
---|
202 | {
|
---|
203 | throw (new ArgumentException("Range must be in the same package as the pivottable"));
|
---|
204 | }
|
---|
205 |
|
---|
206 | var sr=SourceRange;
|
---|
207 | if (value.End.Column - value.Start.Column != sr.End.Column - sr.Start.Column)
|
---|
208 | {
|
---|
209 | throw (new ArgumentException("Can not change the number of columns(fields) in the SourceRange"));
|
---|
210 | }
|
---|
211 |
|
---|
212 | SetXmlNodeString(_sourceWorksheetPath, value.Worksheet.Name);
|
---|
213 | SetXmlNodeString(_sourceAddressPath, value.FirstAddress);
|
---|
214 | _sourceRange = value;
|
---|
215 | }
|
---|
216 | }
|
---|
217 | /// <summary>
|
---|
218 | /// Type of source data
|
---|
219 | /// </summary>
|
---|
220 | public eSourceType CacheSource
|
---|
221 | {
|
---|
222 | get
|
---|
223 | {
|
---|
224 | var s=GetXmlNodeString("d:cacheSource/@type");
|
---|
225 | if (s == "")
|
---|
226 | {
|
---|
227 | return eSourceType.Worksheet;
|
---|
228 | }
|
---|
229 | else
|
---|
230 | {
|
---|
231 | return (eSourceType)Enum.Parse(typeof(eSourceType), s, true);
|
---|
232 | }
|
---|
233 | }
|
---|
234 | }
|
---|
235 | private string GetStartXml(ExcelRangeBase sourceAddress)
|
---|
236 | {
|
---|
237 | string xml="<pivotCacheDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"\" refreshOnLoad=\"1\" refreshedBy=\"SomeUser\" refreshedDate=\"40504.582403125001\" createdVersion=\"1\" refreshedVersion=\"3\" recordCount=\"5\" upgradeOnRefresh=\"1\">";
|
---|
238 |
|
---|
239 | xml += "<cacheSource type=\"worksheet\">";
|
---|
240 | xml += string.Format("<worksheetSource ref=\"{0}\" sheet=\"{1}\" /> ", sourceAddress.Address, sourceAddress.WorkSheet);
|
---|
241 | xml += "</cacheSource>";
|
---|
242 | xml += string.Format("<cacheFields count=\"{0}\">", sourceAddress._toCol - sourceAddress._fromCol + 1);
|
---|
243 | var sourceWorksheet = PivotTable.WorkSheet.Workbook.Worksheets[sourceAddress.WorkSheet];
|
---|
244 | for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++)
|
---|
245 | {
|
---|
246 | if (sourceWorksheet == null || sourceWorksheet.Cell(sourceAddress._fromRow, col).Value == null || sourceWorksheet.Cell(sourceAddress._fromRow, col).Value.ToString().Trim() == "")
|
---|
247 | {
|
---|
248 | xml += string.Format("<cacheField name=\"Column{0}\" numFmtId=\"0\">", col - sourceAddress._fromCol + 1);
|
---|
249 | }
|
---|
250 | else
|
---|
251 | {
|
---|
252 | xml += string.Format("<cacheField name=\"{0}\" numFmtId=\"0\">", sourceWorksheet.Cell(sourceAddress._fromRow, col).Value);
|
---|
253 | }
|
---|
254 | //xml += "<sharedItems containsNonDate=\"0\" containsString=\"0\" containsBlank=\"1\" /> ";
|
---|
255 | xml += "<sharedItems containsBlank=\"1\" /> ";
|
---|
256 | xml += "</cacheField>";
|
---|
257 | }
|
---|
258 | xml += "</cacheFields>";
|
---|
259 | xml += "</pivotCacheDefinition>";
|
---|
260 |
|
---|
261 | return xml;
|
---|
262 | }
|
---|
263 | }
|
---|
264 | }
|
---|