How parse this excel? [closed] - java

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 10 months ago.
Improve this question
I have an excel file, i have to parse to list of objects:
excel:
excel
my pojo:
my service:
public List<RegisterModel> parse(MultipartFile file) throws IOException {
Workbook workbook = new HSSFWorkbook(file.getInputStream());
Sheet worksheet = workbook.getSheetAt(0);
List<RegisterModel> registerModelList = new ArrayList<>();
RegisterModel registerModel = new RegisterModel();
for (int i = 3; i < worksheet.getPhysicalNumberOfRows(); i++) {
Row row = worksheet.getRow(i);
String headers = String.valueOf(row.getCell(0));
String values = String.valueOf(row.getCell(1));
if (headers.equals("OPERDAY")){
registerModel.setDate(values);
}
if (headers.equals("SUIP")){
registerModel.setSuip(values);
}
if (headers.equals("STATE")){
registerModel.setSuip(values);
}
if (headers.equals("NOM_OPER")){
registerModel.setTransactionID(values);
}
registerModelList.add(registerModel);
}
System.out.println(registerModelList);
return registerModelList;
}
but it is not works(
result: values are duplicate
[RegisterModel(date=2022-03-01T23:48:47, suip=Проведён, state=null, transactionID=1888314188),
RegisterModel(date=2022-03-01T23:48:47, suip=Проведён, state=null, transactionID=1888314188),
RegisterModel(date=2022-03-01T23:48:47, suip=Проведён, state=null, transactionID=1888314188)]

The issue is caused by only creating a single instance of registerModel outside of your for loop. You just keep editing that object over and over instead of creating new instances of it. The way to solve this is to create a new instance of registerModel every time a previous object is completed or before a new object is started.
There are multiple ways to achieve this by using nested loops or incrimenting your for loop by 5 at a time (rows in your order) and specifically keeping track of where items are at. However, if we assume that the last bit of data in an order is the "NOM_OPER" row then we can do the following quick and easy solution.
This is the code that has been changed:
if (headers.equals("NOM_OPER")){
registerModel.setTransactionID(values);
//Now that the object is complete we can add it to the list (moved here from below)
registerModelList.add(registerModel);
//The lastly we NEED to create a new instance of registerModel for the next order to use
registerModel = new RegisterModel();
}
//Remove the below line after the if statements.
//You should only add the model to the list once the object is complete. Don't add it on every row.
//registerModelList.add(registerModel);
And the complete method looks like this:
public List<RegisterModel> parse(MultipartFile file) throws IOException {
Workbook workbook = new HSSFWorkbook(file.getInputStream());
Sheet worksheet = workbook.getSheetAt(0);
List<RegisterModel> registerModelList = new ArrayList<>();
RegisterModel registerModel = new RegisterModel();
for (int i = 3; i < worksheet.getPhysicalNumberOfRows(); i++) {
Row row = worksheet.getRow(i);
String headers = String.valueOf(row.getCell(0));
String values = String.valueOf(row.getCell(1));
if (headers.equals("OPERDAY")){
registerModel.setDate(values);
}
if (headers.equals("SUIP")){
registerModel.setSuip(values);
}
if (headers.equals("STATE")){
registerModel.setSuip(values);
}
if (headers.equals("NOM_OPER")){
registerModel.setTransactionID(values);
//Now that the object is complete we can add it to the list (moved here from below)
registerModelList.add(registerModel);
//The lastly we NEED to create a new instance of registerModel for the next order to use
registerModel = new RegisterModel();
}
//Remove the below line after the if statements.
//You should only add the model to the list once the object is complete. Don't add it on every row.
//registerModelList.add(registerModel);
}
System.out.println(registerModelList);
return registerModelList;
}

Related

Can't change row text in .docx file once row is added to table

I have the problem with the following code:
XWPFTable table = <get table somehow>;
CTRow firstRow = table.getRow(0).getCtRow();
for (int i = 0; i < data.getRowCount(); i++) {
CTRow ctRow = (CTRow) firstRow.copy();
XWPFTableRow row = new XWPFTableRow(ctRow, table);
XWPFRun[] cellRuns = row.getTableCells()
.stream()
.map(c -> c.getParagraphs().get(0))
.map(p -> p.getRuns().isEmpty() ? p.createRun() : p.getRuns().get(0))
.toArray(XWPFRun[]::new);
for (int j = 0; j < cellRuns.length; j++) {
cellRuns[j].setText(data.getValueAt(i, j).toString(), 0);
}
table.addRow(row);
}
table.getRow(1).getTableCells()
.get(0).getParagraphs()
.get(0).getRuns()
.get(0).setText("FooBar", 0); //change text in some added row
This code is copying the first row of the table several times and then copying values from data. Works perfectly fine (except text style) except the last operator, which was supposed to change the text in some added table row. Also, the "FooBar" string doesn't even appear in document.xml of created WORD document. I failed to see any clues from debug, because it seems, that table.addRow(row); operator just copies row pointer to it's internal list of rows. Also, I didn't have problems with altering already existing rows. So do you have any ideas why this could happen?
To reproducing the problem do having a source.docx having a first table having at least two rows.
Then do running following code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
public class WordInsertTableRow {
static XWPFTableRow insertNewTableRow(XWPFTableRow sourceTableRow, int pos) throws Exception {
XWPFTable table = sourceTableRow.getTable();
CTRow newCTRrow = CTRow.Factory.parse(sourceTableRow.getCtRow().newInputStream());
XWPFTableRow tableRow = new XWPFTableRow(newCTRrow, table);
table.addRow(tableRow, pos);
return tableRow;
}
static void commitTableRows(XWPFTable table) {
int rowNr = 0;
for (XWPFTableRow tableRow : table.getRows()) {
table.getCTTbl().setTrArray(rowNr++, tableRow.getCtRow());
}
}
public static void main(String[] args) throws Exception {
XWPFDocument doc = new XWPFDocument(new FileInputStream("source.docx"));
boolean weMustCommitTableRows = false;
XWPFTable table = doc.getTableArray(0);
// insert new row, which is a copy of row 2, as new row 3:
XWPFTableRow sourceTableRow = table.getRow(1);
XWPFTableRow newRow3 = insertNewTableRow(sourceTableRow, 2);
// now changing something in that new row:
int i = 1;
for (XWPFTableCell cell : newRow3.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
for (XWPFRun run : paragraph.getRuns()) {
run.setText("New row 3 run " + i++, 0);
}
}
}
System.out.println(newRow3.getCtRow()); // was changed
System.out.println(table.getRow(2).getCtRow()); // even this is changed
System.out.println(table.getCTTbl().getTrArray(2)); // but this was not changed, why not?
weMustCommitTableRows = true;
if (weMustCommitTableRows) commitTableRows(table); // now it is changed
FileOutputStream out = new FileOutputStream("result.docx");
doc.write(out);
out.close();
doc.close();
}
}
This code creates a copy of second row and inserts it as third row in the table. Then it does changing something in that new third row.
The issue ist, that the changings do appearing in low level CTRow of the row itself but do not appearing in low Level CTTbl of the table. For me this is not logically and I cannot get the reason of that. It looks as if the new CTRow elements are not part of the CTTbl at all. But they were added to it using ctTbl.setTrArray in XWPFTable.addRow. So I suspect there is something wrong with setTrArray in org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl. It seems updating the XML correctly but losing the object relations in the array (or list) of CTRows in CTTbl. But this is very hard to determining because of the kind of programming the org.openxmlformats.schemas classes. At least I was not able to do so. Maybe another of the professional and enthusiast programmers here may be able?
I am using the same approach for inserting rows having tthe same styling as a given source row. But after I have done this, I am setting boolean weMustCommitTableRows = true; and then I am doing if (weMustCommitTableRows) commitTableRows(table); before writing out the document. Then all changings will be committed.

Delete multiple columns in NatTable

I'm using NatTable to display table data, the table can be sorted and filtered. Since the table is quite large I also used GlazedList. I need to be able to remove columns after sorting and filtering. As I tried, I could only remove the content of the table but the header remains there. The column header is nested in many layers and I don't know I could affect or trigger a refresh on it.
My code are mostly from the examples with slight modifications:
set up the layers:
ModelProvider mp = new ModelProvider();
// property names of the Person class
this.propertyNames = new String[this.attributeNames.size() + 1];
this.propertyNames[0] = "Entry";
for (int i = 0; i < this.attributeNames.size(); i++) {
this.propertyNames[i + 1] = this.attributeNames.get(i);
}
// mapping from property to label, needed for column header labels
this.propertyToLabelMap = new HashMap<String, String>();
for (String str : this.propertyNames) {
this.propertyToLabelMap.put(str, str);
}
IColumnPropertyAccessor<GazEntry> columnPropertyAccessor = new GazColumnPropertyAccessor();
final BodyLayerStack<GazEntry> bodyLayerStack = new BodyLayerStack<GazEntry>(
mp.entrylines, columnPropertyAccessor);
IDataProvider columnHeaderDataProvider =
new DefaultColumnHeaderDataProvider(this.propertyNames, this.propertyToLabelMap);
final DataLayer columnHeaderDataLayer =
new DataLayer(columnHeaderDataProvider);
final ColumnHeaderLayer columnHeaderLayer =
new ColumnHeaderLayer(columnHeaderDataLayer, bodyLayerStack, bodyLayerStack.getSelectionLayer());
SortHeaderLayer<GazEntry> sortHeaderLayer =
new SortHeaderLayer<GazEntry>(
columnHeaderLayer,
new GlazedListsSortModel<GazEntry>(
bodyLayerStack.getSortedList(),
columnPropertyAccessor,
configRegistry,
columnHeaderDataLayer));
// build the column header layer
// Note: The column header layer is wrapped in a filter row composite.
// This plugs in the filter row functionality
FilterRowHeaderComposite<GazEntry> filterRowHeaderLayer = new FilterRowHeaderComposite<GazEntry>(
new DefaultGlazedListsFilterStrategy<GazEntry>(
bodyLayerStack.getFilterList(), columnPropertyAccessor,
configRegistry), sortHeaderLayer,
columnHeaderDataLayer.getDataProvider(), configRegistry);
// build the row header layer
IDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(
bodyLayerStack.getBodyDataProvider());
DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(
rowHeaderDataProvider);
final ILayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer,
bodyLayerStack, bodyLayerStack.getSelectionLayer());
// build the corner layer
IDataProvider cornerDataProvider = new DefaultCornerDataProvider(
columnHeaderDataProvider, rowHeaderDataProvider);
DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
ILayer cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer,
filterRowHeaderLayer);
IRowDataProvider<GazEntry> bodyDataProvider = (IRowDataProvider<GazEntry>) bodyLayerStack.getBodyDataProvider();
bodyLayerStack.setConfigLabelAccumulator(new CrossValidationLabelAccumulator(
bodyDataProvider));
// DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
bodyLayerStack.registerCommandHandler(new
DeleteRowCommandHandler<GazEntry>(bodyLayerStack.bodyData));
//TODO: register delete column.
bodyLayerStack.registerCommandHandler(new
DeleteColCommandHandler<GazEntry>(bodyLayerStack.bodyData));
and the command handler to delete a column
class DeleteColCommandHandler<T> implements ILayerCommandHandler<DeleteColCommand> {
private List<T> bodyData;
public DeleteColCommandHandler(List<T> bodyData) {
this.bodyData = bodyData;
}
#Override
public Class<DeleteColCommand> getCommandClass() {
return DeleteColCommand.class;
}
//TODO: delete column
#Override
public boolean doCommand(ILayer targetLayer, DeleteColCommand command) {
// convert the transported position to the target layer
if (command.convertToTargetLayer(targetLayer)) {
// remove the element
// this.bodyData.remove(command.getRowPosition());
SelectionLayer slayer = ((BodyLayerStack) targetLayer).getSelectionLayer();
int[] selected = slayer.getSelectedColumnPositions();
for (int index : selected) {
String colName = CopyOf_6031_GlazedListsFilterExample.this.propertyNames[index];
CopyOf_6031_GlazedListsFilterExample.this.attributeNames.remove(colName);
targetLayer.fireLayerEvent(new
ColumnDeleteEvent(targetLayer, index));
}
return true;
}
return false;
}
}
as said, this deletes the column content but leaves the header. Can anyone tell me how I can also remove the column header?
Do you really want to delete a column or do you simply want to hide a column? Because hiding would be much easier. Of course this depends on your use case and if your data model can be modified to really deleting a column.
Nevertheless, the DefaultColumnHeaderDataProvider does not support dynamic adding or removing columns as it is based on an array. For such an use case you need to provide a custom IDataProvider for the column header. The NatTable Examples application contains an example for that under Tutorial Examples -> Data -> DynamicColumnExample.
You simply need to implement an IDataProvider that is based on a List rather than an array, so elements can be removed and the size modified.

How to read a csv and create a list of maps out of each line?

I have a Java class to automate some behaviour on the web, my only problem is that now instead of the static data that I have I need to use the data from the csv.
for example:
this is one of the actions in my automation class:
WebElement supplierAddressField = driver.findElement(By.id("FieldaddressOfSupplierLine"));
supplierAddressField.sendKeys("hollywood blvd 34");
So now, instead of the static "supplier address" value I want to iterate on each line of the .sendKeys(csvLineMap.get("supplier address"));
Because in each line I dont need all the headers info, this is why I think it will be the best to just create a list of maps, that each map key will be the header of the csv and the value will be the value for this header in a specific line.
this is the structure of the csv:
Please help me to figure this out...thanksss!!
Apache Commons CSV
For what you are asking for I would recommend you look at Apache Commons CSV. One of the examples from their User Guide matches very closely with with the examples you are trying
Reader in = new FileReader("path/to/file.csv");
Iterable<CSVRecord> records = CSVFormat.EXCEL.parse(in);
for (CSVRecord record : records) {
String lastName = record.get("Last Name");
String firstName = record.get("First Name");
}
ok, this might be overly complex for what you want, but I always open csv's as excel files because then you can run down the columns. The code for picking up any column would look like this:
Workbook w = Workbook.getWorkbook(inputWorkbook);
Sheet sheet = w.getSheet(0);
nom = sheet.getRows();
String[][] SheetArray = new String [2][nom];
// change the first number to the number of columns you want,
// or pick up the number same as you did with rows
Cell cell;
// GETS DATA FROM SHEET AND RUNS THROUGH WHOLE LOOP BELOW FOR EACH REFERENCE
for(int j =0;j<sheet.getRows();j++) // cycles through rows and loads into 2d array
{ // start 6
cell = sheet.getCell(0, j); <- your column number here
cellcont = cell.getContents();
SheetArray[0][j] = cellcont;
// repeat the above block for each column you want
} // end 6
you now have a 2d array with all the info in it which you can handle however you want.
wrap the entire thing in a try .. catch.
With uniVocity-parsers you can parse only the fields you are interested, in any order:
CsvParserSettings parserSettings = new CsvParserSettings();
// Let's extract headers
parserSettings.setHeaderExtractionEnabled(true);
parserSettings.selectFields("Field 5", "Field 1");
//Rows will come organized according to your field selection
List<String[]> allRows = parser.parseAll("path/to/file.csv");
If you prefer, you can easily get a map with the values of all columns:
CsvParserSettings parserSettings = new CsvParserSettings();
// Let's extract headers
parserSettings.setHeaderExtractionEnabled(true);
// To get the values of all columns, use a column processor
ColumnProcessor rowProcessor = new ColumnProcessor();
parserSettings.setRowProcessor(rowProcessor);
CsvParser parser = new CsvParser(parserSettings);
//This will kick in our column processor
parser.parse(new FileReader("path/to/file.csv"));
//Finally, we can get the column values:
Map<String, List<String>> columnValues = rowProcessor.getColumnValuesAsMapOfNames();
Have a look. It is faster than any other parser and you can do much more, such as converting the values and generating java beans.
Disclosure: I am the author of this library. It's open-source and free (Apache V2.0 license).

Fixing some content at the end of first page aspose words java

I am working with apose words java recently.
In my first page I have a table need to merge, which can grow any size, no fixed number of rows and at the end of my first page, I want to keep some content (for example contact details) to be fixed. (Note: I can't keep contact details in Footer or in foot note section because of some formatting I need to ensure which can't maintain in footer or foot note section)
On growing of table as many rows, My content is going down, But I want to fix it at the end of my first page. if table grows bigger in size, wanted to skip the content and render table in next page.
is there any solution/work around for this?
My expected results are like below....
Page 1 Start
dynamic Table row1
dynamic Table row2
dynamic Table row3
Contact Details ,wanted to fix at the end of my first page
Page 1 end
Page 2 Start
dynamic table row 4
dynamic table row 5
........
For your scenario, ideally the contact details should be set in a footer. It is possible, but very risky.
First create a new document, either in Aspose.Words or MS Word, it will be used as a template.
Add a blank table on top
Add contact details, after the blank table
Add a bookmark, after the contact details
Now, using Aspose.Words, you can check the location of the bookmark, every time you are adding a new row in the table. If bookmark is at page 1, add new row to the first table. If bookmark is at page 2, add new row to the second table. Below is the sample code that adds rows to the table, keeping the contact details fixed on page 1.
Template document: Google drive link
Java source code is given below.
public static void main(String[] args)
{
try
{
String template = Common.DATA_DIR + "Contact Template.docx";
String saveDocument = Common.DATA_DIR + "Contact with tables.docx";
String bookmarkNameContact = "ContactEnd";
// Load the template
com.aspose.words.Document wordDoc = new com.aspose.words.Document(template);
DocumentBuilder builder = new DocumentBuilder(wordDoc);
// Find the contacts bookmark
com.aspose.words.Bookmark bookmarkContact = wordDoc.getRange().getBookmarks().get(bookmarkNameContact);
// Set the table with null
com.aspose.words.Table table = null;
// Add some rows
for (int i = 0; i < 50; i++)
{
// If contacts bookmark is on 1st page, add new rows to first table
if (getBookmarkPage(wordDoc, bookmarkContact) == 1)
{
table = (com.aspose.words.Table) wordDoc.getChild(NodeType.TABLE, 0, true);
} else
{
// If the contacts bookmark is on second page, add rows to second table
table = (com.aspose.words.Table) wordDoc.getChild(NodeType.TABLE, 1, true);
// If there is no second table, create it
if (table == null)
{
table = createNewTable(wordDoc, bookmarkContact);
}
}
// Add rows dynamically to either first or second table
addRow(wordDoc, table, "some text " + i);
}
// Save the document
wordDoc.save(saveDocument);
} catch (Exception ex)
{
System.err.println(ex.getMessage());
}
}
private static com.aspose.words.Table createNewTable(com.aspose.words.Document wordDoc, com.aspose.words.Bookmark bookmarkContact) throws Exception
{
// Get the first table and clone it to create the second one
com.aspose.words.Table firstTable = (com.aspose.words.Table) wordDoc.getChild(NodeType.TABLE, 0, true);
com.aspose.words.Table table = (com.aspose.words.Table) firstTable.deepClone(true);
// Add the second table after the bookmark
bookmarkContact.getBookmarkEnd().getParentNode().getParentNode().appendChild(table);
// Delete all its rows
table.getRows().clear();
return table;
}
// Add a new row to the table
private static void addRow(com.aspose.words.Document wordDoc, com.aspose.words.Table table, String text)
{
// Create a new row
com.aspose.words.Row row = new com.aspose.words.Row(wordDoc);
row.getRowFormat().setAllowBreakAcrossPages(true);
// Add it to the table
table.appendChild(row);
// Add cells to the row
for (int iCell = 0; iCell < 4; iCell++)
{
// Create a new cell and set text inside it
com.aspose.words.Cell cell = new com.aspose.words.Cell(wordDoc);
cell.appendChild(new com.aspose.words.Paragraph(wordDoc));
cell.getFirstParagraph().appendChild(new Run(wordDoc, text));
cell.getFirstParagraph().getParagraphFormat().setSpaceAfter(0);
row.appendChild(cell);
}
}
private static int getBookmarkPage(com.aspose.words.Document wordDoc, com.aspose.words.Bookmark bookmarkContact) throws Exception
{
// Find the page number, where our contacts bookmark is
LayoutCollector collector = new LayoutCollector(wordDoc);
return collector.getStartPageIndex(bookmarkContact.getBookmarkEnd());
}
I work with Aspose as Developer Evangelist.

sheet.getLastRowNum() function gives invalid count with Apache POI 3.9 [duplicate]

This question already has answers here:
How to get row count in an Excel file using POI library?
(7 answers)
Closed 6 years ago.
I am using Apache POI 3.9 for xls and xlsx file processing.
As per the logic, I want to iterate over each row and want to collect data for further processing. For that I am using sheet.getLastRowNum() to retrieve number of rows in the xls sheet.
But it seems that sheet.getLastRowNum() gives wrong count if number of records are more than 10.
It works fine if total number of rows are 10. Otherwise it gives result deducted by one.
i.e If there are 15 row in the sheet then It gives 14 as Last Row number.
Can Anyone suggest me,How to solve this problem ??
Here is the code that i am using to collect the data ...
public static List<LinkedList<String>> populateExcelSheetContentWithHeader(Sheet sheet,int columnsCount,int rowsCount) throws Exception{
Row row = null;
List<LinkedList<String>> excelFileRecordsList = new LinkedList<LinkedList<String>>();
int emptyColCount = 0;
String freeTextData = null;
LinkedList<String> excelFileDataList =null;
int actualRows = sheet.getLastRowNum();
if (actualRows < rowsCount) {
rowsCount = actualRows;
}
///ITERATE OVER EACH ROW AND POPULATE THE DATA
for(int index=0;index<rowsCount;index++){
row = sheet.getRow(index);
if(row!=null){
emptyColCount = 0;
excelFileDataList =new LinkedList<String>();
for(int colIndex=0;colIndex<columnsCount;colIndex++){
freeTextData = "";
if(isEmptyCell(row.getCell(colIndex))){
emptyColCount++;
}else{
freeTextData = getCellValue(row.getCell(colIndex),false);
}
//ADD TEXT DETILS TO THE LIST
excelFileDataList.add(freeTextData);
}
//CHECK FOR END OF FILE
if(emptyColCount != columnsCount){
excelFileRecordsList.add(excelFileDataList);
}else{
break;
}
}
}
return excelFileRecordsList;
}
Any suggestion is appreciated .
it is possible that you are converting from CSV or you did any kind of modifications (copy or paste) inside your xls? I had the same exact behaviour when I did some changes like I mentioned. To fix it I had to copy the original again. Sorry for not providing a real solution, I just say what happened.
Maybe that helped

Categories