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

Simple TLS certificates in WildFly 18

It's just 2 weeks when WildFly 18 was released. It includes nice improvements in TLS certificates handling through ACME protocol (Automatic Certificate Management Environment), it greatly simplifies obtaining valid HTTPS certificates. There was already a support for the Let's Encrypt CA in WildFly 14 as Farah Juma described in her blog post last year. New WildFly version allows using other CA-s with ACME protocol support. It also adds new switch --lets-encrypt to interactive mode of security enable-ssl-http-server JBoss CLI commands. Let's try it. Before we jump on WildFly configuration, let's just mention the HTTPs can be used even in the default configuration and a self-signed certificate is generated on the fly. Nevertheless, it's not secure and you should not use it for any other purpose than testing. Use Let's Encrypt signed certificate for HTTPs application interface Start WildFly on a machine with the public IP address. Run it on the defaul...

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