I try to create a new table depending on input data and insert it into an docx-document.
Following leads to a corrupted output file:
private Tbl getSampleTable(WordprocessingMLPackage wPMLpackage) {
ObjectFactory factory = Context.getWmlObjectFactory();
int writableWidthTwips = wPMLpackage.getDocumentModel().getSections().get(0).getPageDimensions().getWritableWidthTwips();
List<Map<String, String>> data = getSampleTableData();
TableDefinition tableDef = getSampleTableDef();
int cols = tableDef.getColumns().size();
int cellWidthTwips = new Double(Math.floor((writableWidthTwips / cols))).intValue();
Tbl table = TblFactory.createTable((data.size() + 1), cols, cellWidthTwips);
Tr headerRow = (Tr) table.getContent().get(0);
int f = 0;
for (Column column : tableDef.getColumns()) {
Tc column = (Tc) headerRow.getContent().get(f);
f++;
Text text = factory.createText();
text.setValue(column.getName());
R run = factory.createR();
run.getContent().add(text);
column.getContent().add(run);
headerRow.getContent().add(column);
}
int i = 1;
for (Map<String, String> entry : data) {
Tr row = (Tr) table.getContent().get(i);
i++;
int p = 0;
for (String key : entry.keySet()) {
Tc column = (Tc) row.getContent().get(p);
p++;
Text tx = factory.createText();
R run = factory.createR();
tx.setValue(entry.get(key));
run.getContent().add(tx);
column.getContent().add(run);
row.getContent().add(column);
}
}
return table;
}
Without inserting the table the docx-document is created how it shall be.
I use the this function by trying to insert this table in an file that I receive as input parameter:
ByteArrayInputStream bis = new ByteArrayInputStream(file);
WordprocessingMLPackage wPMLpackage = null;
wPMLpackage = WordprocessingMLPackage.load(bis);
// Zip it up
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SaveToZipFile saver = new SaveToZipFile(wPMLpackage);
saver.save(baos);
byte[] template = baos.toByteArray();
WordprocessingMLPackage target = WordprocessingMLPackage.load(new ByteArrayInputStream(template));
target.getMainDocumentPart().getContent().clear();
target.getMainDocumentPart().addObject(getSampleTable(target));
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
SaveToZipFile saver2 = new SaveToZipFile(target);
saver2.save(baos2);
return baos2.toByteArray();
Someone has an idea why the generated file can't be interpreted by Microsoft Word? The error message is "The file can't be opened as its contents causes problems". Manipulation of the document works as long as I don't insert this table.
Inserting the runs in paragraphs leads to the desired result:
private Tbl getSampleTable(WordprocessingMLPackage wPMLpackage) {
ObjectFactory factory = Context.getWmlObjectFactory();
int writableWidthTwips = wPMLpackage.getDocumentModel().getSections()
.get(0).getPageDimensions()
.getWritableWidthTwips();
List<Map<String, String>> data = getSampleTableData();
TableDefinition tableDef = getSampleTableDef();
int cols = tableDef.getColumns().size();
int cellWidthTwips = new Double(
Math.floor((writableWidthTwips / cols))
).intValue();
Tbl table = TblFactory.createTable((data.size() + 1), cols, cellWidthTwips);
Tr headerRow = (Tr) table.getContent().get(0);
int f = 0;
for (Column column : tableDef.getColumns()) {
Tc column = (Tc) headerRow.getContent().get(f);
P columnPara = (P) column.getContent().get(0);
f++;
Text text = factory.createText();
text.setValue(column.getName());
R run = factory.createR();
run.getContent().add(text);
columnPara.getContent().add(run);
}
int i = 1;
for (Map<String, String> entry : data) {
Tr row = (Tr) table.getContent().get(i);
i++;
int d = 0;
for (String key : entry.keySet()) {
Tc column = (Tc) row.getContent().get(d);
P columnPara = (P) column.getContent().get(0);
d++;
Text tx = factory.createText();
R run = factory.createR();
tx.setValue(entry.get(key));
run.getContent().add(tx);
columnPara.getContent().add(run);
}
}
return table;
}
In creating a table (or anything else for that matter), one approach worth bearing in mind is to create what you want in Word, then use one of the docx4j code gen tools to generate corresponding Java code.
The code gen tool is available 2 ways:
online at http://webapp.docx4java.org/OnlineDemo/PartsList.html
or as a Word AddIn, see http://www.docx4java.org/forums/docx4jhelper-addin-f30/
The advantage of the Word AddIn is that you avoid the save-upload cycle.
Related
I need to put a check symbol in this cell if the condition met. Here's my sample code:
private SXSSFWorkbook RepWkBook = null;
private SXSSFSheet RepSheet = null;
private int RepRowNum = 0;
private ResultSet RepResult = null;
private Row RepRow = null;
RepSheet = RepWkBook.createSheet(reportType);
RepRowNum = 0;
Row row = RepSheet.createRow(RepRowNum++);
CellStyle cellStyle = RepWkBook.createCellStyle();
Font font = RepWkBook.createFont();
font.setBold(true);
cellStyle.setFont(font);cell = RepRow.createCell(col++);
boolean isMOBhigherThanArea = RepResult.getString("IS_MOB_HIGHER_THAN_AREA").equalsIgnoreCase("1");
char st = '\u2713';
if(isMOBhigherThanArea && (!areaStr.equalsIgnoreCase("No Data") || !mobStr.equalsIgnoreCase("No Data"))) {
cell.setCellValue(st);}
I already used
UTF-16 - feff2713
UTF-16BE - 2713
UTF-16LE - 1327
UTF-8 - e29c93
click here for sample output
SAMPLE EXPECTED OUTPUT
Area | MOB Target | Area Result | MOB > Area
City | 85% | 80% | ✔
There is no method setCellValue which takes a char. Try using a String there.
The following works for me:
import java.io.FileOutputStream;
import org.apache.poi.xssf.streaming.*;
class CreateSXSSFUnicode {
public static void main(String[] args) throws Exception {
char st = '\u2713';
String[] headers = new String[] {"Area", "MOB Target", "Area Result", "MOB > Area"};
try (SXSSFWorkbook workbook = new SXSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {
SXSSFSheet sheet = workbook.createSheet();
SXSSFRow row;
int rowNum = 0;
row = sheet.createRow(rowNum++);
for (int c = 0; c < headers.length; c++) {
row.createCell(c).setCellValue(headers[c]);
}
row = sheet.createRow(rowNum++);
int c = 0;
row.createCell(c++).setCellValue("City");
row.createCell(c++).setCellValue("85%");
row.createCell(c++).setCellValue("80%");
//row.createCell(c++).setCellValue(st); // does not work as st is a char
row.createCell(c++).setCellValue(String.valueOf(st)); // this works
workbook.write(fileout);
workbook.dispose();
}
}
}
Result:
Try using
ChrW(&H2713)
(source: https://www.mrexcel.com/board/threads/how-to-insert-a-checkmark-with-vba.607363/)
The only way that I can think of doing that is formatting your cell with a symbolic font, as Windings, and use the proper character for the check symbol in this font.
So your code would be something like:
Font font = RepWkBook.createFont();
font.setBold(true);
Font wingDingFont = RepWkBook.createFont();
wingDingFont.setBold(true);
wingDingFont.setFontName("Wingdings);
cell = RepRow.createCell(col++);
boolean isMOBhigherThanArea = RepResult.getString("IS_MOB_HIGHER_THAN_AREA").equalsIgnoreCase("1");
if(isMOBhigherThanArea && (!areaStr.equalsIgnoreCase("No Data") || !mobStr.equalsIgnoreCase("No Data"))) {
String st = "ü";
cellStyle.setFont(wingDingFont);
cell.setCellValue(st);
} else {
cellStyle.setFont(font);
}
I'm receiving an error when opening my OpenXML created spreadsheet. The error is as follows.
repaired record : xl/worksheets/sheet.xml partial cell information
private void SavexlsExcelFile(String fullPathName)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(fullPathName, SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
Columns columns = new Columns();
worksheetPart.Worksheet.AppendChild(columns);
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Sheet" };
sheets.Append(sheet);
workbookPart.Workbook.Save();
sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
List<List<string>> dataRow = new List<List<string>>();
List<String> dtRow = new List<String>();
Row row = new Row();
for (int i = 0; i < dataGridView1.RowCount; i++)
{
for (int j = 0; j < dataGridView1.ColumnCount; j++)
{
if (i == 0)
{
Cell dataCell = new Cell();
dataCell.DataType = CellValues.String;
CellValue cellValue = new CellValue();
cellValue.Text = dataGridView1.Columns[j].Name;
dataCell.StyleIndex = 2;
dataCell.Append(cellValue);
row.AppendChild(dataCell);
//dataColumn.Add(dataGridView1.Columns[j].Name);
}
dtRow.Add(dataGridView1.Rows[i].Cells[j].Value.ToString());
}
}
dataRow.Add(dtRow);
sheetData.AppendChild(row);
row = new Row();
foreach (List<string> datarow in dataRow)
{
row = new Row();
foreach(string dtrow in datarow)
{
row.Append(ConstructCell(dtrow, CellValues.String, 2));
}
sheetData.AppendChild(row);
}
worksheetPart.Worksheet.Save();
}
}
private Cell ConstructCell(string value, CellValues dataType, uint styleIndex = 0)
{
return new Cell()
{
CellValue = new CellValue(value),
DataType = new EnumValue<CellValues>(dataType),
StyleIndex = styleIndex
};
}
There are 2 issues here that I can see. The first is that your use of Columns is incorrect. You should use Columns if you wish to control things such as the width of a column. To use Columns correctly, you'll need to add child Column elements. For example (taken from here):
Columns columns = new Columns();
columns.Append(new Column() { Min = 1, Max = 3, Width = 20, CustomWidth = true });
columns.Append(new Column() { Min = 4, Max = 4, Width = 30, CustomWidth = true });
In your sample you could just remove the following two lines
Columns columns = new Columns();
worksheetPart.Worksheet.AppendChild(columns);
The second issue is the StyleIndex you are using; the style doesn't exist in your document because you haven't added it. The easiest thing to do here is to just remove the StyleIndex altogether.
When debugging files like this, it's always worth looking at the OpenXml Productivity Tool. You can open a generated file in the tool and validate it to see what errors you have in your file.
All the text in Excel is stored under a shared string table. You need to insert the string in shared string table:
string text = dataGridView1.Columns[j].Name;
cell.DataType = CellValues.SharedString;
if (!_spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Any())
{
_spreadSheet.WorkbookPart.AddNewPart<SharedStringTablePart>();
}
var sharedStringTablePart = _spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
if (sharedStringTablePart.SharedStringTable == null)
{
sharedStringTablePart.SharedStringTable = new SharedStringTable();
}
//Iterate through shared string table to check if the value is already present.
foreach (SharedStringItem ssItem in sharedStringTablePart.SharedStringTable.Elements<SharedStringItem>())
{
if (ssItem.InnerText == text)
{
cell.CellValue = new CellValue(ssItem.ElementsBefore().Count().ToString());
SaveChanges();
return;
}
}
// The text does not exist in the part. Create the SharedStringItem.
var item = sharedStringTablePart.SharedStringTable.AppendChild(new SharedStringItem(new Text(text)));
cell.CellValue = new CellValue(item.ElementsBefore().Count().ToString());
Here is the code below to fetch data from one sheet. Now my query is how can i store this all output data, so that i can write another method to paste it in a diffrent sheet.
public void ReadCount(String Path) {
String []module;
int [][]status;
try {
FileInputStream fs = new FileInputStream(new File(Path));
XSSFWorkbook workBook = new XSSFWorkbook(fs);
boolean isPresent = false;
XSSFSheet sheet = workBook.getSheetAt(0);
for (int i=0; i<sheet.getLastRowNum(); i++) {
Row r = sheet.getRow(i);
for (int cn=0; cn<r.getLastCellNum(); cn++) {
Cell c = r.getCell(cn);
c.setCellType ( Cell.CELL_TYPE_STRING );
String text = c.getStringCellValue();
if(text.trim().equalsIgnoreCase("Module Name")) {
for(int a = i+2; a<sheet.getLastRowNum(); a++) {
Row p = sheet.getRow(a);
Cell q = p.getCell(cn);
q.setCellType ( Cell.CELL_TYPE_STRING );
String m = q.getStringCellValue();
System.out.println(m);
Cell k = p.getCell(cn+1);
k.setCellType ( Cell.CELL_TYPE_NUMERIC );
double PASS = k.getNumericCellValue();
int P = (int)PASS;
System.out.println(P);
Cell l = p.getCell(cn+2);
l.setCellType ( Cell.CELL_TYPE_NUMERIC );
double FAIL = l.getNumericCellValue();
int F = (int)FAIL;
System.out.println(F);
Cell n = p.getCell(cn+3);
n.setCellType ( Cell.CELL_TYPE_NUMERIC );
double ONHOLD = n.getNumericCellValue();
int O = (int)ONHOLD;
System.out.println(O);
}
//return module;
}
}
}
} catch(IOException e) {
e.printStackTrace();
}
}
The console output for this method is
ROW1
1
0
0
ROW2
1
0
0
ROW3
0
1
0
ROW4
0
1
1
I am using apache POI for excel import and parsing .
I have to get the data by passing column name .
this is my code
JSONObject jo = new JSONObject();
JSONArray dataCollection = new JSONArray();
JSONObject data = null;
try {
String tempCampaignFilesPath = getSessionData("userPath") + System.getProperty("file.separator") + "tempCampaignFiles";
File someFile = new File(tempCampaignFilesPath, fileName);
/* read from this file */
FileInputStream fileInputStream = new FileInputStream(someFile);
HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
HSSFSheet sheet = workbook.getSheet(sheetName);
int rowNum = sheet.getLastRowNum() + 1;
int colNum = sheet.getRow(0).getLastCellNum();
Row row = null;
Cell cell = null;
for (int i = 1; i < rowNum; i++) {
row = sheet.getRow(i);
data = new JSONObject();
for (int j = 0; j < colNum; j++) {
cell = row.getCell(j);
data.put(columnList.get(j), cellToString(cell));
}
dataCollection.put(data);
}
fileInputStream.close();
// someFile.delete();
jo.put("tableData", dataCollection);
} catch (Exception e) {
e.printStackTrace();
}
return jo;
There is a provision for column index but how could I do it by column name.
Please help me.
You have to convert column name to index:
int colIdx = CellReference.convertColStringToIndex(letter);
CellUtil.getCell(row, colIdx)
or if you need convert column index to string:
String colName = CellReference.convertNumToColString(colIdx)
Please find below the code an another workaround for this .Please see the comments in code to be more clear what I have done.
JSONObject jo = new JSONObject();
JSONArray dataCollection = new JSONArray();
JSONObject data = null;
try {
String tempCampaignFilesPath = getSessionData("userPath") + System.getProperty("file.separator") + "tempCampaignFiles";
File someFile = new File(tempCampaignFilesPath, fileName);
/* read from this file */
FileInputStream fileInputStream = new FileInputStream(someFile);
HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
HSSFSheet sheet = workbook.getSheet(sheetName);
int rowNum = sheet.getLastRowNum() + 1;
int colNum = sheet.getRow(0).getLastCellNum();
Row row = null;
Cell cell = null;
/* first row data for column names and index */
Map<String, Integer> colMapByName = new HashMap<String, Integer>();
if (sheet.getRow(0).cellIterator().hasNext()) {
for (int j = 0; j < colNum; j++) {
colMapByName.put(cellToString(sheet.getRow(0).getCell(j)), j);
}
}
System.out.println(colMapByName);//shows the indexes of columns populated by traversing first row
/* first row data */
for (int i = 1; i < rowNum; i++) {
row = sheet.getRow(i);
data = new JSONObject();
//colMap consists the columnnames and alias name for it
for (Entry<String, String> colData : colMap.entrySet()) {
cell = row.getCell(colMapByName.get(colData.getValue()));//gives the index of column from colMapByName Map by passing column name
data.put(colData.getKey(), cellToString(cell));//now the data passed to the alias for the column tobe used in application
}
dataCollection.put(data);
}
fileInputStream.close();
someFile.delete();
jo.put("tableData", dataCollection);
} catch (Exception e) {
e.printStackTrace();
}
return jo;
I am trying to search a query from Apache Lucene index. The search is returning a large amount of result, I have to fill the result in JTable using Swing. I am using the loop to extract the object row from Apache Lucene index.
For the above reason if there are thousands of the record then it takes time to fill the records in table , I am using the following code. Is there any other way to achieve the task without running the loop?
try { File indexDir= new File("path of the file")
Directory directory = FSDirectory.open(indexDir);
IndexSearcher searcher = new IndexSearcher(directory, true);
int maxhits=1000000;
QueryParser parser1 = new QueryParser(Version.LUCENE_36, "field",
new StandardAnalyzer(Version.LUCENE_36));
Query qu=parser1.parse("texttosearch");
TopDocs topDocs = searcher.search(, maxhits);
ScoreDoc[] hits = topDocs.scoreDocs;
len = hits.length;
int docId = 0;
Document d;
Vector column_name=new Vector();
column_name.addElement("title");
column_name.addElement("");
// For All Rows Data
Vector row=new Vector();
String filename="";
String titlee="";
Vector newRow=new Vector();
for ( i = 0; i<len; i++) {
docId = hits[i].doc;
d = searcher.doc(docId);
filename= d.get(("fpath"));
titlee=d.get("title");
newRow= new Vector();
newRow.addElement(titlee);
newRow.addElement(filename);
row.addElement(newRow);
}
DefaultTableModel model= new DefaultTableModel(row, column_name);
table.setModel(model);
}
catch(Exception ex)
{
ex.printStackTrace();
}
small mistakes sometimes creates big troubles
Vector row = new Vector(); should be Vector<Vector<Object>> row = new Vector<Vector<Object>>();
first line in loop for (i = 0; i < len; i++) { must be newRow = new Vector();
pseudo code
for (i = 0; i < len; i++) {
// must be otherwise first Vector is added forever!!!
newRow = new Vector();
//loop, add elements to one dimensional Vector
// add 1D Vector to 2D Vector used and implemented in JTables API
row.addElement(newRow);
}
I'd be to define variable in form Vector<Object> newRow = new Vector<Object>();
everything important is described in Oracle turorial How to use Tables