Insert new row into LibreOffice writer table using UNO - java

I have recently tried to code a small java file which will insert a row into an already existing table in a .odt document. The table itself has 4 rows and 3 column, but I would like to implement a check which will expand that table if the content to be inserted is larger than 4. However, every time I try to get the table's rows, it returns a null pointer. I am not that familiar with UNO api, but as far as i read through the documentation, the class XColumnsAndRowRange should be used in this situation. My code is as follows:
XTextTablesSupplier xTablesSupplier = (XTextTablesSupplier) UnoRuntime.queryInterface(XTextTablesSupplier.class, xTextDocument);
XNameAccess xNamedTables = xTablesSupplier.getTextTables();
try {
Object table = xNamedTables.getByName(tblName);
XTextTable xTable = (XTextTable) UnoRuntime.queryInterface(XTextTable.class, table);
XCellRange xCellRange = (XCellRange) UnoRuntime.queryInterface(XCellRange.class, table);
if(flag){
XColumnRowRange xCollumnAndRowRange =(XColumnRowRange)
UnoRuntime.queryInterface(XColumnRowRange.class, xCellRange);
XTableRows rows = xCollumnAndRowRange.getRows();
System.out.println("Testing if this works");
rows.insertByIndex(4, size-4);
}
I am not sure if I am missing something here or if I should be using a different function.

As Lyrl suggested, this works:
XTableRows rows = xTable.getRows();
Apparently XColumnRowRange is only used for spreadsheets.
Note: With Basic or Python you would not have this problem, because those languages do not need queryInterface. The code would simply be:
table = tables.getByName(tblName)
rows = table.getRows()

Related

How to add rows to an existing table using Docx4J

I have an existing Workbook with a Sheet that has a table ('table' refers to the Insert Table feature of the Excel UI with column headers and filter arrows, etc). I am having trouble determining which classes to use to edit existing rows of the table or inserting new rows into the table.
I have been successful (thanks in no small part to JasonPlutext) with writing new cell contents to existing cells as well as creating entirely new cells/rows. I'd rather not have to write the header row and all the data rows first and them make it into a table using the API, but I would like to know if anybody know how it should be done. In the past, I could just create the table with the number of rows I knew I would need but in this case the rows quantity is dynamic. I was hoping I could just reference a tablePart and then there would be some method for inserting into a List object.
Any guidance is appreciated.
EDIT:
So as a concrete example, let's say I have a workbook and sheet with an existing table of 2 columns with 2 rows (including the header) starting at A1. I can open the underlying xl>tables>table1.xml and see this:
<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="xr xr3" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" id="5" xr:uid="{FAABA541-34FC-423B-94F5-DDD8D784132E}" name="SummarySFTP" displayName="SummarySFTP" ref="A1:B2" totalsRowShown="0" headerRowDxfId="46" headerRowBorderDxfId="45" tableBorderDxfId="44">
<autoFilter ref="A1:B2" xr:uid="{93499C15-75FB-4436-A9B9-0C1FCBD787F4}">
<filterColumn colId="0" hiddenButton="0"/>
<filterColumn colId="1" hiddenButton="0"/>
</autoFilter>
<tableColumns count="2">
<tableColumn id="1" xr3:uid="{D4DA50CD-C581-4286-9B64-42B02B6646B6}" name="Status"/>
<tableColumn id="2" xr3:uid="{9D4F40B3-B530-42E1-92E9-86D5632CA191}" name="Quantity" dataDxfId="43"/>
</tableColumns>
<tableStyleInfo showFirstColumn="0" showLastColumn="0" showRowStripes="1" showColumnStripes="0"/>
</table>
I can see my two columns, and the ref attribute of the root tag as well as the autoFilter block's ref attribute. What I want to do is add a new row such that the area of the table would be A1:B3.
Inspecting an xlsx file containing a table in the docx4j webapp, it looks fairly straightforward.
It generates code for the contents of the table part like:
CTTable table = smlObjectFactory.createCTTable();
JAXBElement<org.xlsx4j.sml.CTTable> tableWrapped = smlObjectFactory.createTable(table);
// Create object for autoFilter
CTAutoFilter autofilter = smlObjectFactory.createCTAutoFilter();
table.setAutoFilter(autofilter);
autofilter.setRef( "A2:B4");
// Create object for tableColumns
CTTableColumns tablecolumns = smlObjectFactory.createCTTableColumns();
table.setTableColumns(tablecolumns);
tablecolumns.setCount( new Long(2) );
// Create object for tableColumn
CTTableColumn tablecolumn = smlObjectFactory.createCTTableColumn();
tablecolumns.getTableColumn().add( tablecolumn);
tablecolumn.setTotalsRowFunction(org.xlsx4j.sml.STTotalsRowFunction.NONE);
tablecolumn.setName( "Column1");
tablecolumn.setId( 1 );
// Create object for tableColumn
CTTableColumn tablecolumn2 = smlObjectFactory.createCTTableColumn();
tablecolumns.getTableColumn().add( tablecolumn2);
tablecolumn2.setTotalsRowFunction(org.xlsx4j.sml.STTotalsRowFunction.NONE);
tablecolumn2.setName( "Column2");
tablecolumn2.setId( 2 );
// Create object for tableStyleInfo
CTTableStyleInfo tablestyleinfo = smlObjectFactory.createCTTableStyleInfo();
table.setTableStyleInfo(tablestyleinfo);
tablestyleinfo.setName( "TableStyleMedium2");
table.setTableType(org.xlsx4j.sml.STTableType.WORKSHEET);
table.setHeaderRowCount( new Long(1) );
table.setTotalsRowCount( new Long(0) );
table.setName( "Table1");
table.setId( 1 );
table.setRef( "A2:B4");
table.setDisplayName( "Table1");
Once you know the row quantity, you can see you need to write it in 2 places, using setRef and autofilter.setRef

java - import from excel to mysql

i have excel file (.xlsx) with column
Column1 Column2 Column3 Column1
A 50 30 40
B 45 40 20
.......................................
I need to import this excel in MySQL database. I use following code:
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream(new File("Data.xlsx"));
XSSFWorkbook workbook = new XSSFWorkbook (fis);
XSSFSheet sheet = workbook.getSheetAt(0);
Iterator ite = sheet.rowIterator();
while(ite.hasNext()){
Row row = (Row) ite.next();
Iterator<Cell> cite = row.cellIterator();
while(cite.hasNext()){
Cell c = cite.next();
System.out.print(c.toString() +";");
}
System.out.println();
}
fis.close();
}
I need to get in list all row. This code show in console all data from row, but I don't now to add that data in list and list import to MySQL.
Any idea?
I can think of few approaches in order to write this data into the MySQL database but, I will give you the most basic approach to achieve what you desire. You are using Apache POI library in order to log all the data to console.
while (rows.hasNext()) {
String[] rowsVal = new String[Number_of_Columns];
if (row.getCell(0).getStringCellValue().equalsIgnoreCase("Column_Name")) {
row = rows.next();
}
while (cells.hasNext()) {
keyVal[j] = cells.next().getStringCellValue();
j++;
}
}
Above code will store the content of the first row in the keyVal[] array.
Now, you need to include the packages containing the JDBC classes needed for database programming. Following code snippet will be useful to insert records into the table:
String sql = "INSERT INTO Table " + "VALUES ("keyVal[0] + "," + keyVal[1] + "," + keyVal[2] + "," + keyVal[3])";
The above code snippet will help you in inserting the data into the database.
Links for Reference:
https://www.tutorialspoint.com/jdbc/jdbc-insert-records.htm
This is not a direct answer to your question, but may in fact be an even better approach than what you are considering. You may try exporting your Excel worksheet as a CSV file. This means the lines would look like:
Column1,Column2,Column3,Column4
A,50,30,40
With this CSV file in hand, you may then use MySQL's LOAD DATA tool, which allows for rapidly importing CSV or other regular data:
LOAD DATA INFILE 'C:/path/to/Data.xlsx'
INTO TABLE yourTable
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
The motivation for possibly avoiding your current approach is that it is costly to use an Apache library to open an Excel workbook, and then read it. Even after doing this, you still would need to use JDBC to write that data to MySQL.

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).

Refresh Pivot table using Apache POI

No/Minimal documentation regarding Apache POI for Pivot tables in the Apache site has got me to write this.
I want to refresh a pivot table in a Work Book using Apache POI.
Please let me know where I can get proper documentation and Examples regarding this.
Kindly follow the followings which i did.
Fill rough data for pivot table in your MyFileName.xlsx file.
Create a Dynamic Range Formula through OFFSET() or Named Table as Source Data for Pivot table and draw pivot table.
Simply Right click your pivot table and choose
pivotTable Options->Data-> Check Refresh Data when opening File
Open a MyFileName.xlsx file and fill out the data.
That's all...
whenever you opening workbook it will be refreshed to current data. :-)
Note: This will not work when you creating Pivot table through POI.
The link codeMan refers to has some advice that looks quite specific to Apache POI & Excel.
You'll see that there is no great documentation for a reason here (it's not supported):
http://poi.apache.org/spreadsheet/limitations.html
To quote Solitudes answer in codeMans link verbatim:
It is possible. In the PivotCacheDefinition, there is an attribute
refreshOnLoad that can be set to true. The cache is then refreshed
when the workbook is opened. More information here.
> In POI this can be done by calling the method setRefreshOnLoad(boolean
bool), that takes a boolean as parameter, on a CTPivotCacheDefinition
If you need to refresh the pivot table before the file is opened, (for example to then use the pivottable calculated data in further calculations and have POI write this) then I'm not sure that this would be possible at all with POI, and potentially hooking up to excel using a COM solution might be the way to go.
Apart from the limitations, you can check a little information about Package org.apache.poi.hssf.record.pivottable
Though if I will have to do the same, I would create the table/chart manually once and will update the chart using apache poi as I have done here
another solution (WO VBA scripts)
In tempalate.xlsx create xlTable object on headers of source record set. Set name to the xlTable, ex. 'mySourceTable'.
Also in file preSet for your PivotTable:
sourceRef ='mySourceTable'
check in RefreshOnLoad
In POI:
private void updateXlTableSource() {
XSSFTable sourceTable = ((XSSFWorkbook)workbook).getTable("mySourceTable");
CTTable ctTable = sourceTable.getCTTable();
String sourceRef = getSourceDataRange().formatAsString();
ctTable.setRef(sourceRef);
ctTable.getAutoFilter().setRef(sourceRef);
}
private CellRangeAddress getSourceDataRange() {
XSSFSheet xssfSheet = (XSSFSheet) workbook.getSheet("sourceSheetName");
int uBoundSourceDataRow = findFirstEmptyRowFrom(xssfSheet) - 1;
if (uBoundSourceDataRow < 2) {
uBoundSourceDataRow = 2;
}
int uBoundSourceDataCol = findFirstEmptyColFromFirstRow(xssfSheet) - 1;
return new CellRangeAddress(0, uBoundSourceDataRow, 0, uBoundSourceDataCol);
}
Note: check your tempalate.xlsx for unKnown query. Delete if it exists, else it will block PT updating
Drawback: PT's autoFilter contains notexisting elements (elements from PT template).
save your file with PTs as file.xlsm and insert VBA script (ALT+F11):
' Create module and insert this:
Public Const pivotName1 As String = "myPivotName"
Public Const sourceSheetName As String = "source"
Public Const sourceColumnCount As Long = 23
' In "ThisWorkbook" chapter insert this:
Dim lRow As Long
Private Sub Workbook_Open()
Application.ScreenUpdating = False
ActiveWorkbook.Worksheets(sourceSheetName).Activate
' In file should preliminarily insert keyWord "firstOpenFlag" in CV1 cell (sheet sourceSheetName)
' It gona start actions below
If ActiveSheet.Cells(1, 100) = "firstOpenFlag"
Then
ActiveSheet.Cells(1, 100) = ""
lRow = getLastRowForFirstCol(sourceSheetName)
Call updateAllPTCache
ActiveWorkbook.Worksheets(sourceSheetName).Activate
ActiveSheet.Range("A1").Select
End If
Application.ScreenUpdating = True
End Sub
Private Function getLastRowForFirstCol(sourceSheetName As String) As Long
ActiveWorkbook.Worksheets(sourceSheetName).Activate
getLastRowForFirstCol = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
If getLastRowForFirstCol < 2 Then getLastRowForFirstCol = 2
End Function
Private Sub updateAllPTCache()
Dim pt As PivotTable
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
For Each pt In ws.PivotTables
pt.ChangePivotCache ActiveWorkbook.PivotCaches.Create( _
SourceType:=xlDatabase, _
SourceData:=sourceSheetName + "!R1C1:R" + CStr(lRow) + "C" + CStr(sourceColumnCount), _
Version:=xlPivotTableVersion14)
' xlPivotTableVersion14 - work in 2013, 2016 exlApp
' Downgrade xlPivotTableVersion for backward compatibility
pt.RefreshTable
Next pt
Next ws
End Sub
Drawback: clients xlsApp should be configed to enable VBA scripts

Reading a Access file using Jackcess and creating a Jtable with the data

I'm currently working on a Java application that reads an Access file and builds a Jtable model using the data that's collected. I've previously done the same with an Excel file but when I tried with Jackcess it was slightly diffrent and I've ran into some questionmarks.
My work so far:
public class AccessModel{
public DefaultTableModel getAccessModel() throws IOException {
Database db = DatabaseBuilder.open(new File("MyFile.accdb"));
Vector<String> columnNames = new Vector<String>();
Vector<String> vector = new Vector<String>();
Vector<Vector<String>> data = new Vector<Vector<String>>();
StringBuilder output = new StringBuilder();
Table table = db.getTable("Table1");
for (Column column : table.getColumns()) { // get the table column names
output.append(column.getName());
output.append("\n");
columnNames.add(column.getName());
}
for (Column column : table.getColumns()) { // get the column rows and values
vector.add(column.getRowValue(table.getNextRow()).toString());
}
data.add(vector);
// return the model to Gui
DefaultTableModel accessModel = new DefaultTableModel(data, columnNames);
return accessModel;
}
}
As you can see this method will only iterate trough the first row, then exit the loop. I'm either blind to an abvious solution due to 12 hours of straight work, or I'm doing something terribly wrong.
I've stumbled across some half-good solutions where an Iterator is used, but I cannot get the hang of it. Any suggestions on this? Or should I stay on lane with my current line of thought?
JTable (value for view is stored in XxxTableModel, in your case is used DefaultTableModel) is row bases Object,
TableColumn (value is stored in TableColumnModel) to divide row(s) to the columns
you would need to create two Objects,
Vector<String> columnNames (is only one row) for columns identifiers from Table table = db.getTable("Table1");
loop inside Table table = db.getTable("Table1"); to fill two dimensional Vector<Vector<Object>> data = new Vector<Vector<Object>>(); by using Vector<Object> vector = new Vector<Object>();, notice 1st. code line insode loop must be vector = new Vector<Object>();, you have to create a new Vector otherwise you'll add the same rown_times, last code line should be data.add(vector)
.
everything (I'm still think so) is described in Oracle tutorial How to use Tables

Categories