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 19KB

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