You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

XSSFPivotTable.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.xssf.usermodel;
  16. import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.OutputStream;
  20. import java.util.ArrayList;
  21. import java.util.Collections;
  22. import java.util.List;
  23. import javax.xml.namespace.QName;
  24. import org.apache.poi.POIXMLDocumentPart;
  25. import org.apache.poi.openxml4j.opc.PackagePart;
  26. import org.apache.poi.openxml4j.opc.PackageRelationship;
  27. import org.apache.poi.ss.SpreadsheetVersion;
  28. import org.apache.poi.ss.usermodel.Cell;
  29. import org.apache.poi.ss.usermodel.CellType;
  30. import org.apache.poi.ss.usermodel.DataConsolidateFunction;
  31. import org.apache.poi.ss.usermodel.Sheet;
  32. import org.apache.poi.ss.util.AreaReference;
  33. import org.apache.poi.ss.util.CellReference;
  34. import org.apache.poi.util.Beta;
  35. import org.apache.poi.util.Internal;
  36. import org.apache.xmlbeans.XmlException;
  37. import org.apache.xmlbeans.XmlOptions;
  38. import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
  39. public class XSSFPivotTable extends POIXMLDocumentPart {
  40. protected final static short CREATED_VERSION = 3;
  41. protected final static short MIN_REFRESHABLE_VERSION = 3;
  42. protected final static short UPDATED_VERSION = 3;
  43. private CTPivotTableDefinition pivotTableDefinition;
  44. private XSSFPivotCacheDefinition pivotCacheDefinition;
  45. private XSSFPivotCache pivotCache;
  46. private XSSFPivotCacheRecords pivotCacheRecords;
  47. private Sheet parentSheet;
  48. private Sheet dataSheet;
  49. @Beta
  50. protected XSSFPivotTable() {
  51. super();
  52. pivotTableDefinition = CTPivotTableDefinition.Factory.newInstance();
  53. pivotCache = new XSSFPivotCache();
  54. pivotCacheDefinition = new XSSFPivotCacheDefinition();
  55. pivotCacheRecords = new XSSFPivotCacheRecords();
  56. }
  57. /**
  58. * Creates an XSSFPivotTable representing the given package part and relationship.
  59. * Should only be called when reading in an existing file.
  60. *
  61. * @param part - The package part that holds xml data representing this pivot table.
  62. *
  63. * @since POI 3.14-Beta1
  64. */
  65. @Beta
  66. protected XSSFPivotTable(PackagePart part) throws IOException {
  67. super(part);
  68. readFrom(part.getInputStream());
  69. }
  70. /**
  71. * @deprecated in POI 3.14, scheduled for removal in POI 3.16
  72. */
  73. @Deprecated
  74. protected XSSFPivotTable(PackagePart part, PackageRelationship rel) throws IOException {
  75. this(part);
  76. }
  77. @Beta
  78. public void readFrom(InputStream is) throws IOException {
  79. try {
  80. XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS);
  81. //Removing root element
  82. options.setLoadReplaceDocumentElement(null);
  83. pivotTableDefinition = CTPivotTableDefinition.Factory.parse(is, options);
  84. } catch (XmlException e) {
  85. throw new IOException(e.getLocalizedMessage());
  86. }
  87. }
  88. @Beta
  89. public void setPivotCache(XSSFPivotCache pivotCache) {
  90. this.pivotCache = pivotCache;
  91. }
  92. @Beta
  93. public XSSFPivotCache getPivotCache() {
  94. return pivotCache;
  95. }
  96. @Beta
  97. public Sheet getParentSheet() {
  98. return parentSheet;
  99. }
  100. @Beta
  101. public void setParentSheet(XSSFSheet parentSheet) {
  102. this.parentSheet = parentSheet;
  103. }
  104. @Beta
  105. @Internal
  106. public CTPivotTableDefinition getCTPivotTableDefinition() {
  107. return pivotTableDefinition;
  108. }
  109. @Beta
  110. @Internal
  111. public void setCTPivotTableDefinition(CTPivotTableDefinition pivotTableDefinition) {
  112. this.pivotTableDefinition = pivotTableDefinition;
  113. }
  114. @Beta
  115. public XSSFPivotCacheDefinition getPivotCacheDefinition() {
  116. return pivotCacheDefinition;
  117. }
  118. @Beta
  119. public void setPivotCacheDefinition(XSSFPivotCacheDefinition pivotCacheDefinition) {
  120. this.pivotCacheDefinition = pivotCacheDefinition;
  121. }
  122. @Beta
  123. public XSSFPivotCacheRecords getPivotCacheRecords() {
  124. return pivotCacheRecords;
  125. }
  126. @Beta
  127. public void setPivotCacheRecords(XSSFPivotCacheRecords pivotCacheRecords) {
  128. this.pivotCacheRecords = pivotCacheRecords;
  129. }
  130. @Beta
  131. public Sheet getDataSheet() {
  132. return dataSheet;
  133. }
  134. @Beta
  135. private void setDataSheet(Sheet dataSheet) {
  136. this.dataSheet = dataSheet;
  137. }
  138. @Beta
  139. @Override
  140. protected void commit() throws IOException {
  141. XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
  142. //Sets the pivotTableDefinition tag
  143. xmlOptions.setSaveSyntheticDocumentElement(new QName(CTPivotTableDefinition.type.getName().
  144. getNamespaceURI(), "pivotTableDefinition"));
  145. PackagePart part = getPackagePart();
  146. OutputStream out = part.getOutputStream();
  147. pivotTableDefinition.save(out, xmlOptions);
  148. out.close();
  149. }
  150. /**
  151. * Set default values for the table definition.
  152. */
  153. @Beta
  154. protected void setDefaultPivotTableDefinition() {
  155. //Not more than one until more created
  156. pivotTableDefinition.setMultipleFieldFilters(false);
  157. //Indentation increment for compact rows
  158. pivotTableDefinition.setIndent(0);
  159. //The pivot version which created the pivot cache set to default value
  160. pivotTableDefinition.setCreatedVersion(CREATED_VERSION);
  161. //Minimun version required to update the pivot cache
  162. pivotTableDefinition.setMinRefreshableVersion(MIN_REFRESHABLE_VERSION);
  163. //Version of the application which "updated the spreadsheet last"
  164. pivotTableDefinition.setUpdatedVersion(UPDATED_VERSION);
  165. //Titles shown at the top of each page when printed
  166. pivotTableDefinition.setItemPrintTitles(true);
  167. //Set autoformat properties
  168. pivotTableDefinition.setUseAutoFormatting(true);
  169. pivotTableDefinition.setApplyNumberFormats(false);
  170. pivotTableDefinition.setApplyWidthHeightFormats(true);
  171. pivotTableDefinition.setApplyAlignmentFormats(false);
  172. pivotTableDefinition.setApplyPatternFormats(false);
  173. pivotTableDefinition.setApplyFontFormats(false);
  174. pivotTableDefinition.setApplyBorderFormats(false);
  175. pivotTableDefinition.setCacheId(pivotCache.getCTPivotCache().getCacheId());
  176. pivotTableDefinition.setName("PivotTable"+pivotTableDefinition.getCacheId());
  177. pivotTableDefinition.setDataCaption("Values");
  178. //Set the default style for the pivot table
  179. CTPivotTableStyle style = pivotTableDefinition.addNewPivotTableStyleInfo();
  180. style.setName("PivotStyleLight16");
  181. style.setShowLastColumn(true);
  182. style.setShowColStripes(false);
  183. style.setShowRowStripes(false);
  184. style.setShowColHeaders(true);
  185. style.setShowRowHeaders(true);
  186. }
  187. protected AreaReference getPivotArea() {
  188. AreaReference pivotArea = new AreaReference(
  189. getPivotCacheDefinition()
  190. .getCTPivotCacheDefinition()
  191. .getCacheSource()
  192. .getWorksheetSource()
  193. .getRef(),
  194. SpreadsheetVersion.EXCEL2007);
  195. return pivotArea;
  196. }
  197. /**
  198. * Verify column index (relative to first column in pivot area) is within the
  199. * pivot area
  200. *
  201. * @param columnIndex
  202. * @throws IndexOutOfBoundsException
  203. */
  204. private void checkColumnIndex(int columnIndex) throws IndexOutOfBoundsException {
  205. AreaReference pivotArea = getPivotArea();
  206. int size = pivotArea.getLastCell().getCol() - pivotArea.getFirstCell().getCol() + 1;
  207. if (columnIndex < 0 || columnIndex >= size) {
  208. throw new IndexOutOfBoundsException("Column Index: " + columnIndex + ", Size: " + size);
  209. }
  210. }
  211. /**
  212. * Add a row label using data from the given column.
  213. * @param columnIndex the index of the source column to be used as row label.
  214. * {@code columnIndex} is 0-based indexed and relative to the first column in the source.
  215. */
  216. @Beta
  217. public void addRowLabel(int columnIndex) {
  218. checkColumnIndex(columnIndex);
  219. AreaReference pivotArea = getPivotArea();
  220. final int lastRowIndex = pivotArea.getLastCell().getRow() - pivotArea.getFirstCell().getRow();
  221. CTPivotFields pivotFields = pivotTableDefinition.getPivotFields();
  222. CTPivotField pivotField = CTPivotField.Factory.newInstance();
  223. CTItems items = pivotField.addNewItems();
  224. pivotField.setAxis(STAxis.AXIS_ROW);
  225. pivotField.setShowAll(false);
  226. for (int i = 0; i <= lastRowIndex; i++) {
  227. items.addNewItem().setT(STItemType.DEFAULT);
  228. }
  229. items.setCount(items.sizeOfItemArray());
  230. pivotFields.setPivotFieldArray(columnIndex, pivotField);
  231. CTRowFields rowFields;
  232. if(pivotTableDefinition.getRowFields() != null) {
  233. rowFields = pivotTableDefinition.getRowFields();
  234. } else {
  235. rowFields = pivotTableDefinition.addNewRowFields();
  236. }
  237. rowFields.addNewField().setX(columnIndex);
  238. rowFields.setCount(rowFields.sizeOfFieldArray());
  239. }
  240. @Beta
  241. public List<Integer> getRowLabelColumns() {
  242. if (pivotTableDefinition.getRowFields() != null) {
  243. List<Integer> columnIndexes = new ArrayList<Integer>();
  244. for (CTField f : pivotTableDefinition.getRowFields().getFieldArray()) {
  245. columnIndexes.add(f.getX());
  246. }
  247. return columnIndexes;
  248. } else {
  249. return Collections.emptyList();
  250. }
  251. }
  252. /**
  253. * Add a column label using data from the given column and specified function
  254. * @param columnIndex the index of the source column to be used as column label.
  255. * {@code columnIndex} is 0-based indexed and relative to the first column in the source.
  256. * @param function the function to be used on the data
  257. * The following functions exists:
  258. * Sum, Count, Average, Max, Min, Product, Count numbers, StdDev, StdDevp, Var, Varp
  259. * @param valueFieldName the name of pivot table value field
  260. */
  261. @Beta
  262. public void addColumnLabel(DataConsolidateFunction function, int columnIndex, String valueFieldName) {
  263. checkColumnIndex(columnIndex);
  264. addDataColumn(columnIndex, true);
  265. addDataField(function, columnIndex, valueFieldName);
  266. // colfield should be added for the second one.
  267. if (pivotTableDefinition.getDataFields().getCount() == 2) {
  268. CTColFields colFields;
  269. if(pivotTableDefinition.getColFields() != null) {
  270. colFields = pivotTableDefinition.getColFields();
  271. } else {
  272. colFields = pivotTableDefinition.addNewColFields();
  273. }
  274. colFields.addNewField().setX(-2);
  275. colFields.setCount(colFields.sizeOfFieldArray());
  276. }
  277. }
  278. /**
  279. * Add a column label using data from the given column and specified function
  280. * @param columnIndex the index of the source column to be used as column label
  281. * {@code columnIndex} is 0-based indexed and relative to the first column in the source..
  282. * @param function the function to be used on the data
  283. * The following functions exists:
  284. * Sum, Count, Average, Max, Min, Product, Count numbers, StdDev, StdDevp, Var, Varp
  285. */
  286. @Beta
  287. public void addColumnLabel(DataConsolidateFunction function, int columnIndex) {
  288. addColumnLabel(function, columnIndex, function.getName());
  289. }
  290. /**
  291. * Add data field with data from the given column and specified function.
  292. * @param function the function to be used on the data
  293. * The following functions exists:
  294. * Sum, Count, Average, Max, Min, Product, Count numbers, StdDev, StdDevp, Var, Varp
  295. * @param columnIndex the index of the column to be used as column label.
  296. * @param valueFieldName the name of pivot table value field
  297. */
  298. @Beta
  299. private void addDataField(DataConsolidateFunction function, int columnIndex, String valueFieldName) {
  300. checkColumnIndex(columnIndex);
  301. AreaReference pivotArea = getPivotArea();
  302. CTDataFields dataFields;
  303. if(pivotTableDefinition.getDataFields() != null) {
  304. dataFields = pivotTableDefinition.getDataFields();
  305. } else {
  306. dataFields = pivotTableDefinition.addNewDataFields();
  307. }
  308. CTDataField dataField = dataFields.addNewDataField();
  309. dataField.setSubtotal(STDataConsolidateFunction.Enum.forInt(function.getValue()));
  310. Cell cell = getDataSheet().getRow(pivotArea.getFirstCell().getRow())
  311. .getCell(pivotArea.getFirstCell().getCol() + columnIndex);
  312. cell.setCellType(CellType.STRING);
  313. dataField.setName(valueFieldName);
  314. dataField.setFld(columnIndex);
  315. dataFields.setCount(dataFields.sizeOfDataFieldArray());
  316. }
  317. /**
  318. * Add column containing data from the referenced area.
  319. * @param columnIndex the index of the column containing the data
  320. * @param isDataField true if the data should be displayed in the pivot table.
  321. */
  322. @Beta
  323. public void addDataColumn(int columnIndex, boolean isDataField) {
  324. checkColumnIndex(columnIndex);
  325. CTPivotFields pivotFields = pivotTableDefinition.getPivotFields();
  326. CTPivotField pivotField = CTPivotField.Factory.newInstance();
  327. pivotField.setDataField(isDataField);
  328. pivotField.setShowAll(false);
  329. pivotFields.setPivotFieldArray(columnIndex, pivotField);
  330. }
  331. /**
  332. * Add filter for the column with the corresponding index and cell value
  333. * @param columnIndex index of column to filter on
  334. */
  335. @Beta
  336. public void addReportFilter(int columnIndex) {
  337. checkColumnIndex(columnIndex);
  338. AreaReference pivotArea = getPivotArea();
  339. int lastRowIndex = pivotArea.getLastCell().getRow() - pivotArea.getFirstCell().getRow();
  340. CTPivotFields pivotFields = pivotTableDefinition.getPivotFields();
  341. CTPivotField pivotField = CTPivotField.Factory.newInstance();
  342. CTItems items = pivotField.addNewItems();
  343. pivotField.setAxis(STAxis.AXIS_PAGE);
  344. pivotField.setShowAll(false);
  345. for(int i = 0; i <= lastRowIndex; i++) {
  346. items.addNewItem().setT(STItemType.DEFAULT);
  347. }
  348. items.setCount(items.sizeOfItemArray());
  349. pivotFields.setPivotFieldArray(columnIndex, pivotField);
  350. CTPageFields pageFields;
  351. if (pivotTableDefinition.getPageFields()!= null) {
  352. pageFields = pivotTableDefinition.getPageFields();
  353. //Another filter has already been created
  354. pivotTableDefinition.setMultipleFieldFilters(true);
  355. } else {
  356. pageFields = pivotTableDefinition.addNewPageFields();
  357. }
  358. CTPageField pageField = pageFields.addNewPageField();
  359. pageField.setHier(-1);
  360. pageField.setFld(columnIndex);
  361. pageFields.setCount(pageFields.sizeOfPageFieldArray());
  362. pivotTableDefinition.getLocation().setColPageCount(pageFields.getCount());
  363. }
  364. /**
  365. * Creates cacheSource and workSheetSource for pivot table and sets the source reference as well assets the location of the pivot table
  366. * @param source Source for data for pivot table
  367. * @param position Position for pivot table in sheet
  368. * @param sourceSheet Sheet where the source will be collected from
  369. */
  370. @Beta
  371. protected void createSourceReferences(AreaReference source, CellReference position, Sheet sourceSheet){
  372. //Get cell one to the right and one down from position, add both to AreaReference and set pivot table location.
  373. AreaReference destination = new AreaReference(position, new CellReference(position.getRow()+1, position.getCol()+1));
  374. CTLocation location;
  375. if(pivotTableDefinition.getLocation() == null) {
  376. location = pivotTableDefinition.addNewLocation();
  377. location.setFirstDataCol(1);
  378. location.setFirstDataRow(1);
  379. location.setFirstHeaderRow(1);
  380. } else {
  381. location = pivotTableDefinition.getLocation();
  382. }
  383. location.setRef(destination.formatAsString());
  384. pivotTableDefinition.setLocation(location);
  385. //Set source for the pivot table
  386. CTPivotCacheDefinition cacheDef = getPivotCacheDefinition().getCTPivotCacheDefinition();
  387. CTCacheSource cacheSource = cacheDef.addNewCacheSource();
  388. cacheSource.setType(STSourceType.WORKSHEET);
  389. CTWorksheetSource worksheetSource = cacheSource.addNewWorksheetSource();
  390. worksheetSource.setSheet(sourceSheet.getSheetName());
  391. setDataSheet(sourceSheet);
  392. String[] firstCell = source.getFirstCell().getCellRefParts();
  393. String[] lastCell = source.getLastCell().getCellRefParts();
  394. worksheetSource.setRef(firstCell[2]+firstCell[1]+':'+lastCell[2]+lastCell[1]);
  395. }
  396. @Beta
  397. protected void createDefaultDataColumns() {
  398. CTPivotFields pivotFields;
  399. if (pivotTableDefinition.getPivotFields() != null) {
  400. pivotFields = pivotTableDefinition.getPivotFields();
  401. } else {
  402. pivotFields = pivotTableDefinition.addNewPivotFields();
  403. }
  404. AreaReference sourceArea = getPivotArea();
  405. int firstColumn = sourceArea.getFirstCell().getCol();
  406. int lastColumn = sourceArea.getLastCell().getCol();
  407. CTPivotField pivotField;
  408. for(int i = 0; i<=lastColumn-firstColumn; i++) {
  409. pivotField = pivotFields.addNewPivotField();
  410. pivotField.setDataField(false);
  411. pivotField.setShowAll(false);
  412. }
  413. pivotFields.setCount(pivotFields.sizeOfPivotFieldArray());
  414. }
  415. }