<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>j2ee.pl - związani z javą &#187; excel</title>
	<atom:link href="http://j2ee.pl/tag/excel/feed/" rel="self" type="application/rss+xml" />
	<link>http://j2ee.pl</link>
	<description>związani z Javą</description>
	<lastBuildDate>Mon, 24 Aug 2009 11:45:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Dodatkowe dwa słowa o Apache XMLBeans i HSSF POI</title>
		<link>http://j2ee.pl/2007/12/17/dodatkowe-dwa-slowa-o-apache-xmlbeans-i-hssf-poi/</link>
		<comments>http://j2ee.pl/2007/12/17/dodatkowe-dwa-slowa-o-apache-xmlbeans-i-hssf-poi/#comments</comments>
		<pubDate>Mon, 17 Dec 2007 09:01:12 +0000</pubDate>
		<dc:creator>Michał Porzożyński</dc:creator>
				<category><![CDATA[Inne biblioteki]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xpath]]></category>

		<guid isPermaLink="false">http://j2ee.pl/2007/12/17/dodatkowe-dwa-slowa-o-apache-xmlbeans-i-hssf-poi/</guid>
		<description><![CDATA[Na naszym blogu możesz znaleźć dwa artykuły mojego autorstwa o Apache XMLBeans oraz Apache POI. Ostatnio miałem okazję ponownie pracować  z tymi bibliotekami, napotykając przy tym na dwa problemy, których rozwiązanie nie okazało się dla mnie jakoś specjalnie proste (mimo, że być powinno ;)). Dzisiaj będzie o wykorzystaniu wyrażeń XPath w XMLBeans oraz o [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://j2ee.pl/wp-content/uploads/2007/12/apache.png" alt="ASF" align="left" />Na naszym blogu możesz znaleźć dwa artykuły mojego autorstwa o <a href="http://j2ee.pl/2007/10/20/apache-xmlbeans-bindowanie-danych-xml-do-typow-java/">Apache XMLBeans</a> oraz <a href="http://j2ee.pl/2007/06/28/wstep-do-apache-poi-hssf-dostep-do-plikow-ms-excel-w-javie/">Apache POI</a>. Ostatnio miałem okazję ponownie pracować  z tymi bibliotekami, napotykając przy tym na dwa problemy, których rozwiązanie nie okazało się dla mnie jakoś specjalnie proste (mimo, że być powinno ;)). Dzisiaj będzie o wykorzystaniu wyrażeń XPath w XMLBeans oraz o przeliczaniu formuł zaszytych w arkuszach Excel. Tematy trochę jakby nie mają nic ze sobą wspólnego, ale przecież to tylko dodatkowe dwa słowa ;)<br />
<span id="more-110"></span></p>
<h3>XMLBeans i XPath</h3>
<p>XMLBeans posiada fajną funkcjonalność, pozwalająca na użycie języka <a href="http://en.wikipedia.org/wiki/XPath">XPath</a> do wyciągania z obiektu klasy XmlObject (klasy do której &#8220;wparsowany&#8221; jest nasz xml) potrzebnych nam danych.  Z tak zwanego <em>out of the box,</em> nasza biblioteka pozwala na tworzenie jedynie prostych zapytań XPath (np: //book). Jeżeli chcemy wykorzystać trochę bardziej złożoną semantykę (powiedzmy: //book[@title='EJB3 in Action'])  powinniśmy spiąć XMLBeans z biblioteką <a href="http://saxon.sourceforge.net/">Saxon</a> (procesor XSLT i XQuery). Takie spięcie polega jedynie na dodaniu do naszej aplikacji bibliotek saxon.jar, saxon-dom.jar (znajdują się w jednym archiwum ściąganym ze strony saxona) oraz xbean_xpath.jar (dostępnego razem z dystrybucją XMLBeans). Jeśli środowisko jest już przygotowane, wystarczy wywołać na obiekcie XmlObject metodę selectPath podając w jej parametrze wyrażenie XPath. W odpowiedzi powinniśmy dostać tablicę obiektów XmlObject z interesującymi nas danymi.</p>
<pre class="prettyprint">XmlObject[] data = BookDocument.selectPath("//book[@title='EJB3 in Action']");</pre>
<p>W moim przypadku coś poszło jednak nie tak. Mimo, że sprawdziłem poprawność wyrażenia XPath, zmienna <em>data </em>była nullem. Zajęło mi trochę czasu aby problem rozwiązać. Okazuje się że Apache XMLBeans w wersji 2.3.0 współpracuje tylko z bardzo konkretną wersją biblioteki Saxon: wersją 8.8. Ja posiadałem najnowszego Saxon&#8217;a oznaczonego numerem 9.0. W taki oto sposób straciłem 45 minut i przed tą stratą postanowiłem ostrzec Was :)</p>
<h3>Apache HSSF POI i przeliczanie formuł w Excelu</h3>
<p>O problemie przeliczania formuł w arkuszach MS Excel pisałem już wcześniej. Wtedy była to tylko wzmianka o tym, że istnieje specjalna klasa służąca właśnie do tego (<strong>HSSFFormulaEvaluator</strong>) i że nie udało mi się jej użyć ;) Od wersji 3.0.1 klasa ta już jest niedostępna, a problem pozostał. No właśnie&#8230; może przybliżę problem: powiedzmy, że istnieje arkusz Excela, który posiada tylko trzy pola: A1 &#8211; liczba, A2 &#8211; liczba, A3 = A2 &#8211; A1. Z jakiegoś tylko tobie znanego powodu, za pomocą Apache POI chcesz zmienić liczbę w polu A2 na jakąś inną.. lepszą ;) Robisz wszystko co potrzeba, zapisujesz arkusz na dysku, otwierasz go w Excelu i zauważasz, że formuła w polu A3 ciągle pokazuje wyliczenia z poprzednimi wartościami.  Co należy zrobić aby formuła została przeliczona ? Należy zapamiętać formułę w stringu, nadać komórce typ: HSSFCell.CELL_TYPE_FORMULA oraz zapisać ponownie do komórki zapamiętaną wcześniej formułę. Rozwiązanie proste jak budowa cepa, tym bardziej więc dziwi, że działa tak, jakbyśmy tego chcieli ;)</p>
<pre class="prettyprint">String formula = cell.getCellFormula();
cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
cell.setCellFormula(formula);</pre>
<p>To by było na tyle. Obiecuję, że już nie będę Was męczył zagadnieniami związanymi z POI i XMLBeans :)</p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2007/12/17/dodatkowe-dwa-slowa-o-apache-xmlbeans-i-hssf-poi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wstęp do Apache POI HSSF &#8211; dostęp do plików MS Excel w Javie</title>
		<link>http://j2ee.pl/2007/06/28/wstep-do-apache-poi-hssf-dostep-do-plikow-ms-excel-w-javie/</link>
		<comments>http://j2ee.pl/2007/06/28/wstep-do-apache-poi-hssf-dostep-do-plikow-ms-excel-w-javie/#comments</comments>
		<pubDate>Wed, 27 Jun 2007 23:17:09 +0000</pubDate>
		<dc:creator>Michał Porzożyński</dc:creator>
				<category><![CDATA[Inne biblioteki]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[excel]]></category>

		<guid isPermaLink="false">http://j2ee.pl/2007/06/28/wstep-do-apache-poi-hssf-dostep-do-plikow-ms-excel-w-javie/</guid>
		<description><![CDATA[Apache POI jest zbiorem subprojektów, które dostarczają Javowe API do manipulowania plikami w formacie Microsoft Office 97 &#8211; XP (tutaj muszę wspomnieć, że bez problemu udało mi się działać także na dość skomplikowanych plikach z wersji 2003). HSSF umożliwia odczyt i zapis plików programu MS Excel, HWPF &#8211; MS Word, a HSLF &#8211; MS PowerPoint. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://j2ee.pl/wp-content/project-logo.jpg" alt="POI" align="left" border="0" />Apache POI jest zbiorem subprojektów, które dostarczają Javowe API do manipulowania plikami w formacie Microsoft Office 97 &#8211; XP (tutaj muszę wspomnieć, że bez problemu udało mi się działać także na dość skomplikowanych plikach z wersji 2003). HSSF umożliwia odczyt i zapis plików programu MS Excel, HWPF &#8211; MS Word, a HSLF &#8211; MS PowerPoint. W momencie powstawania tego artykułu dostępna była wersja 3.0.1-FINAL (z 8 czerwca 2007).</p>
<p><span id="more-57"></span></p>
<p>W niniejszym artykule zaprezentuję podstawowe możliwości HSSF: wyświetlenie na konsoli prostego pliku MS Excel, manipulacja danymi, oraz zapis. Aplikacja stworzona zostanie w Eclipse 3.2.2, a do jej budowania użyję Maven 2.0.7. Aby nie wybiegać poza temat, musiałem założyć, że obydwa te narzędzia są czytelnikowi znane. W Eclipse korzystam m.in. z wtyczki m2eclipse, która ułatwia korzystanie z mavena. Dobrą i darmową książkę o Apache Maven można pobrać ze strony <a href="http://www.mergere.com/m2book_download.jsp" target="_blank">http://www.mergere.com/m2book_download.jsp</a></p>
<p>Zaczynamy..<br />
Za pomocą Mavena tworze szkielet aplikacji, a następnie, po przejściu do katalogu poi-excel, tworzę projekt dla Eclipse</p>
<pre class="prettyprint">mvn archetype:create -DgroupId=pl.j2ee.poi.hssf -DartifactId=poi-excel</pre>
<pre class="prettyprint">mvn eclipse:eclipse</pre>
<p>Obydwa polecenia powinny zakończyć się komunikatem <strong>BUILD SUCCESSFUL</strong> .</p>
<p>Otwieram wygenerowany projekt w Eclipse i zabieram się za edycje pliku pom.xml do którego dodam odpowiednie zależnosci oraz skonfiguruję build. Usunę także klasę wygenerowanego przez mavena testu AppTest.</p>
<p>W rezultacie otrzymuję taki oto plik (opis w komentarzach):</p>
<pre class="prettyprint">&lt;project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  http://maven.apache.org/maven-v4_0_0.xsd"&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;pl.j2ee.poi.hssf&lt;/groupId&gt;
  &lt;artifactId&gt;poi-excel&lt;/artifactId&gt;
  &lt;packaging&gt;jar&lt;/packaging&gt;
  &lt;version&gt;1.0&lt;/version&gt;
  &lt;name&gt;poi-excel&lt;/name&gt;
  &lt;url&gt;http://j2ee.pl&lt;/url&gt;
  &lt;build&gt;
    &lt;!-- build do pliku poi-excel.jar --&gt;
    &lt;finalName&gt;poi-excel&lt;/finalName&gt;
    &lt;sourceDirectory&gt;${basedir}/src/main&lt;/sourceDirectory&gt;
    &lt;plugins&gt;
      &lt;!-- Kompilacja w Java 6.0 (moze byc 1.4)--&gt;
      &lt;plugin&gt;
        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
        &lt;configuration&gt;
          &lt;source&gt;1.6&lt;/source&gt;
          &lt;target&gt;1.6&lt;/target&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
      &lt;!-- Nasz wlasny plik MANIFEST.MF, w ktorym
           umieszczamy m.in. info o naszej klasie glownej --&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-jar-plugin&lt;/artifactId&gt;
        &lt;configuration&gt;
          &lt;archive&gt;
            &lt;manifestFile&gt;
              src/main/resources/META-INF/MANIFEST.MF
            &lt;/manifestFile&gt;
          &lt;/archive&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
    &lt;/plugins&gt;
  &lt;/build&gt;
  &lt;dependencies&gt;
    &lt;!-- Gwozdz programu.. Apache POI. W momencie powstawania artykulu
          w repozytorium nie bylo jeszcze wersji 3.0.1 --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;poi&lt;/groupId&gt;
      &lt;artifactId&gt;poi&lt;/artifactId&gt;
      &lt;version&gt;3.0-FINAL&lt;/version&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
  &lt;repositories&gt;
    &lt;!-- Dodatkowe repozytorium (na ibiblio biblioteki
    sa znacznie nowsze niz na glownym serwerze mavena --&gt;
    &lt;repository&gt;
      &lt;name&gt;ibiblio&lt;/name&gt;
      &lt;id&gt;ibiblio&lt;/id&gt;
      &lt;url&gt;http://www.ibiblio.org/maven/&lt;/url&gt;
    &lt;/repository&gt;
  &lt;/repositories&gt;
&lt;/project&gt;</pre>
<p>Dodatkowo w katalogu src/main/resources/META-INF umieszczam plik MANIFEST.MF, w którym wskazuje na klasę pl.j2ee.poi.hssf.App jako na punkt startowy mojej aplikacji.</p>
<pre class="prettyprint">Main-Class: pl.j2ee.poi.hssf.App</pre>
<p>Tworzę prosty plik w formacie MS Excel. Utworzę go za pomocą pakietu Open Office 2.2. Arkusz o nazwie &#8220;Faktura&#8221; przedstawia.. i tutaj uwaga: (bardzo) prostą fakturę ;) Poniżej link do pliku oraz jego screenshot. Jak można zauważyć, w arkuszu znajduje się trzy kolumny z wartościami liczbowymi (L.P.; Cenna Netto, VAT), jedna kolumna tekstowa (Nazwa) oraz jedna kolumna wyliczana (Cenna Brutto = Cenna Netto * (1 + VAT)). Dodatkowo w komórce F9 umieściłem sumę cen brutto.</p>
<p><a href="http://j2ee.pl/2007/06/28/wstep-do-apache-poi-hssf-dostep-do-plikow-ms-excel-w-javie/excel-1/" rel="attachment wp-att-58" title="Excel 1"><img src="http://j2ee.pl/wp-content/excel-1.thumbnail.png" alt="Excel 1" border="0" /></a><br />
<a href="http://j2ee.pl/wp-content/example.xls" title="example.xls"></a></p>
<p><a href="http://j2ee.pl/wp-content/example.xls" title="example.xls">example.xls</a></p>
<p>Nadszedł już czas aby wreszcie napisać trochę kodu. Nasza prosta aplikacja będzie miała do wykonania cztery czynności</p>
<ol>
<li>Wydrukowanie arkusza na standardowe wyjście</li>
<li>Zmiana ceny piwa</li>
<li>Dodanie zniżki</li>
<li>Zapis zmienionego arkusza do nowego pliku</li>
</ol>
<p>Operacje te pozwolą na szybkie opanowanie podstawowych klas pakietu POI HSSF. Poszczególne funkcjonalności zostaną zaimplementowane w prostych metodach prywatnych, tak abym ja miał ułatwione zadanie w opisywaniu poszczególnych kroków, oraz po to, aby kod aplikacji wyglądał jako tako ;) Przepływ (w sensie flow) aplikacji definiujemy w starym dobrym <em>public static void main</em>. Dodatkowo definiujemy kilka stałych które wykorzystamy później.</p>
<pre class="prettyprint">public class App {

  // sciezka do pliku MS Excel
  private static final String EXCEL_FILE = "c:example.xls";
  // sciezka to nowego pliku MS Excel
  private static final String NEW_EXCEL_FILE = "c:example-new.xls";
  // nazwa arkusza z danymi
  private static final String SHEET_NAME = "Faktura";
  // numer kolumny z nazwami produktow
  private static final short NAME_COL_NUMBER = 2;
  // numer kolumny z cenami netto produktow
  private static final short PRICE_NET_COL_NUMBER = 3;
  //numer kolumny z cenami netto produktow
  private static final short PRICE_COL_NUMBER = 5;
  // identyfikator komorki z suma faktury
  private static final String SUM_CELL = "F9";

  private HSSFWorkbook workbook;
  private HSSFSheet sheet;

  public static void main(String[] args) throws IOException {

    App app = new App();
    app.initializeWorkbook();
    app.printWorksheet();
    app.changeBeerPrice(60);
    app.discount();
    app.saveAs(NEW_EXCEL_FILE);

  }
}</pre>
<p>Na dobry początek idzie pod młotek inicalizacja  (czyli w tym przypadku wczytanie) pliku MS Excel, a następnie wybór arkusza w którym znajdują się dane. Aby to zrobić musimy poznać trzy istotne klasy:</p>
<ul>
<li><strong>HSSFWorkbook </strong>reprezentuje plik MSExcel. Wykorzystujemy ją kiedy chcemy wczytać lub zapisać plik XLS. Służy ona także do tworzenia nowych plików. Na potrzeby tego artykułu przyjmuję, że słowo <em>workbook </em>jest tożsame z <em>plik XLS</em> &#8211; jest to byt który zawiera arkusze z danymi.</li>
<li><strong>HSSFSheet</strong> reprezentuje arkusz z danymi.</li>
<li><strong>POIFSFileSystem</strong> zarządza cyklem życia systemu plików. Wykorzystujemy ją m.in. do wczytania pliku do obiektu klasy HSSFWorkbook.</li>
</ul>
<p>Wczytanie danych z pliku .xls do obiektu HSSFWorkbook polega na utworzeniu obiektu POIFSFileSystem, który przekazywany jest następnie do konstruktora obiektu HSSFWorkbook.<br />
Aby utworzyć obiekt reprezentujący interesujący nas arkusz z danymi, należy wywołać metodę getSheet(nazwa_arkusza) na obiekcie workbooka.</p>
<pre class="prettyprint">  /**
   * Inicjalizacja obiektu Workbook na podstawie pliku
   * example.xls
   * @throws IOException
   */
  private void initializeWorkbook() throws IOException {
    FileInputStream file = new FileInputStream(EXCEL_FILE);
    POIFSFileSystem poiFileSystem = new POIFSFileSystem(file);
    // klasa HSSFWorkbook reprezentuje plik excela
    this.workbook = new HSSFWorkbook(poiFileSystem);
    file.close();

    sheet = workbook.getSheet(SHEET_NAME);
  }</pre>
<p>Wyświetlenie zawartości arkusza polega na iteracji po każdym wierszu z danymi. Następnie, w obrębie danego wiersza druga pętla przechodzi po konkretnych komórkach, wyświetlając ich zawartość.</p>
<ul>
<li><strong>HSSFRow </strong>reprezentuje rząd (wiersz). Obiekty tego typu przechowywane są w obiektach klasy HSSFSheet.</li>
<li><strong>HSSFCell  </strong>reprezentuje komórkę. Obiekty HSSFCell przechowywane są w obiektach klasy HSSFRow. Metody tej klasy pozwalają nam dobrać się m.in. do wartości komórki (<em>get/setRichStringCellValue</em>, <em>get/setNumericCellValue </em>&#8230;) czy jej formuły (<em>get/setCellFormula</em>).</li>
</ul>
<p>Metody <em>sheet.getFirstRowNum()</em> i <em>sheet.getLastRowNum()</em> zwracają odpowiednio numer pierwszego i ostatniego wiersza w którym znajdują się jakiekolwiek dane. Metody <em>row.getFirstCellNum()</em> i <em>row.getLastCellNum()</em> zwracają odpowiednio numer pierwszej i ostatniej komórki danego wiersza w których znajdują się dane. Oczywiście może zdarzyć się taka sytuacja, że pomiędzy pierwszą i ostatnią komórką danego wiersza natrafi się komórka pusta, jak i pomiędzy pierwszym i ostatnim wierszem danego arkusza mogą wystąpić wiersze bez danych. W takiej sytuacji metody sheet.getRow(i) oraz row.getCell(j) zwrócą <strong>null</strong>. Metoda którą przedstawię poniżej nie posiada zabezpieczeń związanych z taką sytuacją.. ale Ty powinieneś(powinnaś) pamiętać, aby je zaimplementować. Do formatowania wyświetlanych danych użyłem dostępnej od Java 5.0 klasy Formatter. Mimo tego efekt działania metody i tak pozostawia wiele do życzenia ;) Jednak moim zadaniem w tym artykule jest raczej przedstawienie podstawowych możliwości HSSF, a nie języka Java i moich umiejętności posługiwania się nim ;)</p>
<p>Odczyt i zapis wartości komórek należy wykonywać przy pomocy odpowiednich metod <em>get/set*CellValue()</em> &#8211; w zależności od typu komórki. Typ sprawdzamy za pomocą metody <em>getCellType()</em> a następnie porównujemy  go ze stałymi zdefiniowanymi w klasie HSSFCell (CELL_TYPE_NUMERIC, CELL_TYPE_FORMULA, &#8230;). Jeżeli w komórce przechowujemy tekst &#8211; nie korzystamy z klasy String, a z <strong>HSSFRichTextString</strong>. Obecnie istnieją metody obsługujące klasę String, jednak oznaczone są one jako <em>deprecated. </em></p>
<pre class="prettyprint">  /**
   * Drukuje arkusz na standardowe wyjscie. Metoda daleka od doskonalosci ;)
   *
   */
  private void printWorksheet() {
    // pierwsza petla przechodzi po wierszach, w ktorych sa jakiekolwiek dane
    for (int i = sheet.getFirstRowNum(); i &lt; sheet.getLastRowNum(); i++) {
      // druga petla przechodzi po komorkach w danym wierszu
      HSSFRow row = sheet.getRow(i + 1);
      for (short j = row.getFirstCellNum(); j &lt; row.getLastCellNum(); j++) {
        StringBuilder stringBuilder = new StringBuilder();
        Formatter formatter = new Formatter(stringBuilder);
        HSSFCell cell = row.getCell(j);
        if (HSSFCell.CELL_TYPE_FORMULA == cell.getCellType() ||
               HSSFCell.CELL_TYPE_NUMERIC == cell.getCellType()) {
          formatter.format("%8.2f", cell.getNumericCellValue());
          System.out.print(stringBuilder.toString());
        } else {
          formatter.format("%15s", cell.getRichStringCellValue());
          System.out.print(stringBuilder.toString());
        }
      }
      System.out.println();
    }
  }</pre>
<p>Metoda zmieniająca cenę piwa nie wprowadza do naszej aplikacji właściwie nic nowego. Iterujemy po kolumnie z nazwami produktów i kiedy znajdujemy odpowiedni wiersz, wprowadzamy nową cenę.</p>
<pre class="prettyprint">  /**
   * Zmiana ceny piwa ! ;)
   * @param newBeerPrice
   * @throws IOException
   */
  private void changeBeerPrice(double newBeerPrice) throws IOException {
    for (int i = sheet.getFirstRowNum(); i &lt; sheet.getLastRowNum(); i++) {
      if (sheet.getRow(i) != null &amp;&amp; "Piwo".equals(sheet.getRow(i)
            .getCell(NAME_COL_NUMBER).getRichStringCellValue().getString())) {
        sheet.getRow(i).getCell(PRICE_NET_COL_NUMBER).setCellValue(newBeerPrice);
        break;

      }
    }
  }</pre>
<p>Jest jeden haczyk. Jeżeli po wywołaniu metody <em>changeBeerPrice</em> zechcemy wyświetlić zawartość arkusza, to zauważymy, że wartość brutto jak i suma cen brutto nie została przeliczona. Aby wymusić takie przeliczenie należy, według dokumentacji, posłużyć się klasą <strong>HSSFFormulaEvaluator</strong>. Jednak jak się okazało (i co potwierdzają liczne wpisy na forach internetowych) sposób ten raz działa.. a raz nie &#8211; w moim przypadku zdecydowanie obliczanie nie działało. Mimo wszystko poniżej przedstawiam potrzebny kod.</p>
<pre class="prettyprint">HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, workbook);
evaluator.evaluateInCell(cell);</pre>
<p>Najwyższy już czas aby dodać zniżkę do naszej faktury.  Powiedzmy 20% :)  Tworzymy cztery komórki za pomocą metody row.createCell(). Dwie z tych komórek będą zawierały tylko opis: <em>Rabat</em> oraz <em>Po rabacie</em>. Kolejna komórka musi przyjmować wartość rabatu (w naszym przypadku 0.20), a ostatnia będzie zawierać formułę obliczającą rabat (suma_cen_brutto * (1 &#8211; rabat)). Metoda <em>cell.setCellFormula</em> jako argument przyjmuje <em>String</em>. Kod metody powinien być dość jasny po przebrnięciu przez wcześniejszą część artykułu.</p>
<pre class="prettyprint">/**
   * Dodaje znizke do naszej faktury
   *
   */
  private void discount() {
    // zapisujemy do arkusza wartosc rabatu
    int rowDicountLine = sheet.getLastRowNum();
    HSSFRow rowDicountValue = sheet.createRow(rowDicountLine + 2);

    HSSFCell cellDiscountValue = rowDicountValue.createCell(PRICE_COL_NUMBER,
                                      HSSFCell.CELL_TYPE_NUMERIC);
    cellDiscountValue.setCellValue(0.20);
    // dodajemy napis ktory informuje ze mamy rabat
    HSSFRichTextString discountString = new HSSFRichTextString("Rabat:");
    rowDicountValue.createCell((short) (PRICE_COL_NUMBER - 1))
                                 .setCellValue(discountString);

    // zapisujemy do arkusza formule obliczajaca wartosc faktury po rabacie
    HSSFRow rowDiscountSum = sheet.createRow(rowDicountLine + 4);
    HSSFCell cellDiscountSum = rowDiscountSum.createCell(PRICE_COL_NUMBER);
    cellDiscountSum.setCellFormula(SUM_CELL + " * " + "(1 - F" + (rowDicountLine + 3) + ")");
    //  dodajemy napis
    HSSFRichTextString afterDiscountString = new HSSFRichTextString("Po rabacie:");
    rowDiscountSum.createCell((short) (PRICE_COL_NUMBER - 1)).setCellValue(afterDiscountString);
  }</pre>
<p>Na koniec zostało już tylko zapisanie danych w nowym pliku. Zadanie to wykonujemy poprzez przekazanie obiektu OutputStream do metody write() klasy HSSFWorkbook.</p>
<pre class="prettyprint">
  /**
   * Zapisuje biezacy plik pod wskazana nazwa
   * @param filePath
   * @throws IOException
   */
  private void saveAs(String filePath) throws IOException {
    FileOutputStream fileOutputStream = new FileOutputStream(filePath);
    workbook.write(fileOutputStream);
    fileOutputStream.close();
  }</pre>
<p>Rezultat działania naszej aplikacji można podziwiać na screenie poniżej ;)</p>
<p><a href="http://j2ee.pl/2007/06/28/wstep-do-apache-poi-hssf-dostep-do-plikow-ms-excel-w-javie/excel-2/" rel="attachment wp-att-61" title="Excel 2"><img src="http://j2ee.pl/wp-content/excel-2.thumbnail.png" alt="Excel 2" /></a></p>
<p>Co jeszcze oferuje HSSF ?</p>
<ul>
<li>Niskopoziomowy dostęp do arkusza dla użytkowników z większymi wymaganiami (niż potrzeby tego artykułu)</li>
<li>EventModel API dla efektywnego dostępu w trybie tylko do odczytu</li>
</ul>
<p>O tych funkcjonalnościach wypadałoby napisać parę słów w przyszłości.. ale przed nami jak zwykle mało czasu, a ilość ciekawych tematów zatrważająca :)<br />
Mam nadzieję, że ten krótki wstęp do Apache POI pomoże Wam w zmaganiach z formatem arkusza kalkulacyjnego Microsoftu.</p>
<p>Źródła aplikacji: <a href="http://j2ee.pl/wp-content/poi-excel.zip" title="poi-excel.zip">poi-excel.zip</a></p>
<p>P.S.<br />
W trakcie tworzenia szkieletu aplikacji za pomocą Maven otrzymałem taki oto komunikat błędu:</p>
<p>Embedded error: Archetype does not exist: Unable to determine the release version</p>
<p>Google zupełnie milczało na ten temat (0 trafień). Próbowałem wykonać kilka różnych zabiegów w celu poprawy sytuacji, ale dopiero skasowanie katalogu .m2 z mojego katalogu domowego i ponowne uruchomienie polecenia mvn:create zaowocowało komunikatem BUILD SUCCESSFUL.</p>
]]></content:encoded>
			<wfw:commentRss>http://j2ee.pl/2007/06/28/wstep-do-apache-poi-hssf-dostep-do-plikow-ms-excel-w-javie/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
