cgrand / spreadmap

Evil project to turn excel spreadsheets in persistent reactive structures.
89 stars 3 forks source link

Read a specific sheet within a workbook? #4

Open ghost opened 10 years ago

ghost commented 10 years ago

I'm not sure if this is within the scope of the API - I'd like to read a specific sheet within a workbook.

clojens commented 10 years ago

You were too much in a hurry to leave, as I found the answer you were looking for:

;; prepare on my side of things (how I like to bootstrap easily in instarepl)
(require '[alembic.still :refer [distill*]]
             '[clojure.repl :refer [doc]])
(distill* '[[net.cgrand/spreadmap "0.1.4"]] {:verbose false})
(require '[net.cgrand.spreadmap :as xls :refer :all ])
(import '[org.apache.poi.ss.usermodel Workbook WorkbookFactory CellValue DateUtil Cell])

;; public exposed forms, functions, types, interfaces
(keys (ns-publics 'net.cgrand.spreadmap))
;;=> (sheet-index spreadmap Valueable SheetMisc ->SpreadSheet value formula-tokens CellMisc fm=)

;; load a excel workbook
(def book1 (spreadmap "G:\\Book1.xls"))

;; note the details of picking a right object for 97/2003 (HSSF) or 2007 (XSSF) Excel format is made for you, using the WorkbookFactory
(type book1) ;;=> net.cgrand.spreadmap.SpreadSheet

;; testing generic data accessors of spreadsheet
(.containsKey book1 "A2")
(.valAt book1 "bar!A2")

;; get the workbook actual by creating convenient access
(def hssf (.wb book1))

;; now we can do the type hssf check (I already knew, hence the name ;)
(type hssf) ;;=> org.apache.poi.hssf.usermodel.HSSFWorkbook

;; get sheet name by index is now possible
(.getSheetName hssf 1) ;;=> "bar"

;; and finally be able to obtain the actual sheet, pull via string name
(.getSheet hssf "bar") ;;=> #<HSSFSheet org.apache.poi.hssf.usermodel.HSSFSheet@4e91774>

Thats it I think

clojens commented 10 years ago

As a general tip for your future effort, it helps to look at what the interfaces are implementing in terms of protocols to see what method names are implemented, are they collections or not: https://github.com/cgrand/spreadmap/blob/master/src/net/cgrand/spreadmap.clj#L135 actually made me aware that the form (.wb book1) would be available as such, which led me down to checking its type (type (.wb book1)) and then Google to look those up in the API documentation of the Java library (since clojure wraps Java often) to find the matching Java methods and expected arguments and whether or not this is a real type or a factory. In which case you know you wont find your implementation methods there (wrong place, keep looking) so travel down the derived types/concrete implementations and keep digging down to your final type. Usually you look for a getter that takes a integer/string (identifier) to pull the collection you seek.

ghost commented 10 years ago

Thanks for the pointers and the nice write up. My apologies for getting back to you so late on this: I didn't see the github notification until recently and real life butted itself and this side project was sidelined for a while.

I'm closing this issue with a good enough solution for now.