Přeskočit na hlavní obsah

Jak na Excel 5 - knihovna JExcelApi

Konečně se v našem seriálu dostáváme k čistě javovým implemtacím Excelového formátu. Začneme knihovnou Java Excel API (JExcelApi), kterou vytvořil Andy Khan a uvolnil pod licencí GNU LGPL.

Co tato knihovna umí zajímavého?

  • vytváření a čtení XLS souborů
  • formátování buněk
  • práci se vzorci
  • vkládání PNG obrázků
  • kopírování grafů (vytváření nových podporováno není)
Knihovna není nijak rozsáhlá, takže se dá v API pohodlně orientovat.

Zajímavější pro vás může být informace, co mi na této knihovně vadí. Tady jsou mé připomínky:

  • odlišný přístup k dokumentům při čtení a při zápisu (třídy Workbook a WritableWorkbook nemají ani společný interface)
  • práce s čisly podporuje pouze typ double, osobně bych uvítal např. i BigDecimal
  • chybí jakákoliv podpora pro makra (ani při kopírování nezůstanou zachována)
  • nepodporuje automatickou šířku sloupce (Auto Fit Selection)
  • nelze nastavit typ buňky (viz příklad - vložím vzorec jehož výsledkem je text, ale JExcelApi si při čtení myslí, že to je číslo)
  • tvar vzorců neodpovídá na 100% tvaru z Excelu (chybí uvozovací rovnítko, jako oddělovač parametrů funkcí je použita čárka namísto středníku)
Další věc, která se mi moc nelíbí (a to ani v originálním Excelu) jsou překlady jmen funkcí používaných ve vzorcích. Sice jde jednoduše nastavit, že se použijí původní "americká" jména (WorkbookSettings.setLocale(...)), ale osobně bych to preferoval úplně bez překladů.

A nakonec praktická ukázka:

/**
* Priklad cteni dokumentu pres JExcel
* @throws BiffException
* @throws IOException
* @throws FormulaException
*/
public static void readDemo() throws BiffException, IOException, FormulaException {
    System.out.println("Ctu soubor: " + FILE_NAME);

    // otevreni souboru
    final Workbook wb = Workbook.getWorkbook(new File(FILE_NAME));

    //vypisem vsechny listy
    for (int i=0,m=wb.getNumberOfSheets();i<m;i++) {
        final Sheet sheet = wb.getSheet(i);
        System.out.println("List: " + sheet.getName());

        //vypisem hodnoty v listu
        for (int j=0,n=sheet.getRows();j<n;j++) {
            final Cell[] cells = sheet.getRow(j);
            final StringBuffer tmpStrRow = new StringBuffer();
            for (int k=0; k<cells.length; k++) {

                //spravne bychom tady meli bunku zpracovavat v zavislosti na jejim typu,
                //neb v JavaDocu je metoda getContents oznacena jako "dirty" :)
                tmpStrRow.append(cells[k].getContents());
                //zracovani podle typu bunky muze vypadat nasledovne:
                if (cells[k].getType()==CellType.BOOLEAN_FORMULA
                        || cells[k].getType()==CellType.DATE_FORMULA
                        || cells[k].getType()==CellType.NUMBER_FORMULA
                        || cells[k].getType()==CellType.STRING_FORMULA) {
                    final FormulaCell tmpFormula = (FormulaCell) cells[k];
                    //do zavorky vypiseme vzorech pouzity v teto bunce
                    tmpStrRow.append(" (").append(tmpFormula.getFormula()).append(")");
                }
                tmpStrRow.append("\t");
            }
            System.out.println(tmpStrRow.toString());
        }
    }
    //nakonec zavrem workbook  a uvolnime pamet
    wb.close();
}

/**
* Priklad vytvoreni XLS dokumentu pres JExcel
* @throws IOException see {@link Workbook}
* @throws RowsExceededException see {@link WritableSheet#addCell(jxl.write.WritableCell)}
* @throws WriteException see {@link WritableSheet#addCell(jxl.write.WritableCell)}
*/
public static void writeDemo() throws IOException, RowsExceededException, WriteException {
    System.out.println("Vytvarim soubor: " + FILE_NAME);
    // konfigurace - nechci pouzivat jmena funkci v nemcine :)
    final WorkbookSettings wbs = new WorkbookSettings();
    wbs.setLocale(Locale.US);
    //vytvoreni noveho Workbooku (souboru)
    final WritableWorkbook wb = Workbook.createWorkbook(new File(FILE_NAME),wbs);
    //pridame list
    final WritableSheet sheet = wb.createSheet("Muj super list", 0);
    //nastaveni fontu
    final WritableFont font = new WritableFont(WritableFont.TIMES, 16, WritableFont.BOLD, true);
    final WritableCellFormat cellFormat = new WritableCellFormat(font);

    //pridani stringu
    sheet.addCell(new Label(0,0,"Popisek hodnoty", cellFormat));
    //pridani cisla (bez specialniho formatovani)
    sheet.addCell(new Number(1,0, 1.23456d));
    //pridani vzorce
    sheet.addCell(new Formula(1,1, "CONCATENATE(\"Vysledek vzorce: \",B1+1.90703)"));

    //zapsani do souboru
    wb.write();
    //uvolneni z pameti
    wb.close();
    System.out.println("Soubor ulozen.");
}
výstupem programu bylo na mém německém počítači toto:
Vytvarim soubor: jne5.xls
Soubor ulozen.
Ctu soubor: jne5.xls
List: Muj super list
Popisek hodnoty 1,235 
 4 (VERKETTEN("Vysledek vzorce: ",B1+1.90703))
Celý příklad si můžete stáhnout na adrese http://www.cacek.cz/javlog-attachments/JakNaExcel5.zip

Komentáře

Anonymní píše…
Když spustím stáhnutelný příklad, při vytváření WorkbookSettings mi to vyhodí vyjímku:



Vytvarim soubor: jne5.xls
Exception in thread "main" java.lang.ExceptionInInitializerError
at JExcelApiTest.writeDemo(JExcelApiTest.java:86)
at JExcelApiTest.main(JExcelApiTest.java:116)
Caused by: java.lang.NullPointerException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at common.Logger.initializeLogger(Logger.java:71)
at common.Logger.getLogger(Logger.java:42)
at jxl.WorkbookSettings.[clinit]*(WorkbookSettings.java:42)
... 2 more



(*[clinit] je v ostrych zavorkach, formular mi vsak nedovoli psat tagy)


cestu k souboru mám, si myslím, nastavenou dobře. Každopádně to spadne v době, kdy jí to snad ani nepotřebuje.

Nevíte kde je chyba?
Anonymní píše…
--> tak mi zrejme chybu udelal nekde Eclipse nebo ja. Kdyz jsem vytvoril projekt na jinem pocitaci ve starsim Eclipsu, fungovalo mi to dobre, po presunuti funkcniho projektu mi funguje uz i tady...

Populární příspěvky z tohoto blogu

Three ways to redirect HTTP requests to HTTPs in WildFly and JBoss EAP

WildFly application server (and JBoss EAP) supports several simple ways how to redirect the communication from plain HTTP to TLS protected HTTPs. This article presents 3 ways. Two are on the application level and the last one is on the server level valid for requests to all deployments. 1. Request confidentiality in the deployment descriptor The first way is based on the Servlet specification. You need to specify which URLs should be protected in the web.xml deployment descriptor. It's the same approach as the one used for specifying which URLs require authentication/authorization. Just instead of requesting an assigned role, you request a transport-guarantee . Sample content of the WEB-INF/web.xml <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1

Ignore the boring SSH error message - Host identification has changed!

The problem If you work with virtual machines in clouds, or you run an SSH server in Docker containers, then you've probably met the following error message during making ssh connection: (I'm connecting through SSH to a docker container) ~$ ssh -p 8822 root@localhost @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the ECDSA key sent by the remote host is SHA256:smYv5yA0n9/YrBgJMUCk5dYPWGj7bTpU40M9aFBQ72Y. Please contact your system administrator. Add correct host key in /home/jcacek/.ssh/known_hosts to get rid of this message. Offending ECDSA key in /home/jcacek/.ssh/known_hosts:107 remove with: ssh-keygen -f "/home/jcacek/.ssh/know

Enable Elytron in WildFly

Steps to enable Elytron in WildFly nightly builds. There is an ongoing effort to bring a new security subsystem Elytron to WildFly and JBoss EAP. For some time a custom server profile named standalone-elytron.xml  existed beside other profiles in standalone/configuration directory. It was possible to use it for playing with Elytron. The custom Elytron profile was removed now.  The Elytron subsystem is newly introduced to all standard server profiles. The thing is, the Elytron is not used by default and users have to enable it in the subsystems themselves. Let's look into how you can enable it. Get WildFly nightly build # Download WildFly nightly build wget --user=guest --password=guest https://ci.wildfly.org/httpAuth/repository/downloadAll/WF_Nightly/.lastSuccessful/artifacts.zip # unzip build artifacts zip. It contains WildFly distribution ZIP unzip artifacts.zip # get the WildFly distribution ZIP name as property WILDFLY_DIST_ZIP=$(ls wildfly-*-SNAPSHOT.zip) # un