How to Add negative value for DataBar in apache poi? - apache-poi

i used this code to create a databar :
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFDataBarFormatting;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
public class ConditionalFormattingDataBars {
public static void applyDataBars(SheetConditionalFormatting sheetCF, String region, ExtendedColor color) throws Exception {
CellRangeAddress[] regions = { CellRangeAddress.valueOf(region) };
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(color);
DataBarFormatting dbf = rule.getDataBarFormatting();
dbf.getMinThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MIN);
dbf.getMaxThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MAX);
dbf.setWidthMin(0); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l57
dbf.setWidthMax(100); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l64
if (dbf instanceof XSSFDataBarFormatting) {
Field _databar = XSSFDataBarFormatting.class.getDeclaredField("_databar");
_databar.setAccessible(true);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar ctDataBar =
(org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar)_databar.get(dbf);
ctDataBar.setMinLength(0);
ctDataBar.setMaxLength(100);
}
sheetCF.addConditionalFormatting(regions, rule);
}
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("new sheet");
java.util.List<Double> list = java.util.Arrays.asList(0.279, 0.252, 0.187, 0.128, 0.078, 0.043, 0.022, 0.012, 0.011, 0.0, 0.0);
for (int i = 0; i < list.size(); i++) {
sheet.createRow(i+1).createCell(1).setCellValue(list.get(i));
}
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
ExtendedColor color = workbook.getCreationHelper().createExtendedColor();
color.setARGBHex("FF80C279");
applyDataBars(sheetCF, "B2:B12", color);
sheet.setColumnWidth(1, 50*256);
FileOutputStream out = new FileOutputStream("ConditionalFormattingDataBars.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
And i fond it on the question provided Hear
And it is working !
However i tried to modify it to add negative value Like This :
but i did not fond any Class Or Object To do this !
is this even possible ?

This is a similar problem as this one: How to make solid color for databar in apache.poi.
The settings for negative values in data bars were not available when Office Open XML was published. It is a later added feature. Since apache poi uses the published features of Office Open XML only, this feature is not available directly. Also it is not available using the underlying org.openxmlformats.schemas.spreadsheetml.x2006.main.* classes as those also only are created from published Office Open XML.
How to see this? All Office Open XML files are ZIP archives. One can unzip them and have a look at the XML. So we set data bar settings as needed in Excel and save the *.xlsx file. Then we unzip the *.xlsx file and have a look at /xl/worksheets/sheet1.xml. There we find the settings for conditional formatting.
So we only can solve this problem the same way as in the linked answer above.
Complete example:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFDataBarFormatting;
import org.apache.poi.xssf.usermodel.XSSFConditionalFormattingRule;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
public class ConditionalFormattingDataBars {
public static void applyDataBars(SheetConditionalFormatting sheetCF, String region, ExtendedColor colorPos, ExtendedColor colorNeg) throws Exception {
CellRangeAddress[] regions = { CellRangeAddress.valueOf(region) };
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(colorPos);
DataBarFormatting dbf = rule.getDataBarFormatting();
dbf.getMinThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MIN);
dbf.getMaxThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MAX);
dbf.setWidthMin(0); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l57
dbf.setWidthMax(100); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l64
if (dbf instanceof XSSFDataBarFormatting) {
Field _databar = XSSFDataBarFormatting.class.getDeclaredField("_databar");
_databar.setAccessible(true);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar ctDataBar =
(org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar)_databar.get(dbf);
ctDataBar.setMinLength(0);
ctDataBar.setMaxLength(100);
}
// use extension from x14 namespace to set data bars having setting for negative value
if (rule instanceof XSSFConditionalFormattingRule) {
Field _cfRule = XSSFConditionalFormattingRule.class.getDeclaredField("_cfRule");
_cfRule.setAccessible(true);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule ctRule =
(org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule)_cfRule.get(rule);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExtensionList extList =
ctRule.addNewExtLst();
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExtension ext = extList.addNewExt();
String extXML =
"<x14:id"
+ " xmlns:x14=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\">"
+ "{00000000-000E-0000-0000-000001000000}"
+ "</x14:id>";
org.apache.xmlbeans.XmlObject xlmObject = org.apache.xmlbeans.XmlObject.Factory.parse(extXML);
ext.set(xlmObject);
ext.setUri("{B025F937-C7B1-47D3-B67F-A62EFF666E3E}");
Field _sh = XSSFConditionalFormattingRule.class.getDeclaredField("_sh");
_sh.setAccessible(true);
XSSFSheet sheet = (XSSFSheet)_sh.get(rule);
extList = sheet.getCTWorksheet().addNewExtLst();
ext = extList.addNewExt();
extXML =
"<x14:conditionalFormattings xmlns:x14=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\">"
+ "<x14:conditionalFormatting xmlns:xm=\"http://schemas.microsoft.com/office/excel/2006/main\">"
+ "<x14:cfRule type=\"dataBar\" id=\"{00000000-000E-0000-0000-000001000000}\">"
+ "<x14:dataBar minLength=\"" + 0 + "\" maxLength=\"" + 100 + "\" border=\"1\" negativeBarBorderColorSameAsPositive=\"0\">"
+ "<x14:cfvo type=\"min\"/>"
+ "<x14:cfvo type=\"max\"/>"
+ "<x14:borderColor rgb=\"" + colorPos.getARGBHex() + "\"/>"
+ "<x14:negativeFillColor rgb=\"" + colorNeg.getARGBHex() + "\"/>"
+ "<x14:negativeBorderColor rgb=\"" + colorNeg.getARGBHex() + "\"/>"
+ "<x14:axisColor theme=\"1\"/>"
+ "</x14:dataBar>"
+ "</x14:cfRule>"
+ "<xm:sqref>" + region + "</xm:sqref>"
+ "</x14:conditionalFormatting>"
+ "</x14:conditionalFormattings>";
xlmObject = org.apache.xmlbeans.XmlObject.Factory.parse(extXML);
ext.set(xlmObject);
ext.setUri("{78C0D931-6437-407d-A8EE-F0AAD7539E65}");
}
sheetCF.addConditionalFormatting(regions, rule);
}
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("new sheet");
java.util.List<Double> list = java.util.Arrays.asList(0.279, -0.252, 0.187, -0.128, 0.078, 0.043, -0.022, 0.012, 0.011, 0.0, 0.0);
for (int i = 0; i < list.size(); i++) {
sheet.createRow(i+1).createCell(1).setCellValue(list.get(i));
}
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
ExtendedColor colorPos = workbook.getCreationHelper().createExtendedColor();
colorPos.setARGBHex("FF80C279");
ExtendedColor colorNeg = workbook.getCreationHelper().createExtendedColor();
colorNeg.setARGBHex("FFFF0000");
applyDataBars(sheetCF, "B2:B12", colorPos, colorNeg);
sheet.setColumnWidth(1, 50*256);
FileOutputStream out = new FileOutputStream("ConditionalFormattingDataBars.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
This code will only work properly always for new created XSSFWorkbook. If the XSSFWorkbook was created from an existing workbook, the this could contain org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExtensionList for x14 extensions already. If so, then these must be taken into account. But that would be a much more complex and challenging project.

Related

Excel Conversion of .xls to .xlsx using Java

I am trying to extract test output results in excel format. I want the results to be summarized in neat columns and row formats and want to display results graphically using a Pie chart.
To do this, I have used Apache POI API(Excel edits) and JFreeChart(for Pie chart creation).
I have been able to do all this, and the results are generated in .xls format.
When I tried to convert it to xlsx format after all of this, its doing the job, but the Pie chart and other excel stylings are missed to be written to .xlsx output file.
The code I have used for conversion from .xls to .xlsx is as follows:
package excelFileGenerate6;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
//import com.aspose.cells.SaveFormat;
public class conversion_to_xlsx {
public static void main(String[] args) throws InvalidFormatException,
IOException {
String inpFn = "C:\\Users\\Username\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\report.xls";
String outFn = "C:\\Users\\Username\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\converted_report.xlsx";
FileInputStream in = new FileInputStream(inpFn);
try {
Workbook wbIn = new HSSFWorkbook(in);
File outF = new File(outFn);
if (outF.exists())
outF.delete();
Workbook wbOut = new XSSFWorkbook();
int sheetCnt = wbIn.getNumberOfSheets();
for (int i = 0; i < sheetCnt; i++) {
Sheet sIn = wbIn.getSheetAt(i);
//Sheet sOut = wbOut.getSheet(null);
Sheet sOut = wbOut.createSheet(sIn.getSheetName());
Iterator<Row> rowIt = sIn.rowIterator();
while (rowIt.hasNext()) {
Row rowIn = rowIt.next();
Row rowOut = sOut.createRow(rowIn.getRowNum());
Iterator<Cell> cellIt = rowIn.cellIterator();
while (cellIt.hasNext()) {
Cell cellIn = cellIt.next();
Cell cellOut = rowOut.createCell(
cellIn.getColumnIndex(), cellIn.getCellType());
switch (cellIn.getCellType()) {
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_BOOLEAN:
cellOut.setCellValue(cellIn.getBooleanCellValue());
break;
case Cell.CELL_TYPE_ERROR:
cellOut.setCellValue(cellIn.getErrorCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
cellOut.setCellFormula(cellIn.getCellFormula());
break;
case Cell.CELL_TYPE_NUMERIC:
cellOut.setCellValue(cellIn.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
cellOut.setCellValue(cellIn.getStringCellValue());
break;
}
{
CellStyle styleIn = cellIn.getCellStyle();
CellStyle styleOut = cellOut.getCellStyle();
styleOut.setDataFormat(styleIn.getDataFormat());
}
cellOut.setCellComment(cellIn.getCellComment());
// HSSFCellStyle cannot be cast to XSSFCellStyle
// cellOut.setCellStyle(cellIn.getCellStyle());
}
}
}
FileOutputStream out = new FileOutputStream(outF);
try {
wbOut.write(out);
} finally {
out.close();
}
} finally {
in.close();
}
}
}
I have generated the excel reports and associated Pie chart using HSSF workbook style which gives the excel output in .xls format. Tried the online help to convert the HSSF objects to XSSF objects , but the pie chart creation gave a sun/image/codec error.
Attaching the Screenshots of code snippets and excel output files.
Any code/direction for converting my .xls results to .xlsx format will highly be of help for me..
Thanks
The code used to create Pie Chart :
package excelFileGenerate6;
import java.awt.Color;
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.ChartUtilities;
import java.util.Iterator;
public class CreatePieChartExample {
public void createPie(String Filename) throws IOException {
/* Read Excel and the Chart Data */
FileInputStream chart_file_input = new FileInputStream(new File(Filename));
/* Read data into HSSFWorkbook */
HSSFWorkbook my_workbook = new HSSFWorkbook(chart_file_input);
/* This worksheet contains the Pie Chart Data */
HSSFSheet my_sheet = my_workbook.getSheetAt(0);
/* Create JFreeChart object that will hold the Pie Chart Data */
DefaultPieDataset my_pie_chart_data = new DefaultPieDataset();
/* We now iterate over the Excel Workbook data and Populate Pie Chart Data */
/* Create an Iterator object */
Iterator<Row> rowIterator = my_sheet.iterator();
/* Loop through worksheet data and populate Pie Chart Dataset */
String chart_label="a";
Number chart_data=0;
while(rowIterator.hasNext()) {
//Read Rows from Excel document
Row row = rowIterator.next();
//Read cells in Rows and get chart data
Iterator<Cell> cellIterator = row.cellIterator();
while(cellIterator.hasNext()) {
Cell cell = cellIterator.next();
switch(cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
chart_data=cell.getNumericCellValue();
break;
case Cell.CELL_TYPE_STRING:
chart_label=cell.getStringCellValue();
break;
}
}
/* Add data to the data set */
my_pie_chart_data.setValue(chart_label,chart_data);
}
/* Create a logical chart object with the chart data collected */
JFreeChart myPieChart=ChartFactory.createPieChart("Test Results",my_pie_chart_data,true,true,false);
// Add custom colors
PiePlot plot = (PiePlot) myPieChart.getPlot();
//To create chart labels with only values on pie
PieSectionLabelGenerator gen = new StandardPieSectionLabelGenerator("{1}");
plot.setLabelGenerator(gen);
plot.setSectionPaint("Passed", Color.GREEN);
plot.setSectionPaint("Failed", Color.RED);
plot.setSectionPaint("Pending", Color.black);
plot.setSectionPaint("Total Time taken (ms)", Color.pink);
plot.setSectionPaint("Skipped", Color.blue);
plot.setSectionPaint("How many Sub headers are Passed", Color.yellow);
plot.setSectionPaint("Total TC's", Color.CYAN);
/* Specify the height and width of the Pie Chart */
int width=640; /* Width of the chart */
int height=480; /* Height of the chart */
float quality=1; /* Quality factor */
/* We don't want to create an intermediate file. So, we create a byte array output stream
and byte array input stream
And we pass the chart data directly to input stream through this */
/* Write chart as JPG to Output Stream */
ByteArrayOutputStream chart_out = new ByteArrayOutputStream();
ChartUtilities.writeChartAsJPEG(chart_out,quality,myPieChart,width,height);
/* We now read from the output stream and frame the input chart data */
InputStream feed_chart_to_excel=new ByteArrayInputStream(chart_out.toByteArray());
byte[] bytes = IOUtils.toByteArray(feed_chart_to_excel);
/* Add picture to workbook */
int my_picture_id = my_workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
/* We can close Piped Input Stream. We don't need this */
feed_chart_to_excel.close();
/* Close PipedOutputStream also */
chart_out.close();
/* Create the drawing container */
HSSFPatriarch drawing = my_sheet.createDrawingPatriarch();
/* Create an anchor point */
ClientAnchor my_anchor = new HSSFClientAnchor();
/* Define top left corner, and we can resize picture suitable from there */
my_anchor.setCol1(4);
my_anchor.setRow1(5);
/* Invoke createPicture and pass the anchor point and ID */
HSSFPicture my_picture = drawing.createPicture(my_anchor, my_picture_id);
/* Call resize method, which resizes the image */
my_picture.resize();
/* Close the FileInputStream */
chart_file_input.close();
/* Write changes to the workbook */
FileOutputStream out = new FileOutputStream(new File(Filename));
my_workbook.write(out);
out.close();
}
public static void main(String args[]) throws IOException {
CreatePieChartExample chart = new CreatePieChartExample();
chart.createPie("C:\\Users\\user\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\report.xls");
}
}
The code used for .xls to .xlsx conversion:
package excelFileGenerate6;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
//import com.aspose.cells.SaveFormat;
public class conversion_to_xlsx {
public static void main(String[] args) throws InvalidFormatException,
IOException {
String inpFn = "C:\\Users\\user\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\report.xls";
String outFn = "C:\\Users\\user\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\converted_report.xlsx";
FileInputStream in = new FileInputStream(inpFn);
try {
Workbook wbIn = new HSSFWorkbook(in);
File outF = new File(outFn);
if (outF.exists())
outF.delete();
Workbook wbOut = new XSSFWorkbook();
int sheetCnt = wbIn.getNumberOfSheets();
for (int i = 0; i < sheetCnt; i++) {
Sheet sIn = wbIn.getSheetAt(i);
//Sheet sOut = wbOut.getSheet(null);
Sheet sOut = wbOut.createSheet(sIn.getSheetName());
Iterator<Row> rowIt = sIn.rowIterator();
while (rowIt.hasNext()) {
Row rowIn = rowIt.next();
Row rowOut = sOut.createRow(rowIn.getRowNum());
Iterator<Cell> cellIt = rowIn.cellIterator();
while (cellIt.hasNext()) {
Cell cellIn = cellIt.next();
Cell cellOut = rowOut.createCell(
cellIn.getColumnIndex(), cellIn.getCellType());
switch (cellIn.getCellType()) {
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_BOOLEAN:
cellOut.setCellValue(cellIn.getBooleanCellValue());
break;
case Cell.CELL_TYPE_ERROR:
cellOut.setCellValue(cellIn.getErrorCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
cellOut.setCellFormula(cellIn.getCellFormula());
break;
case Cell.CELL_TYPE_NUMERIC:
cellOut.setCellValue(cellIn.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
cellOut.setCellValue(cellIn.getStringCellValue());
break;
}
{
CellStyle styleIn = cellIn.getCellStyle();
CellStyle styleOut = cellOut.getCellStyle();
styleOut.setDataFormat(styleIn.getDataFormat());
}
cellOut.setCellComment(cellIn.getCellComment());
// HSSFCellStyle cannot be cast to XSSFCellStyle
// cellOut.setCellStyle(cellIn.getCellStyle());
}
}
}
FileOutputStream out = new FileOutputStream(outF);
try {
wbOut.write(out);
} finally {
out.close();
}
} finally {
in.close();
}
}
}

how to add comment to a table of word by apache poi

I want to write a comment to a existing word document programmatically using apache poi. I have successfully added comments to the paragraph by the method mentioned here, but when adding comments to the table, I don't know how to associate it with real comments
BigInteger cId = BigInteger.ZERO;
ctComment = comments.addNewComment();
ctComment.setAuthor("Axel Ríchter");
ctComment.setInitials("AR");
ctComment.setDate(new GregorianCalendar(Locale.US));
ctComment.addNewP().addNewR().addNewT().setStringValue("The first comment.");
ctComment.setId(cId);
paragraph = document.createParagraph();
paragraph.getCTP().addNewCommentRangeStart().setId(cId);
run = paragraph.createRun();
run.setText("Paragraph with the first comment.");
paragraph.getCTP().addNewCommentRangeEnd().setId(cId);
paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);
in paragraph, we can use paragraph.getCTP().addNewR().addNewCommentReference().setId() to link a comment, but there seems no similar method in table. what should i do? I am a beginner to apache poi, any suggestions are greatly appreciated.
The short answer to your question how to comment a whole table is: You get the first paragraph in first cell of that table to set the CommentRangeStart as the first element in that paragraph. Then you get the last paragraph in last cell of that table to set the CommentRangeEnd as the last element in that paragraph.
But if you wants changing a already present Word document, then much more needs to be taken into account. What if there are comment already? My example you are linking is for creating a new Word document from scratch. So there cannot be comments already before. I have provided also How to manipulate content of a comment with Apache POI. But this rely on already present comments. Now we have to use a combination of both. This needs to take into account already present comments as well as a not already present comments document which then needs to be new created.
Additional there is difficulty to to set the CommentRangeStart as the first element in a already present paragraph. There are no methods for this. So we need using very low level XML manipulating to achieve this.
The following example needs a WordDocument.docx having at least one table. This whole table gets commented then.
import java.io.*;
import org.apache.poi.*;
import org.apache.poi.ooxml.*;
import org.apache.poi.openxml4j.opc.*;
import org.apache.xmlbeans.*;
import org.apache.poi.xwpf.usermodel.*;
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import javax.xml.namespace.QName;
import java.math.BigInteger;
import java.util.GregorianCalendar;
import java.util.Locale;
public class WordCommentWholeTable {
//a method to get or create the CommentsDocument /word/comments.xml in the *.docx ZIP archive
private static MyXWPFCommentsDocument createCommentsDocument(XWPFDocument document) throws Exception {
MyXWPFCommentsDocument myXWPFCommentsDocument = null;
//trying to get the CommentsDocument
for (POIXMLDocumentPart.RelationPart rpart : document.getRelationParts()) {
String relation = rpart.getRelationship().getRelationshipType();
if (relation.equals(XWPFRelation.COMMENT.getRelation())) {
POIXMLDocumentPart part = rpart.getDocumentPart();
myXWPFCommentsDocument = new MyXWPFCommentsDocument(part.getPackagePart());
String rId = document.getRelationId(part);
document.addRelation(rId, XWPFRelation.COMMENT, myXWPFCommentsDocument);
}
}
//create a new CommentsDocument if there is not one already
if (myXWPFCommentsDocument == null) {
OPCPackage oPCPackage = document.getPackage();
PackagePartName partName = PackagingURIHelper.createPartName("/word/comments.xml");
PackagePart part = oPCPackage.createPart(
partName,
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml");
myXWPFCommentsDocument = new MyXWPFCommentsDocument(part);
document.addRelation(null, XWPFRelation.COMMENT, myXWPFCommentsDocument);
}
return myXWPFCommentsDocument;
}
//a method to get the next comment Id from CTComments
private static BigInteger getCommentId(CTComments comments) {
BigInteger cId = BigInteger.ZERO;
for (CTComment ctComment : comments.getCommentList()) {
if (ctComment.getId().compareTo(cId) == 1) {
cId = ctComment.getId();
}
}
cId = cId.add(BigInteger.ONE);
return cId;
}
//method to set CommentRangeStart as first element in paragraph
private static CTMarkupRange insertCommentRangeStartAsFirstElement(XWPFParagraph paragraph) {
String uri = CTMarkupRange.type.getName().getNamespaceURI();
String localPart = "commentRangeStart";
XmlCursor cursor = paragraph.getCTP().newCursor();
cursor.toFirstChild();
cursor.beginElement(localPart, uri);
cursor.toParent();
CTMarkupRange commentRangeStart = (CTMarkupRange)cursor.getObject();
cursor.dispose();
return commentRangeStart;
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("WordDocument.docx"));
MyXWPFCommentsDocument myXWPFCommentsDocument = createCommentsDocument(document);
CTComments comments = myXWPFCommentsDocument.getComments();
CTComment ctComment;
XWPFParagraph paragraph;
XWPFRun run;
//comment for the table
BigInteger cId = getCommentId(comments);
ctComment = comments.addNewComment();
ctComment.setAuthor("Axel Ríchter");
ctComment.setInitials("AR");
ctComment.setDate(new GregorianCalendar(Locale.US));
ctComment.addNewP().addNewR().addNewT().setStringValue("This is a comment for whole table.");
ctComment.setId(cId);
//get first paragraph in first table cell to set CommentRangeStart
XWPFTable table = document.getTables().get(0);
XWPFTableRow row = table.getRow(0);
XWPFTableCell cell = row.getCell(0);
paragraph = cell.getParagraphArray(0);
CTMarkupRange commentRangeStart = insertCommentRangeStartAsFirstElement(paragraph);
commentRangeStart.setId(cId);
//get last paragraph in last table cell to set CommentRangeEnd and CommentReference
row = table.getRows().get(table.getRows().size()-1);
cell = row.getTableCells().get(row.getTableCells().size()-1);
paragraph = cell.getParagraphs().get(cell.getParagraphs().size()-1);
paragraph.getCTP().addNewCommentRangeEnd().setId(cId);
paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);
FileOutputStream out = new FileOutputStream("WordDocumentWithComments.docx");
document.write(out);
out.close();
document.close();
}
//a wrapper class for the CommentsDocument /word/comments.xml in the *.docx ZIP archive
private static class MyXWPFCommentsDocument extends POIXMLDocumentPart {
private CTComments comments;
private MyXWPFCommentsDocument(PackagePart part) throws Exception {
super(part);
try {
comments = CommentsDocument.Factory.parse(part.getInputStream(), DEFAULT_XML_OPTIONS).getComments();
} catch (Exception ex) {
// there was no comments yet
}
if (comments == null) comments = CommentsDocument.Factory.newInstance().addNewComments();
}
private CTComments getComments() {
return comments;
}
#Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTComments.type.getName().getNamespaceURI(), "comments"));
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
comments.save(out, xmlOptions);
out.close();
}
}
}

How to get list of Named range,sheet name and referance formuls using XSSF and SAX (Event API) for large excel file

I'm tring to to read large excel file (size~10MB,.xlsx) .
I'm using below code
Workbook xmlworkbook =WorkbookFactory.create(OPCPackage.openOrCreate(root_path_name_file));
But it's showing Heap memory issue.
I have also seen other solution on StackOverflow some of them given to increase the JVM but i dont want to increase jvm.
Issue 1) We can't use SXSSF (Streaming Usermodel API) because this is only for writing or creating new workbook.
My sole objective to get the number of NamedRange of sheet, Total number of sheet and their sheet name for large excel file.
If the requirement is only to get the named ranges and sheet names, then only the /xl/workbook.xml from the *.xlsx ZIPPackage must be parsed since those informations are all stored there.
This is possible by getting the appropriate PackagePart and parsing the XML from this. For parsing XML my favorite is using StAX.
Example code which gets all sheet names and defined named ranges:
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.XMLEvent;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.regex.Pattern;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
class StaxReadOPCPackageParts {
public static void main(String[] args) {
try {
File file = new File("file.xlsx");
OPCPackage opcpackage = OPCPackage.open(file);
//get the workbook package part
PackagePart workbookpart = opcpackage.getPartsByName(Pattern.compile("/xl/workbook.xml")).get(0);
//create reader for package part
XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(workbookpart.getInputStream());
List<String> sheetNames = new ArrayList<>();
Map<String, String> definedNames = new HashMap<>();
boolean isInDefinedName = false;
String sheetName = "";
String definedNameName = "";
StringBuffer definedNameFormula = new StringBuffer();
while(reader.hasNext()){ //loop over all XML in workbook.xml
XMLEvent event = (XMLEvent)reader.next();
if(event.isStartElement()) {
StartElement startElement = (StartElement)event;
QName startElementName = startElement.getName();
if(startElementName.getLocalPart().equalsIgnoreCase("sheet")) { //start element of sheet definition
Attribute attribute = startElement.getAttributeByName(new QName("name"));
sheetName = attribute.getValue();
sheetNames.add(sheetName);
} else if (startElementName.getLocalPart().equalsIgnoreCase("definedName")) { //start element of definedName
Attribute attribute = startElement.getAttributeByName(new QName("name"));
definedNameName = attribute.getValue();
isInDefinedName = true;
}
} else if(event.isCharacters() && isInDefinedName) { //character content of definedName == the formula
definedNameFormula.append(((Characters)event).getData());
} else if(event.isEndElement()) {
EndElement endElement = (EndElement)event;
QName endElementName = endElement.getName();
if(endElementName.getLocalPart().equalsIgnoreCase("definedName")) { //end element of definedName
definedNames.put(definedNameName, definedNameFormula.toString());
definedNameFormula = new StringBuffer();
isInDefinedName = false;
}
}
}
opcpackage.close();
System.out.println("Sheet names:");
for (String shName : sheetNames) {
System.out.println("Sheet name: " + shName);
}
System.out.println("Named ranges:");
for (String defName : definedNames.keySet()) {
System.out.println("Name: " + defName + ", Formula: " + definedNames.get(defName));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

Excel File Upload with Kendo UI

while I was trying to upload an excel file with kendo ui I found a code on the internet. It is using a keyword named "Constants" but this keyword does not recognize the ".xls" file extension. I am stuck at this and did some research but have no answer to solve this. Here is my code:
public ActionResult Submit(IEnumerable<HttpPostedFileBase> files)
{
if(files!= null)
{
string fileName;
string filePath;
string fileExtension;
foreach(var f in files)
{
//Set file details
SetFileDetails(f, out fileName, out filePath, out fileExtension);
if(fileExtension == Constants.xls || fileExtension == Constants.xlsx)
{
//Save the uploaded file to app folder
string savedExcelFiles = Constants.UploadedFolder + fileName;
f.SaveAs(Server.MapPath(savedExcelFiles));
ReadDataFromExcelFiles(savedExcelFiles);
}
else
{
//file not supported send alert
}
}
}
return RedirectToActionPermanent("Index","Connect");
}
private static void SetFileDetails(HttpPostedFileBase f,out string fileName,out string filePath,out string fileExtension)
{
fileName=Path.GetFileName(f.FileName);
fileExtension=Path.GetExtension(f.FileName);
filePath = Path.GetFullPath(f.FileName);
}
private void ReadDataFromExcelFiles(string savedExcelFiles)
{
var connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=Excel 12.0;",Server.MapPath(savedExcelFiles));
//fill the DataSet by the sheets
var adapter = new OleDbDataAdapter("SELECT * FROM [Sheet1$]",connectionString);
var ds = new DataSet();
List<UploadExcel> uploadExl = new List<UploadExcel>();
adapter.Fill(ds,"Subscriber");
DataTable data=ds.Tables["Subscriber"];
GetSetUploadExcelData(uploadExl,data);
}
private static void GetSetUploadExcelData (List<UploadExcel> uploadExl,DataTable data)
{
for(int i=0;i<data.Rows.Count-1;i++)
{
UploadExcel NewUpload = new UploadExcel();
NewUpload.ID = Convert.ToInt16(data.Rows[i]["ID"]);
NewUpload.CostCenter = Convert.ToString(data.Rows[i]["CostCenter"]);
NewUpload.FirstName = Convert.ToString(data.Rows[i]["FirstName"]);
NewUpload.LastName = Convert.ToString(data.Rows[i]["LastName"]);
NewUpload.MobileNo = Convert.ToString(data.Rows[i]["MobileNo"]);
NewUpload.EmailID = Convert.ToString(data.Rows[i]["EmailID"]);
NewUpload.Services = Convert.ToString(data.Rows[i]["Services"]);
NewUpload.UsageType = Convert.ToString(data.Rows[i]["UsageType"]);
NewUpload.Network = Convert.ToString(data.Rows[i]["Network"]);
NewUpload.UsageIncluded = Convert.ToInt16(data.Rows[i]["UsageIncluded"]);
NewUpload.Unit = Convert.ToString(data.Rows[i]["Unit"]);
uploadExl.Add(NewUpload);
}
}
}
I suspect that the Constants.xls relates to a static class or enum that the original code author is using to hold the .xls/.xlsx extensions.
If you create a constants class something like:
public static class Constants
{
public static string xls = "xls";
public static string xlsx = "xlsx";
}
This would then should help.
If you need any more assistance then please let me know.
edit: Just reviewing the code it seems they are also putting in constant mapping for the uploadfolder location as well so I suspect this is just a static class rather than an enum with application specific details. in a way a bit like using the appSettings within webconfig

How can i find - which portlets are deployed on which pages in Liferay 6.1?

In other words, Which Database tables do i need to look into for the mapping of a portlet to a page in an organization? If there is such a thing?! We are using Liferay 6.1.20
Apart from the marketplace portlet.
If you have access to the Database you can fire a simple query on the Layout table to know in what all pages your portlet is added:
SELECT * FROM Layout WHERE typeSettings LIKE '%my_WAR_myportlet%';
Also you can build a FinderImpl with service-builder to execute this query through a portlet and add that portlet to page to display in whatever format you want.
Below is another solution without deploying any portlet and without having access to the DB (tested on MySQL DB):
Go to Server Administration
Go to Script tab
Select Beanshell from the Language drop-down
Paste the following script code in the textarea and press the button execute:
import com.liferay.portal.kernel.dao.jdbc.DataAccess;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.StringBundler;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = DataAccess.getUpgradeOptimizedConnection();
// your custom query here
String sqlQuery = "SELECT * FROM Layout WHERE typeSettings LIKE '%my_WAR_myportlet%'";
out.println("SQL Query: "+ sqlQuery);
ps = con.prepareStatement(sqlQuery);
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
List rows = new ArrayList();
List columnLabels = new ArrayList();
columnLabels.add("Sr. No.");
for (int c = 1; c <= columnCount; c++) {
String cl = rsmd.getColumnLabel(c);
columnLabels.add(cl);
}
while (rs.next()) {
List row = new ArrayList(columnCount);
for (int c = 1; c <= columnCount; c++) {
Object value = rs.getObject(c);
row.add(value);
}
rows.add(row);
}
// --- formatting the results ---
out.append("<div class=\"lfr-search-container \"><div class=\"results-grid\">");
out.append("<table class=\"taglib-search-iterator\">");
out.append("<thead>");
out.append("<tr class=\"portlet-section-header results-header\">");
for (String value : columnLabels) {
out.append("<th>");
out.append(value);
out.append("</th>");
}
out.append("</tr>");
out.append("</thead>");
out.append("<tbody>");
boolean alt = false;
long resultsCount = 1;
for (List line : rows) {
out.append("<tr class=\"portlet-section-alternate results-row " + (alt ? "alt" : "") + "\">");
// for sr. no.
out.append("<td>");
out.append(resultsCount + "");
out.append("</td>");
resultsCount = resultsCount + 1;
for (Iterator iterator = line.iterator(); iterator.hasNext();) {
Object value = (Object) iterator.next();
out.append("<td>");
if (value != null) {
out.append(value.toString());
} else {
out.append("<span style=\"font-style:italic\">null</span>");
}
out.append("</td>");
}
out.append("</tr>");
alt = !alt;
}
out.append("</tbody>");
out.append("</table>");
out.append("</div></div>");
} catch (Exception exp) {
out.println("ERROR: " + exp);
throw exp;
}
finally {
DataAccess.cleanUp(con, ps, rs);
}
Please remember to change the string my_WAR_myportlet to your portletId
Needless to say you can modify the script to update the styles and can show selective columns. Also you can run any SQL query, just update String sqlQuery.
Hope this helps.
This is the solution, a free marketplace plugin that resolve your issue.
http://www.liferay.com/it/marketplace/-/mp/application/27156990
Here is a code to get all the portlets from the first column
ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
Layout layout = themeDisplay.getLayout();
LayoutTypePortlet layoutTypePortlet = (LayoutTypePortlet) layout.getLayoutType();
List<Portlet> portlets = layoutTypePortlet.getAllPortlets("column-1");
for (Portlet portlet : portlets) {
// print your portlet.getPortletId() or do whatever you need
}
[layout] is the table in which you can find out which portlets(typeSettings ) are deployed on which page

Resources