From: <prn...@us...> - 2009-12-13 20:48:32
|
Revision: 6642 http://octave.svn.sourceforge.net/octave/?rev=6642&view=rev Author: prnienhuis Date: 2009-12-13 20:48:21 +0000 (Sun, 13 Dec 2009) Log Message: ----------- Moved range limit calculations from xlsread to parsecell; fixed parse_sp_range for larger column capacities(OOXML & ODS). Modified Paths: -------------- trunk/octave-forge/main/io/inst/parse_sp_range.m trunk/octave-forge/main/io/inst/parsecell.m trunk/octave-forge/main/io/inst/xlsread.m Modified: trunk/octave-forge/main/io/inst/parse_sp_range.m =================================================================== --- trunk/octave-forge/main/io/inst/parse_sp_range.m 2009-12-13 14:47:03 UTC (rev 6641) +++ trunk/octave-forge/main/io/inst/parse_sp_range.m 2009-12-13 20:48:21 UTC (rev 6642) @@ -21,15 +21,14 @@ ## Author: Philip Nienhuis ## Created: 2009-06-20 -## Latest update 2009-12-11 +## Latest update 2009-12-13 function [topleft, nrows, ncols, toprow, lcol] = parse_sp_range (range_org) - # This entire function needs fixing or replacement for OOXML (larger ranges) - range = deblank (toupper (range_org)); range_error = 0; nrows = 0; ncols = 0; + # Basic checks if (index (range, ':') == 0) if (isempty (range)) range_error = 0; @@ -37,10 +36,15 @@ rightcol = 'A'; else # Only upperleft cell given, just complete range to 1x1 + # (needed for some routines) range = [range ":" range]; endif endif + + # Split up both sides of the range [topleft, lowerright] = strtok (range, ':'); + + # Get toprow and clean up left column [st, en] = regexp (topleft, '\d+'); toprow = str2num (topleft(st:en)); leftcol = deblank (topleft(1:st-1)); @@ -51,6 +55,7 @@ [st, en2] = regexp (leftcol,'\D+'); leftcol = leftcol(en1+1:en2); + # Get bottom row and clean up right column [st, en] = regexp (lowerright,'\d+'); bottomrow = str2num (lowerright(st:en)); rightcol = deblank (lowerright(2:st-1)); @@ -60,33 +65,30 @@ endif [st, en2] = regexp (rightcol,'\D+'); rightcol = rightcol(en1+1:en2); + + # Check nr. of rows nrows = bottomrow - toprow + 1; if (nrows < 1) range_error = 1; endif if (range_error == 0) - # Get columns. - # FIXME for OOXML! We provisonally assume Excel 97 format, max 256 columns - ncols = 0; - [st, en1] = regexp (leftcol, '\D+'); - [st, en2] = regexp (rightcol, '\D+'); - i1= 0; i2 = 0; - if (en2 > en1) - i1 = rightcol(2:2) - leftcol(1:1) + 1; - i2 = rightcol(1:1) - 'A'+ 1; - lcol = leftcol(1:1) - 'A' + 1; - elseif (en2 == en1) - i1 = rightcol(en2) - leftcol(en2) + 1; - lcol = leftcol(1:1) - 'A' + 1; - if (en2 == 2) - i2 = rightcol(1) - leftcol(1); - lcol = lcol * 26 + (leftcol(2:2) - 'A' + 1); - endif - else - range_error = 1; - endif - ncols = i1 + 26 * i2; + # Get left column nr. + [st, en] = regexp (leftcol, '\D+'); + lcol = (leftcol(st:st) - 'A' + 1); + while (++st <= en) + lcol = lcol * 26 + (leftcol(st:st) - 'A' + 1); + endwhile + + # Get right column nr. + [st, en] = regexp (rightcol, '\D+'); + rcol = (rightcol(st:st) - 'A' + 1); + while (++st <= en) + rcol = rcol * 26 + (rightcol(st:st) - 'A' + 1); + endwhile + + # Check + ncols = rcol - lcol + 1 if (ncols < 1) range_error = 1; endif Modified: trunk/octave-forge/main/io/inst/parsecell.m =================================================================== --- trunk/octave-forge/main/io/inst/parsecell.m 2009-12-13 14:47:03 UTC (rev 6641) +++ trunk/octave-forge/main/io/inst/parsecell.m 2009-12-13 20:48:21 UTC (rev 6642) @@ -38,11 +38,11 @@ ## @end deftypefn ## Author: Philip Nienhuis -## Created: 2009-12-11 +## Created: 2009-12-13 -function [ numarr, txtarr, lim ] = parsecell (rawarr) +function [ numarr, txtarr, lim ] = parsecell (rawarr, rawlimits=[]) - lim = struct ( "numlimits", [], "txtlimits", [] ); + lim = struct ( "numlimits", [], "txtlimits", []); numarr = []; txtarr = {}; @@ -59,7 +59,7 @@ endif # Prepare parsing [nrows, ncols] = size (rawarr); - + # Find text entries in raw data cell array txtptr = cellfun ('isclass', rawarr, 'char'); if (~no_txt) @@ -82,6 +82,11 @@ # Crop textarray txtarr = txtarr(irowt:irowb, icoll:icolr); lim.txtlimits = [icoll, icolr; irowt, irowb]; + if (~isempty (rawlimits)) + correction = [1; 1]; + lim.txtlimits (:,1) = lim.txtlimits(:,1) + rawlimits(:,1) - correction; + lim.txtlimits (:,2) = lim.txtlimits(:,2) + rawlimits(:,1) - correction; + endif else # If no text cells found return empty text array txtarr = {}; @@ -118,8 +123,16 @@ endfor numarr = cat (2, tmparr{:}); lim.numlimits = [icoll, icolr; irowt, irowb]; + if (~isempty (rawlimits)) + correction = [1; 1]; + lim.numlimits(:,1) = lim.numlimits(:,1) + rawlimits(:,1) - correction(:); + lim.numlimits(:,2) = lim.numlimits(:,2) + rawlimits(:,1) - correction(:); + endif endif endif + + lim.rawlimits = rawlimits; + endif endfunction Modified: trunk/octave-forge/main/io/inst/xlsread.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsread.m 2009-12-13 14:47:03 UTC (rev 6641) +++ trunk/octave-forge/main/io/inst/xlsread.m 2009-12-13 20:48:21 UTC (rev 6642) @@ -101,11 +101,11 @@ ## @end example ## ## @example -## [An, Tn, Ra, status] = xlsread ('Sales2009.xls', 'Third_sheet'); +## [An, Tn, Ra, limits] = xlsread ('Sales2009.xls', 'Third_sheet'); ## (which returns the numeric contents in range C3:AB40 in worksheet ## 'Third_sheet' in file test4.xls into array An, the text data into -## array Tn, the raw cell data into cell array Ra and the return status -## in status) +## array Tn, the raw cell data into cell array Ra and the ranges from +## where the actual data came in limits) ## @end example ## ## @seealso xlswrite, xlsopen, xls2oct, xlsclose, xlsfinfo, oct2xls @@ -116,7 +116,7 @@ ## Created: 2009-10-16 ## Latest update: 2009-12-11 -function [ numarr, txtarr, rawarr, limits ] = xlsread (fn, wsh, datrange, reqintf=[]) +function [ numarr, txtarr, rawarr, lims ] = xlsread (fn, wsh, datrange, reqintf=[]) rstatus = 0; @@ -164,22 +164,10 @@ xls = xlsclose (xls); if (rstatus) - [numarr, txtarr, lims] = parsecell (rawarr); - limits = []; - - # Rebase various limits to original spreadsheet limits - if ((strcmp (xtype, 'POI') || strcmp (xtype, 'JXL')) && ~isempty (rawlimits)) - correction = [1; 1]; - if (~isempty(lims.numlimits)) - limits.numlimits(:,1) = rawlimits(:,1) + lims.numlimits(:,1) - correction(:); - limits.numlimits(:,2) = limits.numlimits(:,1) + lims.numlimits(:,2) - lims.numlimits(:,1); - endif - if (~isempty(lims.txtlimits)) - limits.txtlimits(:,1) = rawlimits(:,1) + lims.txtlimits(:,1) - correction(:); - limits.txtlimits(:,2) = limits.txtlimits(:,1) + lims.txtlimits(:,2) - lims.txtlimits(:,1); - endif - limits.rawlimits = rawlimits; - endif + [numarr, txtarr, lims] = parsecell (rawarr, rawlimits); + # Wipe lims if using Excel (that doesn't return reliable rawlimits). + # The user can get the limits relative to the rawarr by parsecell (rawarr). + if (strcmp (xtype, 'COM')) lims = []; endif else rawarr = {}; numarr = []; txtarr = {}; endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2009-12-13 20:51:34
|
Revision: 6643 http://octave.svn.sourceforge.net/octave/?rev=6643&view=rev Author: prnienhuis Date: 2009-12-13 20:51:27 +0000 (Sun, 13 Dec 2009) Log Message: ----------- First throw at ODS spreadsheet (OpenOffice.org) support. Only reading works, writing too unreliable yet. Added Paths: ----------- trunk/octave-forge/main/io/inst/calccelladdress.m trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/odsclose.m trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/odsread.m Added: trunk/octave-forge/main/io/inst/calccelladdress.m =================================================================== --- trunk/octave-forge/main/io/inst/calccelladdress.m (rev 0) +++ trunk/octave-forge/main/io/inst/calccelladdress.m 2009-12-13 20:51:27 UTC (rev 6643) @@ -0,0 +1,39 @@ +## Copyright (C) 2009 Philip +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## calccelladdress - compute spreadsheet style cell address from +## row & column index. +## +## Max column index currently set to 1024 (ODS) + +## Author: Philip Nienhuis <prnienhuis at users.sf.net> +## Created: 2009-12-12 + +function [ celladdress ] = calccelladdress (trow, lcol, row, column) + + colnr = lcol + column - 1; + if (colnr> 1024) error ("Column nr >1024"); endif + str = char (rem ((colnr-1), 26) + 'A'); + if (colnr > 26 && colnr < 703) + tmp = char (floor ((colnr - 27) / 26) + 'A'); + str = [tmp str]; + elseif (colnr > 702) + tmp = char (floor ((colnr - 703) / 26) + 'A'); + str = ['A' tmp str]; + endif + celladdress = sprintf ("%s%d", str, trow + row - 1); + +endfunction \ No newline at end of file Added: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m (rev 0) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2009-12-13 20:51:27 UTC (rev 6643) @@ -0,0 +1,62 @@ +## Copyright (C) 2009 Philip Nienhuis <pr.nienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## ods2oct - get data out of an ODS spreadsheet into octave. +## Watch out, no error checks, and spreadsheet formula error results +## are conveyed as 0 (zero). +## +## Author: Philip Nienhuis +## Created: 2009-12-13 + +function [ rawarr, ods ] = ods2oct (ods, wsh, range) + + sh = ods.workbook.getSheet (wsh); + + [dummy, nrows, ncols, toprow, lcol] = parse_sp_range (range); + + # Placeholder for data + rawarr = cell (nrows, ncols); + for ii=1:nrows + for jj = 1:ncols + celladdress = calccelladdress (toprow, lcol, ii, jj); + try + val = sh.getCellAt (celladdress).getValue (); + catch + # No panic, probably a merged cell + val = {}; + end_try_catch + if (~isempty (val)) + if (ischar (val)) + # Text string + rawarr (ii, jj) = val; + elseif (isnumeric (val)) + # Boolean + if (val) rawarr (ii, jj) = true; else; rawarr (ii, jj) = false; endif + else + try + val = sh.getCellAt (celladdress).getValue ().doubleValue (); + rawarr (ii, jj) = val; + catch + # Probably empty Cell + end_try_catch + endif + endif + endfor + endfor + + ods.limits = [ lcol, lcol+ncols-1; toprow, toprow+nrows-1 ]; + +endfunction Added: trunk/octave-forge/main/io/inst/odsclose.m =================================================================== --- trunk/octave-forge/main/io/inst/odsclose.m (rev 0) +++ trunk/octave-forge/main/io/inst/odsclose.m 2009-12-13 20:51:27 UTC (rev 6643) @@ -0,0 +1,32 @@ +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## odsclose - close an ods spreadsheet file & if needed write out to disk +## Basic version - no checks yet + +## Author: Philip Nienhuis +## Created: 2009-12-13 + +function [ ods ] = odsclose (ods) + + if (ods.changed > 0) + file = java_new ('java.io.File', ods.filename); + ods.workbook.saveAs (file); + endif + + ods = []; + +endfunction Added: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m (rev 0) +++ trunk/octave-forge/main/io/inst/odsopen.m 2009-12-13 20:51:27 UTC (rev 6643) @@ -0,0 +1,30 @@ +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## odsopen - open ODS spreadsheet +## Basic version, no checks yet + +## Author: Philip Nienhuis +## Created: 2009-12-13 + +function [ ods ] = odsopen (filename, rw=0) + + file = java_new ('java.io.File', filename); + wb = java_invoke ('org.jopendocument.dom.spreadsheet.SpreadSheet', 'createFromFile', file); + + ods = struct ("xtype", 'JOD', "app", file, "filename", filename, "workbook", wb, "changed", 0, "limits", []); + +endfunction Added: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m (rev 0) +++ trunk/octave-forge/main/io/inst/odsread.m 2009-12-13 20:51:27 UTC (rev 6643) @@ -0,0 +1,61 @@ +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} @var{rawarr} = odsread (@var{filename}, @var{wsh}, @var{range}) +## . +## +## Proof-of-concept function for reading data from an ODS spreadsheet. +## It works but there are no error checks at all; erroneous function +## results and empty cells are not ignored but returned as 0. +## +## You need to have jOpenDocument-1.2b2.jar in your javaclasspath (get it at +## http://www.jopendocument.org/) and the octave-forge java package installed. +## +## @var{filename} must be a valid ODS spreadsheet file name. If @var{filename} +## does not contain any directory path, the file is saved in the current +## directory. +## +## @var{wsh} is the name or index number of a worksheet in the spreadsheet file. +## +## @var{range} must be a valid spreadsheet range and cannot be empty. +## +## Return args @var{numarr} and @var{txtarr} contain numeric & text data, +## resp.; @var{rawarr} contains the raw data and lim the actual cell ranges +## from where the data originated. +## +## Example: +## +## @example +## [ n, t, r, l ] = odsread ('test1.ods', '2ndSh', 'A1:AF250'); +## @end example +## +## @end deftypefn + +## Author: Philip Nienhuis <prnienhuis at users.sf.net> +## Created: 2009-12-12 + +function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh, range) + + ods = odsopen (filename, 0); + + [rawarr, ods] = ods2oct (ods, wsh, range); + + [numarr, txtarr, lim] = parsecell (rawarr, ods.limits); + + odsclose (ods); + +endfunction This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2009-12-30 15:07:05
|
Revision: 6680 http://octave.svn.sourceforge.net/octave/?rev=6680&view=rev Author: prnienhuis Date: 2009-12-30 15:06:54 +0000 (Wed, 30 Dec 2009) Log Message: ----------- Revised and improved, now also based on odftoolkit & xercesImpl. Only reading from .ods supported, adding write support is not yet feasible Modified Paths: -------------- trunk/octave-forge/main/io/inst/calccelladdress.m trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/odsclose.m trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/odsread.m trunk/octave-forge/main/io/inst/parsecell.m Modified: trunk/octave-forge/main/io/inst/calccelladdress.m =================================================================== --- trunk/octave-forge/main/io/inst/calccelladdress.m 2009-12-30 15:04:15 UTC (rev 6679) +++ trunk/octave-forge/main/io/inst/calccelladdress.m 2009-12-30 15:06:54 UTC (rev 6680) @@ -17,20 +17,22 @@ ## calccelladdress - compute spreadsheet style cell address from ## row & column index. ## -## Max column index currently set to 1024 (ODS) +## Max column index currently set to 1378 (ODS has max 1024) ## Author: Philip Nienhuis <prnienhuis at users.sf.net> ## Created: 2009-12-12 +## Last updated: 2009-12-27 function [ celladdress ] = calccelladdress (trow, lcol, row, column) + if (nargin < 4) error ("calccelladdress: not enough arguments.") endif colnr = lcol + column - 1; - if (colnr> 1024) error ("Column nr >1024"); endif + if (colnr> 1378) error ("Column nr > 1378"); endif str = char (rem ((colnr-1), 26) + 'A'); if (colnr > 26 && colnr < 703) tmp = char (floor ((colnr - 27) / 26) + 'A'); str = [tmp str]; - elseif (colnr > 702) + elseif (colnr > 702 && colnr < 1379) tmp = char (floor ((colnr - 703) / 26) + 'A'); str = ['A' tmp str]; endif Modified: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m 2009-12-30 15:04:15 UTC (rev 6679) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2009-12-30 15:06:54 UTC (rev 6680) @@ -14,6 +14,380 @@ ## along with Octave; see the file COPYING. If not, see ## <http://www.gnu.org/licenses/>. +## -*- texinfo -*- +## @deftypefn {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}) +## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}) +## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}, @var{range}) +## +## Read data contained within range @var{range} from worksheet @var{wsh} +## in an OpenOffice.org spreadsheet file pointed to in struct @var{ods}. +## +## ods2oct is a mere wrapper for interface-dependent scripts (e.g., +## ods2jotk2oct and ods2jod2oct) that do the actual reading. +## +## @var{wsh} is either numerical or text, in the latter case it is +## case-sensitive and it may be max. 31 characters long. +## Note that in case of a numerical @var{wsh} this number refers to the +## position in the worksheet stack, counted from the left in a Calc +## window. The default is numerical 1, i.e. the leftmost worksheet +## in the ODS file. +## +## @var{range} is expected to be a regular spreadsheet range format, +## or "" (empty string, indicating all data in a worksheet). +## +## If only the first argument is specified, ods2oct will try to read +## all contents from the first = leftmost (or the only) worksheet (as +## if a range of @'' (empty string) was specified). +## +## If only two arguments are specified, ods2oct assumes the second +## argument to be @var{wsh}. In that case ods2oct will try to read +## all data contained in that worksheet. +## +## Return argument @var{rawarr} contains the raw spreadsheet cell data. +## Optional return argument @var{ods} contains the pointer struct. Field +## @var{ods}.limits contains the outermost column and row numbers of the +## actually read cell range. +## @var{rstatus} will be set to 1 if the requested data have been read +## successfully, 0 otherwise. +## Use parsecell() to separate numeric and text values from @var{rawarr}. +## +## @var{ods} is supposed to have been created earlier by odsopen in the +## same octave session. It is only referred to, not changed. +## +## Erroneous data and empty cells turn up empty in @var{rawarr}. +## Date/time values in OpenOffice.org are returned as numerical values +## with base 1-1-000 (same as octave). But beware that Excel spreadsheets +## rewritten by OpenOffice.org into .ods format may have numerical date +## cells with base 01-01-1900 (same as MS-Excel). +## +## Be aware that ods2oct trims @var{rawarr} from empty outer rows & columns, +## so any returned cell array may turn out to be smaller than requested +## in @var{range}. +## +## When reading from merged cells, all array elements NOT corresponding +## to the leftmost or upper OpenOffice.org cell will be treated as if the +## "corresponding" cells are empty. +## +## Examples: +## +## @example +## A = ods2oct (ods1, '2nd_sheet', 'C3:ABS40000'); +## (which returns the numeric contents in range C3:ABS40000 in worksheet +## '2nd_sheet' from a spreadsheet file pointed to in pointer struct ods1, +## into numeric array A) +## @end example +## +## @example +## [An, ods2, status] = ods2oct (ods2, 'Third_sheet'); +## @end example +## +## @seealso odsopen, odsclose, parsecell, odsread, odsfinfo +## +## @end deftypefn + +## Author: Philip Nienhuis +## Created: 2009-12-13 +## Latest update: 2009-12-30 + +function [ rawarr, ods ] = ods2oct (ods, wsh=1, datrange=[]) + + if (strcmp (ods.xtype, 'OTK')) + # Read xls file tru Java & ODF toolkit + [rawarr, ods, rstatus] = ods2jotk2oct (ods, wsh, datrange); + + elseif (strcmp (ods.xtype, 'JOD')) + [rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, datrange); + +# elseif ---- < Other interfaces here > + + else + error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", xls.xtype)); + + endif + +endfunction + +#===================================================================== + +## Copyright (C) 2009 Philip Nienhuis <prnienhuis _at- users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## odf2jotk2oct - read ODS spreadsheet data using Java & odftoolkit +## You need proper java-for-octave & odfdom.jar + xercesImpl.jar +## in your javaclasspath. + +## Author: Philip Nenhuis <pr.nienhuis at users.sf.net> +## Created: 2009-12-24 +## Last update: 2009-12-30 + +function [ rawarr, ods, status ] = ods2jotk2oct (ods, wsh, crange = []) + + # Parts after user gfterry in + # http://www.oooforum.org/forum/viewtopic.phtml?t=69060 + + # Get contents and table stuff from the workbook + odfcont = ods.workbook; # Use a local copy just to be sure. octave + # makes physical copies only when needed (?) + xpath = ods.app.getXPath; + + # AFAICS ODS spreadsheets have the following hierarchy: + # <table:table> - table nodes, the actual worksheets; + # <table:table-row> - row nodes, the rows in a worksheet; + # <table:table-cell> - cell nodes, the cells in a row; + # Styles (formatting) are defined in a section "settings" outside the + # contents proper but are referenced in the nodes. + + # Create an instance of type NODESET for use in subsequent statement + NODESET = java_get ('javax.xml.xpath.XPathConstants', 'NODESET'); + # Parse sheets ("tables") from ODS file + sheets = xpath.evaluate ("//table:table", odfcont, NODESET); + nr_of_sheets = sheets.getLength (); + + # Check user input & find sheet pointer (1-based), using ugly hacks + if (~isnumeric (wsh)) + # Search in sheet names, match sheet name to sheet number + ii = 0; + while (++ii <= nr_of_sheets && ischar (wsh)) + # Look in first part of the sheet nodeset + tmp1 = char (sheets.item(ii-1))(1:150); + ist = index (tmp1, 'table:name=') + 12; + ien = index (tmp1(ist:end), '" table') - 2 + ist; + if (strcmp (tmp1(ist:ien), wsh)) + # Convert local copy of wsh into a number (pointer) + wsh = ii + i; + endif + endwhile + if (ischar (wsh)) error (sprintf ("No worksheet '%s' found in file %s", wsh, ods.filename)); endif + elseif (wsh > nr_of_sheets || wsh < 1) + # We already have a numeric sheet pointer. If it's not in range: + error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); + endif + + # Get table-rows in sheet no. wsh. Sheet count = 1-based (!) + str = sprintf ("//table:table[%d]/table:table-row", wsh); + sh = xpath.evaluate (str, odfcont, NODESET); + nr_of_rows = sh.getLength(); + # Create storage for data content. We can't know max row length yet so expect the worst + rawarr = cell (nr_of_rows, 1024); + + # Either parse (given cell range) or prepare (unknown range) help variables + if (isempty (crange)) + trow = 1; # Top row + brow = nr_of_rows; # Bottom row (ODS max = 65535, Xpath's guess = better) + nrows = brow; # Number of rows to be read + lcol = 1; # Leftmost column of range + rcol = 1024; # Rightmost columns (1024 on ODS) + ncols = rcol; # Number of columns to be read + else + [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); + brow = min (trow + nrows - 1, nr_of_rows); + # Check ODS column limits + if (lcol > 1024 || trow > 65536) error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); endif + # Truncate range silently if needed + rcol = min (lcol + ncols - 1, 1024); + ncols = min (ncols, 1024 - lcol + 1); + nrows = min (nrows, 65536 - trow + 1); + endif + + # Read from worksheet row by row. Row numbers are 0-based + rightmcol = 0; # Used to find actual rightmost column + ii = trow - 1; # Spreadsheet row counter + rowcnt = ii; # xpath row counter (multiple rows may be condensed in one!) + while (++ii <= brow) + row = sh.item(rowcnt++); + nr_of_cells = min (row.getLength (), rcol); + rightmcol = max (rightmcol, nr_of_cells); # Keep track of max row length + + # Read column (cell, "table-cell" in ODS speak) by column + jj = lcol; r_cols = 0; + while (jj + r_cols <= 1024 && jj <= rcol) + tcell = char (row.getCellAt(jj-1)); + cellcont = getcellcont (tcell); # Parse cell contents, func = below + if (~isempty (cellcont.cvalue)) + + # Get data from cell + switch cellcont.ctype + case {'float', 'currency', 'percentage'} + rawarr(ii, jj) = str2double (cellcont.cvalue); + case 'date' + # Dates are returned as octave datenums, i.e. 0-0-0000 based + str = cellcont.cvalue; + yr = str2num (str(1:4)); + mo = str2num (str(6:7)); + dy = str2num (str(9:10)); + if (index (str, 'T')) + hh = str2num (str(12:13)); + mm = str2num (str(15:16)); + ss = str2num (str(18:19)); + rawarr(ii, jj) = datenum (yr, mo, dy, hh, mm, ss); + else + rawarr(ii, jj) = datenum (yr, mo, dy); + endif + case 'time' + str = cellcont.cvalue; + if (index (str, 'PT')) + hh = str2num (str(3:4)); + mm = str2num (str(6:7)); + ss = str2num (str(9:10)); + rawarr(ii, jj) = datenum (0, 0, 0, hh, mm, ss); + endif + case 'boolean' + if (strcmp (cellcont.cvalue, 'true')) + rawarr(ii, jj) = true; + else + rawarr(ii, jj) = false; + endif + case 'string' + rawarr(ii, jj) = cellcont.cvalue; + otherwise + # Nothing + endswitch + endif + ++jj; # Next cell + r_cols = cellcont.cols; # Number of repeated columns. + endwhile + + # Check for repeated rows (i.e. condensed in one table-row) + mm = index (char(row), 'number-rows-repeated'); + if (mm) + str = char (row) (1:82); + ist = mm + 22; ien = index (str(ist:end), '"') + ist - 2; + extrarows = str2num (str(ist:ien)); + if (extrarows > 0 && ii + extrarows < 65535) + # Expand table-row + nr_of_rows = nr_of_rows + extrarows - 1; + ii = ii + extrarows - 1; + nrows = min (65536, nrows + extrarows - 1); + brow = min (trow + nrows - 1, nr_of_rows); + # Increase return argument size if needed + tmp = cell (extrarows, 1024); + rawarr = [rawarr; tmp]; + endif + endif + + endwhile + + # Pre-crop rawarr from right (max was 1024) and bottom + rawarr = rawarr (1:nr_of_rows, 1:rightmcol); + + # Crop rawarr from all empty outer rows & columns just like Excel does + # & keep track of limits + emptr = cellfun('isempty', rawarr); + irowt = 1; + while (all (emptr(irowt, :))), irowt++; endwhile + irowb = nr_of_rows; + while (all (emptr(irowb, :))), irowb--; endwhile + icoll = 1; + while (all (emptr(:, icoll))), icoll++; endwhile + icolr = rightmcol; + while (all (emptr(:, icolr))), icolr--; endwhile + # Crop textarray + rawarr = rawarr(irowt:irowb, icoll:icolr); + status = 1; + + ods.limits = [lcol+icoll-1, lcol+icolr-1; trow+irowt-1, trow+irowb-1]; + +endfunction + + +## Copyright (C) 2009 by Philip Nienhuis <prnienhuis at users.sf.net> +## +## Parse some data from ODS spreadsheet cells. +## Input = character string <table:table-cell>...</table:table-cell> +## +## Author: Philip Nenhuis <pr.nienhuis at users.sf.net> +## Created: 2009-12-24 +## Last update: 2009-12-27 + +function cellcont = getcellcont (tcell) + + cellcont = struct ("ctype", '', "cvalue", '', "cols", 0); + + # Check for repeated columns (often empty columns, viz. to right of data) + ii = index (tcell, 'number-columns-repeated'); + if (ii) + ist = ii+25; ien = index(tcell(ist:end), '"') + ist - 2; + cellcont.cols = str2num (tcell(ist:ien)); + endif + + # Get cell value type: float / boolean / string / date/.... Skip errors. + ii = index (tcell, 'value-type='); + if (ii && ~index (tcell, 'text:p>Err:') && ~index (tcell, 'text:p>#DIV')) + # Then cell contains useful data. + ist = ii + 12; ien = index (tcell(ist:end), '"') + ist - 2; + cellcont.ctype = tcell(ist:ien); + + if (strcmp (cellcont.ctype, 'string')) + # Get string value from between <text:p|r> </text:p|r> tags + ii = index (tcell, '<text'); + if (ii) + ist = ii + 8; ien = index (tcell(ist:end), '</text') + ist - 2; + cellcont.cvalue = tcell(ist:ien); + endif + + elseif (strcmp (cellcont.ctype, 'date')) + # Get date string + ii = index (tcell, 'date-value='); + if (ii) + ist = ii + 12; ien = index (tcell(ist:end), '"') + ist - 2; + # Return string for the time being + cellcont.cvalue = tcell(ist:ien); + endif + + elseif (strcmp (cellcont.ctype, 'time')) + # Get time string + ii = index (tcell, 'time-value='); + if (ii) + ist = ii + 12; ien = index (tcell(ist:end), '"') + ist - 2; + # Return string for the time being (no pun intended) + cellcont.cvalue = tcell(ist:ien); + endif + + else + # Get cell value as string (float, currency, percentage) + ii = index (tcell, 'value='); + if (ii) + ist = ii + 7; ien = index (tcell(ist:end), '"') + ist - 2; + cellcont.cvalue = tcell(ist:ien); + endif + + endif + endif + +endfunction + + +#=========================================================================== + +## Copyright (C) 2009 Philip Nienhuis <pr.nienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + ## ods2oct - get data out of an ODS spreadsheet into octave. ## Watch out, no error checks, and spreadsheet formula error results ## are conveyed as 0 (zero). @@ -21,11 +395,22 @@ ## Author: Philip Nienhuis ## Created: 2009-12-13 -function [ rawarr, ods ] = ods2oct (ods, wsh, range) +function [ rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, crange) + persistent months; + months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + + if (isempty (crange)) error ("Empty cell range not allowed w. jOpenDocument."); endif + + if (isnumeric(wsh)) wsh = max (wsh - 1, 1); endif # Sheet COUNT starts at 0! sh = ods.workbook.getSheet (wsh); - [dummy, nrows, ncols, toprow, lcol] = parse_sp_range (range); + [dummy, nrows, ncols, toprow, lcol] = parse_sp_range (crange); + if (lcol > 1024 || toprow > 65536) error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); endif + # Truncate range silently if needed + rcol = min (lcol + ncols - 1, 1024); + ncols = min (ncols, 1024 - lcol + 1); + nrows = min (nrows, 65536 - toprow + 1); # Placeholder for data rawarr = cell (nrows, ncols); @@ -41,16 +426,28 @@ if (~isempty (val)) if (ischar (val)) # Text string - rawarr (ii, jj) = val; + rawarr(ii, jj) = val; elseif (isnumeric (val)) # Boolean - if (val) rawarr (ii, jj) = true; else; rawarr (ii, jj) = false; endif + if (val) rawarr(ii, jj) = true; else; rawarr(ii, jj) = false; endif else try val = sh.getCellAt (celladdress).getValue ().doubleValue (); - rawarr (ii, jj) = val; + rawarr(ii, jj) = val; catch - # Probably empty Cell + val = char (val); + if (isempty (val)) + # Probably empty Cell + else + # Maybe date / time value. Dirty hack to get values: + mo = strmatch (toupper (val(5:7)), months); + dd = str2num (val(9:10)); + yy = str2num (val(25:end)); + hh = str2num (val(12:13)); + mm = str2num (val(15:16)); + ss = str2num (val(18:19)); + rawarr(ii, jj) = datenum (yy, mo, dd, hh, mm,ss); + endif end_try_catch endif endif @@ -58,5 +455,7 @@ endfor ods.limits = [ lcol, lcol+ncols-1; toprow, toprow+nrows-1 ]; + + rstatus = ~isempty (rawarr); endfunction Modified: trunk/octave-forge/main/io/inst/odsclose.m =================================================================== --- trunk/octave-forge/main/io/inst/odsclose.m 2009-12-30 15:04:15 UTC (rev 6679) +++ trunk/octave-forge/main/io/inst/odsclose.m 2009-12-30 15:06:54 UTC (rev 6680) @@ -14,19 +14,19 @@ ## along with Octave; see the file COPYING. If not, see ## <http://www.gnu.org/licenses/>. -## odsclose - close an ods spreadsheet file & if needed write out to disk -## Basic version - no checks yet +## odsclose - close an ods spreadsheet file +## usage: ods = odsclose (ods) ## Author: Philip Nienhuis ## Created: 2009-12-13 +## Last update: 2009-12-27 function [ ods ] = odsclose (ods) - if (ods.changed > 0) - file = java_new ('java.io.File', ods.filename); - ods.workbook.saveAs (file); - endif + # If needed warn that dangling spreadsheet pointers may be left + if (nargout < 1) warning ("return argument missing - ods invocation not reset."); endif + # Until proper ODS write support has been implemented, not much need be done ods = []; endfunction Modified: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m 2009-12-30 15:04:15 UTC (rev 6679) +++ trunk/octave-forge/main/io/inst/odsopen.m 2009-12-30 15:06:54 UTC (rev 6680) @@ -14,17 +14,252 @@ ## along with Octave; see the file COPYING. If not, see ## <http://www.gnu.org/licenses/>. -## odsopen - open ODS spreadsheet -## Basic version, no checks yet +## -*- texinfo -*- +## @deftypefn {Function File} @var{ods} = odsopen (@var{filename}) +## @deftypefnx {Function File} @var{ods} = odsopen (@var{filename}, @var{readwrite}) +## @deftypefnx {Function File} @var{ods} = odsopen (@var{filename}, @var{readwrite}, @var{reqintf}) +## Get a pointer to an OpenOffice.org spreadsheet in the form of return +## argument @var{ods}. +## +## Calling odsopen without specifying a return argument is fairly useless! +## +## To make this function work at all, you need the Java package > 1.2.5 plus +## either ODFtoolkit > 3.5 & xercesImpl, or jOpenDocument installed on your +## computer + proper javaclasspath set. These interfaces are referred to as +## OTK and JOD, resp., and are preferred in that order by default (depending +## on their presence). +## +## @var{filename} must be a valid .ods OpenOffice.org file name. If @var{filename} +## does not contain any directory path, the file is saved in the current +## directory. +## +## @var{readwrite} is currently ignored until ODS writesupport is implemented. +## +## Optional input argument @var{reqintf} can be used to override the ODS +## interface automatically selected by odsopen. Currently implemented interfaces +## are 'OTK' (Java / ODFtoolkit) or 'JOD' (Java / jOpenDocument). +## +## Examples: +## +## @example +## ods = odsopen ('test1.ods'); +## (get a pointer for reading from spreadsheet test1.ods) +## +## ods = odsopen ('test2.ods', [], 'JOD'); +## (as above, indicate test2.ods will be read from; in this case using +## the jOpenDocument interface is requested) +## @end example +## +## @seealso odsclose, odsread, ods2oct, odsfinfo +## +## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-13 +## Last update: 2009-12-30 -function [ ods ] = odsopen (filename, rw=0) +function [ ods ] = odsopen (filename, rw=0, reqinterface = []) - file = java_new ('java.io.File', filename); - wb = java_invoke ('org.jopendocument.dom.spreadsheet.SpreadSheet', 'createFromFile', file); + persistent odsinterfaces; persistent chkintf; + if (isempty (chkintf)) + odsinterfaces = struct ( "OTK", [], "JOD", [] ); + chkintf = 1; + endif + + if (nargout < 1) usage ("ODS = odsopen (ODSfile, [Rw]). But no return argument specified!"); endif - ods = struct ("xtype", 'JOD', "app", file, "filename", filename, "workbook", wb, "changed", 0, "limits", []); + if (~isempty (reqinterface)) + # Try to invoke requested interface for this call. Check if it + # is supported anyway by emptying the corresponding var. + if (strcmp (tolower (reqinterface), tolower ('OTK'))) + printf ("Java/ODFtoolkit interface requested... "); + odsinterfaces.OTK = []; odsinterfaces.JOD = 0; + elseif (strcmp (tolower (reqinterface), tolower ('JOD'))) + printf ("Java/jOpenDocument interface requested... "); + odsinterfaces.OTK = 0; odsinterfaces.JOD = []; + else + usage (sprintf ("Unknown .ods interface \"%s\" requested. Only OTK or JOD supported", reqinterface)); + endif + odsinterfaces = getodsinterfaces (odsinterfaces); + # Well, is the requested interface supported on the system? + if (~odsinterfaces.(toupper (reqinterface))) + # No it aint + error (" ...but that's not supported!"); + endif + endif + + # Var xwrite is really used to avoid creating files when wanting to read, or + # not finding not-yet-existing files when wanting to write. + +# if (xwrite) xwrite = 1; endif # Be sure it's either 0 or 1 initially + # Check if ODS file exists + # Write statements temporarily disabled! + fid = fopen (filename, 'rb'); + if (fid < 0) +# if (~xwrite) + err_str = sprintf ("File %s not found\n", filename); + error (err_str) +# else +# printf ("Creating file %s\n", filename); +# xwrite = 2; +# endif + else + # close file anyway to avoid Java errors + fclose (fid); + endif + +# Check for the various ODS interfaces. No problem if they've already +# been checked, getodsinterfaces (far below) just returns immediately then. + + odsinterfaces = getodsinterfaces (odsinterfaces); + +# Supported interfaces determined; now check ODS file type. + + chk1 = strcmp (tolower (filename(end-3:end)), '.ods'); + if (~chk1) + error ("Currently ods2oct can only read reliably from .ods files") + endif + + ods = struct ("xtype", [], "app", [], "filename", [], "workbook", [], "changed", 0, "limits", []); + + if (odsinterfaces.OTK) + # Parts after user gfterry in + # http://www.oooforum.org/forum/viewtopic.phtml?t=69060 + wb = java_invoke ('org.odftoolkit.odfdom.doc.OdfDocument', 'loadDocument', filename); + ods.xtype = 'OTK'; + ods.app = wb; + ods.filename = filename; + ods.workbook = wb.getContentDom(); # Reads the entire spreadsheet + + elseif (odsinterfaces.JOD) + file = java_new ('java.io.File', filename); + wb = java_invoke ('org.jopendocument.dom.spreadsheet.SpreadSheet', 'createFromFile', file); + ods.xtype = 'JOD'; + ods.app = 'file'; + ods.filename = filename; + ods.workbook = wb; + +# elseif +# <other interfaces here> + + else + warning ("No support for OpenOffice.org .ods I/O"); + + endif + + if (~isempty (reqinterface)) + # Reset found interfaces for re-testing in the next call. Add interfaces if needed. + chkintf = []; + endif + endfunction + + +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} @var{odsinterfaces} = getodsinterfaces (@var{odsinterfaces}) +## Get supported OpenOffice.org .ods file read/write interfaces from +## the system. +## Each interface for which the corresponding field is set to empty +## will be checked. So by manipulating the fields of input argument +## @var{odsinterfaces} it is possible to specify which +## interface(s) should be checked. +## +## Currently implemented interfaces comprise: +## - Java & ODFtoolkit (www.apache.org) +## - Java & jOpenDocument (www.jopendocument.org) +## +## Examples: +## +## @example +## odsinterfaces = getodsinterfaces (odsinterfaces); +## @end example + +## Author: Philip Nienhuis +## Created: 2009-12-27 +## Last updated 2009-12-27 + +function [odsinterfaces] = getodsinterfaces (odsinterfaces) + + if (isempty (odsinterfaces.OTK) && isempty (odsinterfaces.JOD)) + chk1 = 1; + printf ("Supported interfaces: "); + else + chk1= 0; + endif + + # Try Java & ODF toolkit + if (isempty (odsinterfaces.OTK)) + odsinterfaces.OTK = 0; + try + tmp1 = javaclasspath; + # If we get here, at least Java works. Now check for proper entries + # in class path. Under *nix the classpath must first be split up + if (isunix) tmp1 = strsplit (char(tmp1), ":"); endif + jpchk = 0; entries = {"rt.jar", "odfdom.jar", "xercesImpl.jar"}; + for ii=1:size (tmp1, 2) + tmp2 = strsplit (char (tmp1(1, ii)), "\\/"); + for jj=1:size (entries, 2) + if (strmatch (entries{1, jj}, tmp2{size (tmp2, 2)})), ++jpchk; endif + endfor + endfor + if (jpchk > 2) + odsinterfaces.OTK = 1; + printf (" Java/ODFtoolkit (OTK) OK. "); + chk1 = 1; + else + warning ("\n Java support OK but not all required classes (.jar) in classpath"); + endif + catch + # ODFtoolkit support nonexistent + end_try_catch + endif + + # Try Java & jOpenDocument + if (isempty (odsinterfaces.JOD)) + odsinterfaces.JOD = 0; + try + tmp1 = javaclasspath; + # If we get here, at least Java works. Now check for proper entries + # in class path. Under unix the classpath must first be split up + if (isunix) tmp1 = strsplit (char(tmp1), ":"); endif + jpchk = 0; entries = {"rt.jar", "jOpenDocument"}; + for ii=1:size (tmp1, 2) + tmp2 = strsplit (char (tmp1(1, ii)), "\\/"); + for jj=1:size (entries, 2) + if (strmatch (entries{1, jj}, tmp2{size (tmp2, 2)})), ++jpchk; endif + endfor + endfor + if (jpchk > 1) + odsinterfaces.JOD = 1; + printf (" Java/jOpenDocument (JOD) OK. "); + chk1 = 1; + else + warning ("\nJava support OK but required classes (.jar) not all in classpath"); + endif + catch + # No jOpenDocument support + end_try_catch + endif + + # ---- Other interfaces here, similar to the ones above + + if (chk1) printf ("\n"); endif + +endfunction \ No newline at end of file Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2009-12-30 15:04:15 UTC (rev 6679) +++ trunk/octave-forge/main/io/inst/odsread.m 2009-12-30 15:06:54 UTC (rev 6680) @@ -15,47 +15,104 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} @var{rawarr} = odsread (@var{filename}, @var{wsh}, @var{range}) -## . +## @deftypefn {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}) +## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}, @var{wsh}) +## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}, @var{wsh}, @var{range}) +## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}, @var{wsh}, @var{range}, @var{reqintf}) ## -## Proof-of-concept function for reading data from an ODS spreadsheet. -## It works but there are no error checks at all; erroneous function -## results and empty cells are not ignored but returned as 0. +## Read data contained in range @var{range} from worksheet @var{wsh} +## in OpenOffice.org Calc spreadsheet file @var{filename}. ## -## You need to have jOpenDocument-1.2b2.jar in your javaclasspath (get it at -## http://www.jopendocument.org/) and the octave-forge java package installed. +## You need the octave-forge java package (> 1.2.5) and one or both of +## jopendocument.jar or preferrably: (odfdom.jar & xercesImpl.jar) in +## your javaclasspath. ## -## @var{filename} must be a valid ODS spreadsheet file name. If @var{filename} -## does not contain any directory path, the file is saved in the current -## directory. +## Return argument @var{numarr} contains the numeric data, optional +## return arguments @var{txtarr} and @var{rawarr} contain text strings +## and the raw spreadsheet cell data, respectively, and @var{limits} is +##a struct containing the data origins of the various returned arrays. ## -## @var{wsh} is the name or index number of a worksheet in the spreadsheet file. +## If @var{filename} does not contain any directory, the file is +## assumed to be in the current directory. ## -## @var{range} must be a valid spreadsheet range and cannot be empty. +## @var{wsh} is either numerical or text, in the latter case it is +## case-sensitive and it should conformtoOpenOffice.org Calc sheet +## name requirements. +## Note that in case of a numerical @var{wsh} this number refers to the +## position in the worksheet stack, counted from the left in a Calc +## window. The default is numerical 1, i.e. the leftmost worksheet +## in the Calc file. ## -## Return args @var{numarr} and @var{txtarr} contain numeric & text data, -## resp.; @var{rawarr} contains the raw data and lim the actual cell ranges -## from where the data originated. +## @var{range} is expected to be a regular spreadsheet range format, +## or "" (empty string, indicating all data in a worksheet). ## -## Example: +## If only the first argument is specified, odsread will try to read +## all contents from the first = leftmost (or the only) worksheet (as +## if a range of @'' (empty string) was specified). +## +## If only two arguments are specified, odsread assumes the second +## argument to be @var{wsh} and to refer to a worksheet. In that case +## odsread tries to read all data contained in that worksheet. ## +## The optional last argument @var{reqintf} can be used to override +## the automatic selection by odsread of one interface out of the +## supported ones: Java/ODFtoolkit or Java/jOpenDocument. +## +## Erroneous data and empty cells are set to NaN in @var{numarr} and +## turn up empty in @var{txtarr} and @var{rawarr}. Date/time values +## in date/time formatted cells are returned as numerical values in +## @var{obj} with base 1-1-000. Note that OpenOfice.org and MS-Excel +## have different date base values (1/1/0000 & 1/1/1900, resp.) and +## internal representation so MS-Excel spreadsheets rewritten into +## .ods format by OpenOffice.org Calc may have different date base +## values. +## +## @var{numarr} and @var{txtarr} are trimmed from empty outer rows +## and columns, so any returned array may turn out to be smaller than +## requested in @var{range}. +## +## When reading from merged cells, all array elements NOT corresponding +## to the leftmost or upper Calc cell will be treated as if the +## "corresponding" Calc cells are empty. +## +## odsread is just a wrapper for a collection of scripts that find out +## the interface to be used and do the actual reading. For each call +## to odsread the interface must be started and the Calc file read into +## memory. When reading multiple ranges (in optionally multiple worksheets) +## a significant speed boost can be obtained by invoking those scripts +## directly (odsopen / ods2oct [/ parsecell] / ... / odsclose). +## +## Examples: +## ## @example -## [ n, t, r, l ] = odsread ('test1.ods', '2ndSh', 'A1:AF250'); +## A = odsread ('test4.ods', '2nd_sheet', 'C3:AB40'); +## (which returns the numeric contents in range C3:AB40 in worksheet +## '2nd_sheet' from file test4.ods into numeric array A) ## @end example ## +## @example +## [An, Tn, Ra, limits] = odsread ('Sales2009.ods', 'Third_sheet'); +## (which returns all data in worksheet 'Third_sheet' in file test4.ods +## into array An, the text data into array Tn, the raw cell data into +## cell array Ra and the ranges from where the actual data came in limits) +## @end example +## +## @seealso odsopen, ods2oct, odsclose, odsfinfo, parsecell +## ## @end deftypefn ## Author: Philip Nienhuis <prnienhuis at users.sf.net> ## Created: 2009-12-12 +## Last update: 2009-12-29 -function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh, range) +function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[]) - ods = odsopen (filename, 0); + ods = odsopen (filename, 0, reqintf); - [rawarr, ods] = ods2oct (ods, wsh, range); + [rawarr, ods] = ods2oct (ods, wsh, datrange); [numarr, txtarr, lim] = parsecell (rawarr, ods.limits); - odsclose (ods); + ods = odsclose (ods); endfunction Modified: trunk/octave-forge/main/io/inst/parsecell.m =================================================================== --- trunk/octave-forge/main/io/inst/parsecell.m 2009-12-30 15:04:15 UTC (rev 6679) +++ trunk/octave-forge/main/io/inst/parsecell.m 2009-12-30 15:06:54 UTC (rev 6680) @@ -16,16 +16,25 @@ ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{numarr}, @var{txtarr}, @var{lim} ] = parsecell (@var{rawarr}) +## @deftypefnx {Function File} [ @var{numarr}, @var{txtarr}, @var{lim} ] = parsecell (@var{rawarr}, @var{limits}) ## ## Divide a heterogeneous 2D cell array into a 2D numeric array and a ## 2D cell array containing only strings. Both returned arrays are ## trimmed from empty outer rows and columns. +## This function is particularly useful for parsing cell arrays returned +## by functions reading spreadsheets (e.g., xlsread, odsread). ## ## Optional return argument @var{lim} contains two field with the outer ## column and row numbers of @var{numarr} and @var{txtarr} in the -## original @var{rawarr}. +## original array @var{rawarr}. +## If optional input argument @var{limits} contained the spreadsheet +## data limits returned in the spreadsheet file pointer struct +## (field xls.limits or ods.limits), optional return argument @var{lim} +## contains the real spreadsheet row & column numbers enclosing the +## origins of the numerical and text data returned in @var{numarr} +## and @var{txtarr}. ## -## Example: +## Examples: ## ## @example ## [An, Tn] = parsecell (Rn); @@ -33,12 +42,19 @@ ## text data into array Tn) ## @end example ## -## @seealso xlsread, xls2oct +## @example +## [An, Tn, lims] = parsecell (Rn, xls.limits); +## (which returns the numeric contents of Rn into array An and the +## text data into array Tn.) +## @end example ## +## @seealso xlsread, odsread, xls2oct, ods2oct +## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-13 +## Last updated: 2009-12-29 function [ numarr, txtarr, lim ] = parsecell (rawarr, rawlimits=[]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2009-12-30 15:51:05
|
Revision: 6682 http://octave.svn.sourceforge.net/octave/?rev=6682&view=rev Author: prnienhuis Date: 2009-12-30 15:50:56 +0000 (Wed, 30 Dec 2009) Log Message: ----------- Folded the individual scripts for each interface into the wrapper functions (e.g. xls2com2oct.m now is in the xls2oct.m script file) to needless directory clutter. Updated help text in scripts. Moved check on file extensions in xlsopen to the individual interface sections, as Excel can read more than just xls. Cleaned up code here and there. Modified Paths: -------------- trunk/octave-forge/main/io/inst/oct2xls.m trunk/octave-forge/main/io/inst/xls2oct.m trunk/octave-forge/main/io/inst/xlsfinfo.m trunk/octave-forge/main/io/inst/xlsopen.m trunk/octave-forge/main/io/inst/xlsread.m Modified: trunk/octave-forge/main/io/inst/oct2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2xls.m 2009-12-30 15:10:35 UTC (rev 6681) +++ trunk/octave-forge/main/io/inst/oct2xls.m 2009-12-30 15:50:56 UTC (rev 6682) @@ -25,10 +25,6 @@ ## Return argument @var{xlso} equals supplied argument @var{xlsi} and is ## updated by oct2xls. ## -## oct2xls is a mere wrapper for interface-dependent scripts (e.g., -## oct2com2xls, oct2jpoi2xls, oct2jxla2xls) that do the actual writing to -## spreadsheet files. -## ## A subsequent call to xlsclose is needed to write the updated spreadsheet ## to disk (and -if needed- close the Excel or Java invocation). ## @@ -75,7 +71,7 @@ ## Author: Philip Nienhuis ## Created: 2009-12-01 -## Latest update: 2009-12-11 +## Latest update: 2009-12-30 function [ xls, rstatus ] = oct2xls (obj, xls, wsh, topleft='A1') @@ -100,6 +96,539 @@ # elseif (strcmp'xls.xtype, '<whatever>')) # <Other Excel interfaces> + else + error (sprintf ("oct2xls: unknown Excel .xls interface - %s.", xls.xtype)); + endif endfunction + + +#=================================================================================== +## Copyright (C) 2007 by Michael Goffioul <michael.goffioul at swing.be> +## +## Adapted by P.R. Nienhuis <prnienhuis at users.sf.net> (2009) +## for more flexible writing into Excel worksheets through COM. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}) +## @deftypefnx {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}, @var{wsh}) +## @deftypefnx {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}, @var{wsh}, @var{top_left_cell}) +## Save matrix @var{obj} into worksheet @var{wsh} in Excel file pointed +## to in struct @var{xlsi}. All elements of @var{obj} are converted into +## Excel cells, starting at cell @var{top_left_cell}. Return argument +## @var{xlso} is @var{xlsi} with updated fields. +## +## oct2com2xls should not be invoked directly but rather through oct2xls. +## +## Excel invocations may be left running invisibly in case of COM errors. +## +## Example: +## +## @example +## xls = oct2com2xls (rand (10, 15), xls, 'Third_sheet', 'BF24'); +## @end example +## +## @seealso oct2xls, xls2oct, xlsopen, xlsclose, xlswrite, xlsread, xls2com2oct +## +## @end deftypefn + +## Author: Philip Nienhuis +## Rewritten: 2009-09-26 +## Last updated 2009-12-11 + +function [ xls, status ] = oct2com2xls (obj, xls, wsh, top_left_cell='A1') + + # define some constants not yet in __COM__.cc + xlWorksheet = -4167; # xlChart= 4; + + # scratch vars + status = 0; + + # Preliminary sanity checks + if (nargin < 2) error ("oct2com2xls needs a minimum of 2 arguments."); endif + if (nargin == 2) wsh = 1; endif + if (~iscell (obj)) error ("Cell array expected as input argument"); endif + if (~strcmp (tolower (xls.filename(end-3:end)), '.xls')) + error ("oct2com2xls can only write to Excel .xls files") + endif + if (isnumeric (wsh)) + if (wsh < 1) error ("Illegal worksheet number: %i\n", wsh); endif + elseif (size (wsh, 2) > 31) + error ("Illegal worksheet name - too long") + endif + if (isempty (obj)) + warning ("Request to write empty matrix."); + rstatus = 1; + return; + endif + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || ~strcmp (char (xls.xtype), 'COM'); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if test1 + error ("Invalid file pointer struct"); + endif + + # Cleanup NaNs. Start with backing up strings, empty & boolean cells, + # then set text cells to 0 + obj2 = cell (size (obj)); + txtptr = cellfun ('isclass', obj, 'char'); + if (any(txtptr)) obj2{txtptr} = obj{txtptr}; obj{txtptr} = 0; endif + eptr = cellfun ('isempty', obj); + if (any (eptr)) obj{eptr} = 0; endif + lptr = cellfun ("islogical" , obj); + if (any (lptr)) obj2{lptr} = obj{lptr}; obj{lptr} = 0; endif + + ptr = cellfun ("isnan", obj); + if (any (ptr)) obj{ptr} = []; endif + + # Restore text & booleans + if (any (txtptr)) obj{txtptr} = obj2{txtptr}; endif + if (any (lptr)) obj{lptr} = obj2{lptr}; endif + clear obj2 txtptr eptr lptr ptr; + + if (xls.changed < 2) + # Existing file. Some involved investigation is needed to preserve + # existing data that shouldn't be touched. + # + # See if desired *sheet* name exists. + old_sh = 0; + ws_cnt = xls.workbook.Sheets.count; + if (isnumeric (wsh)) + if (wsh <= ws_cnt) + # Here we check for sheet *position* in the sheet stack + # rather than a name like "Sheet<Number>" + old_sh = wsh; + else + # wsh > nr of sheets; proposed new sheet name. + # This sheet name can already exist to the left in the sheet stack! + shnm = sprintf ("Sheet%d", wsh); shnm1 = shnm; + endif + endif + if (~old_sh) + # Check if the requested (or proposed) sheet already exists + # COM objects are not OO (yet?), so we need a WHILE loop + ii = 1; jj = 1; + while ((ii <= ws_cnt) && ~old_sh) + # Get existing sheet names one by one + sh_name = xls.workbook.Sheets(ii).name; + if (~isnumeric (wsh) && strcmp (sh_name, wsh)) + # ...and check with requested sheet *name*... + old_sh = ii; + elseif (isnumeric (wsh) && strcmp (sh_name, shnm)) + # ... or proposed new sheet name (corresp. to requested sheet *number*) + shnm = [shnm "_"]; + ii = 0; # Also check if this new augmented sheet name exists... + if (strmatch (shnm1, sh_name)), jj++; endif + if (jj > 5) # ... but not unlimited times... + error (sprintf (" > 5 sheets named [_]Sheet%d already present!", wsh)); + endif + endif + ++ii; + endwhile + endif + + if (old_sh) + # Requested sheet exists. Check if it is a *work*sheet + if ~(xls.workbook.Sheets(old_sh).Type == xlWorksheet) + # Error as you can't write data to this + error (sprintf ("Existing sheet '%s' is not type worksheet.", wsh)); + else + # Simply point to the relevant sheet + sh = xls.workbook.Worksheets (old_sh); + endif + else + # Add a new worksheet. Earlier it was checked whether this is safe + sh = xls.workbook.Worksheets.Add (); + if (~isnumeric (wsh)) + sh.Name = wsh; + else + sh.Name = shnm; + printf ("Writing to worksheet %s\n", shnm); + endif + # Prepare to move new sheet to right of the worksheet stack anyway + ws_cnt = xls.workbook.Worksheets.count; # New count needed + # Find where Excel has left it. We have to, depends on Excel version :-( + ii = 1; + while ((ii < ws_cnt+1) && ~strcmp (sh.Name, xls.workbook.Worksheets(ii).Name) == 1) + ++ii; + endwhile + # Excel can't move it beyond the current last one, so we need a trick. + # First move it to just before the last one.... + xls.workbook.Worksheets(ii).Move (before = xls.workbook.Worksheets(ws_cnt)); + # ....then move the last one before the new sheet. + xls.workbook.Worksheets (ws_cnt).Move (before = xls.workbook.Worksheets(ws_cnt - 1)); + endif + xls.changed = 1; + + else + # The easy case: a new Excel file. + # Workbook was created in xlsopen. Write to first worksheet: + sh = xls.workbook.Worksheets (1); + # Delete empty non-used sheets, last one first + xls.app.Application.DisplayAlerts = 0; + xls.workbook.Worksheets(3).Delete(); xls.workbook.Worksheets(2).Delete(); + xls.app.Application.DisplayAlerts = 1; + + # Rename the sheet + if (isnumeric(wsh)) + sh.Name = sprintf("Sheet%i", wsh); + else + sh.Name = wsh; + endif + xls.changed = 2; + endif + + # MG's original part. + # Save object in Excel sheet, starting at cell top_left_cell + if (~isempty(obj)) + r = sh.Range (top_left_cell); + r = r.Resize (size (obj, 1), size (obj, 2)); + r.Value = obj; + delete (r); + endif + + # If we get here, all went OK + status = 1; + +endfunction + + +#==================================================================================== +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls ( @var{arr}, @var{xlsi}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{topleft}) +## +## Add data in 1D/2D CELL array @var{arr} into a range with upper left +## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel +## spreadsheet file pointed to in structure @var{range}. +## Return argument @var{xlso} equals supplied argument @var{xlsi} and is +## updated by oct2java2xls. +## +## oct2jpoi2xls should not be invoked directly but rather through oct2xls. +## +## Example: +## +## @example +## [xlso, status] = xls2jpoi2oct ('arr', xlsi, 'Third_sheet', 'AA31'); +## @end example +## +## @seealso oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite +## +## @end deftypefn + +## Author: Philip Nienhuis +## Created: 2009-11-26 +## Last updated 2009-12-11 + +function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, topleftcell="A1") + + persistent ctype; + if (isempty (ctype)) + # Get cell types. Beware as they start at 0 not 1 + ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); + ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); + ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); + ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); + ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BOOLEAN'); + ctype(6) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_ERROR'); + endif + + # scratch vars + rstatus = 0; changed = 1; + + # Preliminary sanity checks + if (isempty (obj)) + warning ("Request to write empty matrix."); + rstatus = 1; + return; + elseif (~iscell(obj)) + error ("First argument is not a cell array"); + endif + if (nargin < 2) error ("oct2jpoi2xls needs a minimum of 2 arguments."); endif + if (nargin == 2) wsh = 1; endif + if (~strmatch(tolower(xls.filename(end-4:end)), '.xls')) + error ("oct2jpoi2xls can only write to Excel .xls or .xlsx files") + endif + # Check if xls struct pointer seems valid + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || ~strcmp (char (xls.xtype), 'POI'); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if test1 error ("Invalid xls file struct"); endif + + # Check if requested worksheet exists in the file & if so, get pointer + nr_of_sheets = xls.workbook.getNumberOfSheets(); + if (isnumeric (wsh)) + if (wsh > nr_of_sheets) + # Watch out as a sheet called Sheet%d can exist with a lower index... + strng = sprintf ("Sheet%d", wsh); + ii = 1; + while (~isempty (xls.workbook.getSheet (strng)) && (ii < 5)) + strng = ['_' strng]; + ++ii; + endwhile + if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif + sh = xls.workbook.createSheet (strng); + else + sh = xls.workbook.getSheetAt (wsh - 1); # POI sheet count 0-based + endif + printf ("(Writing to worksheet %s)\n", sh.getSheetName()); + else + sh = xls.workbook.getSheet (wsh); + if (isempty(sh)) + # Sheet not found, just create it + sh = xls.workbook.createSheet (wsh); + xls.changed = 2; + endif + endif + + # Beware of strings variables interpreted as char arrays; change them to cell. + if (ischar (obj)) obj = {obj}; endif + + [topleft, nrows, ncols, trow, lcol] = parse_sp_range (topleftcell); + [nrows, ncols] = size (obj); + + # Prepare type array + typearr = ctype(4) * ones (nrows, ncols); # type "BLANK", provisionally + obj2 = cell (size (obj)); # Temporary storage for strings + + txtptr = cellfun ('isclass', obj, 'char'); # type "STRING" replaced by "NUMERIC" + obj2(txtptr) = obj(txtptr); obj(txtptr) = ctype(1); # Save strings in a safe place + + emptr = cellfun ("isempty", obj); + obj(emptr) = ctype(1); # Set empty cells to NUMERIC + + lptr = cellfun ("islogical" , obj); # Find logicals... + obj2(lptr) = obj(lptr); # .. and set them to BOOLEAN + + ptr = cellfun ("isnan", obj); # Find NaNs & set to BLANK + typearr(ptr) = ctype(4); typearr(~ptr) = ctype(1); # All other cells are now numeric + + obj(txtptr) = obj2(txtptr); # Copy strings back into place + obj(lptr) = obj2(lptr); + typearr(txtptr) = ctype(2); # ...and clean up + typearr(emptr) = ctype(4); + typearr(lptr) = ctype(5); # BOOLEAN + + # Create formula evaluator (needed to be able to write boolean values!) + frm_eval = xls.workbook.getCreationHelper().createFormulaEvaluator(); + + for ii=1:nrows + ll = ii + trow - 2; # Java POI's row count = 0-based + row = sh.getRow (ll); + if (isempty (row)) row = sh.createRow (ll); endif + for jj=1:ncols + kk = jj + lcol - 2; # POI's column count is also 0-based + cell = row.createCell (kk, typearr(ii,jj)); + if (typearr(ii, jj) == ctype(5)) + cell = row.createCell (kk, ctype(3)); + # Provisionally we make do with formulas evaluated immediately 8-Z + if obj{ii, jj} bool = '(1=1)'; else bool = '(1=0)'; endif + cell.setCellFormula (bool); frm_eval.evaluateInCell (cell); + elseif ~(typearr(ii, jj) == 3) + # Just put text or number in cell + cell.setCellValue (obj{ii, jj}); + endif + endfor + endfor + + rstatus = 1; + +endfunction + + +#==================================================================================== +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls ( @var{arr}, @var{xlsi}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{topleft}) +## +## Add data in 1D/2D CELL array @var{arr} into a range with upper left +## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel +## spreadsheet file pointed to in structure @var{range}. +## Return argument @var{xlso} equals supplied argument @var{xlsi} and is +## updated by oct2jxla2xls. +## +## oct2jxla2xls should not be invoked directly but rather through oct2xls. +## +## Example: +## +## @example +## [xlso, status] = oct2jxla2oct ('arr', xlsi, 'Third_sheet', 'AA31'); +## @end example +## +## @seealso oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite, xls2jxla2oct +## +## @end deftypefn + +## Author: Philip Nienhuis +## Created: 2009-12-04 +## Last updated 2009-12-11 + +function [ xls, rstatus ] = oct2jxla2xls (obj, xls, wsh, topleftcell="A1") + + persistent ctype; + if (isempty (ctype)) + ctype = [1, 2, 3, 4, 5]; + # Boolean, Number, String, NaN, Empty + endif + + # scratch vars + rstatus = 0; changed = 1; + + # Preliminary sanity checks + if (isempty (obj)) + warning ("Request to write empty matrix."); + rstatus = 1; + return; + elseif (~iscell(obj)) + error ("First argument is not a cell array"); + endif + if (nargin < 2) error ("oct2java2xls needs a minimum of 2 arguments."); endif + if (nargin == 2) wsh = 1; endif + if (~strmatch(tolower(xls.filename(end-4:end)), '.xls')) # FIXME for OOXML + error ("oct2java2xls can only write to Excel .xls files") + endif + + # Prepare workbook pointer if needed + if (xls.changed < 2) + # Create writable copy of workbook. If 2 a writable wb was made in xlsopen + xlsout = java_new ('java.io.File', xls.filename); + wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsout, xls.workbook); + xls.changed = 1; # For in case we come from reading the file + xls.workbook = wb; + else + wb = xls.workbook; + endif + + # Check if requested worksheet exists in the file & if so, get pointer + nr_of_sheets = xls.workbook.getNumberOfSheets(); # 1 based !! + if (isnumeric (wsh)) + if (wsh > nr_of_sheets) + # Watch out as a sheet called Sheet%d can exist with a lower index... + strng = sprintf ("Sheet%d", wsh); + ii = 1; + while (~isempty (wb.getSheet (strng)) && (ii < 5)) + strng = ['_' strng]; + ++ii; + endwhile + if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif + sh = wb.createSheet (strng, nr_of_sheets); ++nr_of_sheets; + else + sh = wb.getSheet (wsh - 1); # POI sheet count 0-based + endif + shnames = char(wb.getSheetNames ()); + printf ("(Writing to worksheet %s)\n", shnames {nr_of_sheets, 1}); + else + sh = wb.getSheet (wsh); + if (isempty(sh)) + # Sheet not found, just create it + sh = wb.createSheet (wsh, nr_of_sheets); + ++nr_of_sheets; + xls.changed = 2; + endif + endif + + # Beware of strings variables interpreted as char arrays; change them to cell. + if (ischar (obj)) obj = {obj}; endif + + [topleft, nrows, ncols, trow, lcol] = parse_sp_range (topleftcell); + [nrows, ncols] = size (obj); + + # Prepare type array to speed up writing + typearr = 5 * ones (nrows, ncols); # type "EMPTY", provisionally + obj2 = cell (size (obj)); # Temporary storage for strings + + txtptr = cellfun ('isclass', obj, 'char'); # type "STRING" replaced by "NUMERIC" + obj2(txtptr) = obj(txtptr); obj(txtptr) = 3; # Save strings in a safe place + + emptr = cellfun ("isempty", obj); + obj(emptr) = 5; # Set empty cells to NUMERIC + + lptr = cellfun ("islogical" , obj); # Find logicals... + obj2(lptr) = obj(lptr); # .. and set them to BOOLEAN + + ptr = cellfun ("isnan", obj); # Find NaNs & set to BLANK + typearr(ptr) = 4; typearr(~ptr) = 2; # All other cells are now numeric + + obj(txtptr) = obj2(txtptr); # Copy strings back into place + obj(lptr) = obj2(lptr); + typearr(txtptr) = 3; # ...and clean up + typearr(emptr) = 5; + typearr(lptr) = 1; # BOOLEAN + + # Write date to worksheet + for ii=1:nrows + ll = ii + trow - 2; # Java JExcelAPI's row count = 0-based + for jj=1:ncols + kk = jj + lcol - 2; # JExcelAPI's column count is also 0-based + switch typearr(ii, jj) + case 1 # Boolean + tmp = java_new ('jxl.write.Boolean', kk, ll, obj{ii, jj}); + sh.addCell (tmp); + case 2 # Numerical + tmp = java_new ('jxl.write.Number', kk, ll, obj{ii, jj}); + sh.addCell (tmp); + case 3 # String + tmp = java_new ('jxl.write.Label', kk, ll, obj{ii, jj}); + sh.addCell (tmp); + otherwise + # Just skip + endswitch + endfor + endfor + + rstatus = 1; + +endfunction + Modified: trunk/octave-forge/main/io/inst/xls2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2oct.m 2009-12-30 15:10:35 UTC (rev 6681) +++ trunk/octave-forge/main/io/inst/xls2oct.m 2009-12-30 15:50:56 UTC (rev 6682) @@ -22,10 +22,6 @@ ## Read data contained within range @var{range} from worksheet @var{wsh} ## in an Excel spreadsheet file pointed to in struct @var{xls}. ## -## xls2oct is a mere wrapper for interface-dependent scripts (e.g., -## xls2com2oct, xls2jpoi2oct and xls2jxla2oct) that do the actual -## reading. -## ## @var{wsh} is either numerical or text, in the latter case it is ## case-sensitive and it may be max. 31 characters long. ## Note that in case of a numerical @var{wsh} this number refers to the @@ -91,7 +87,7 @@ ## Author: Philip Nienhuis ## Created: 2009-10-16 -## Latest update: 2009-12-11 +## Latest update: 2009-12-30 function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh, datrange='') @@ -102,9 +98,512 @@ # Read xls file tru Java POI [rawarr, xls, rstatus] = xls2jpoi2oct (xls, wsh, datrange); elseif (strcmp (xls.xtype, 'JXL')) + # Read xls file tru JExcelAPI [rawarr, xls, rstatus] = xls2jxla2oct (xls, wsh, datrange); # elseif ---- <Other interfaces here> + + else + error (sprintf ("xls2oct: unknown Excel .xls interface - %s.", xls.xtype)); + endif endfunction + + +#==================================================================================== +## Copyright (C)2009 P.R. Nienhuis, <pr.nienhuis at hccnet.nl> +## +## based on mat2xls by Michael Goffioul (2007) <mic...@sw...> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2com2oct (@var{xls}) +## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2com2oct (@var{xls}, @var{wsh}) +## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2com2oct (@var{xls}, @var{wsh}, @var{range}) +## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel +## file pointed to in struct @var{xls} into the cell array @var{obj}. +## +## xls2com2oct should not be invoked directly but rather through xls2oct. +## +## Examples: +## +## @example +## [Arr, status, xls] = xls2com2oct (xls, 'Second_sheet', 'B3:AY41'); +## Arr = xls2com2oct (xls, 'Second_sheet'); +## @end example +## +## @seealso xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite +## +## @end deftypefn + +## Author: Philip Nienhuis +## Created: 2009-09-23 +## Last updated 2009-12-11 + +function [obj, xls, rstatus ] = xls2com2oct (xls, wsh, range) + + rstatus = 0; obj = {}; + + # Basic checks + if (nargin < 2) error ("xls2com2oct needs a minimum of 2 arguments."); endif + if (size (wsh, 2) > 31) + warning ("Worksheet name too long - truncated") + wsh = wsh(1:31); + endif + + nrows = 0; + emptyrange = 0; + if ((nargin == 2) || (isempty (range))) + emptyrange = 1; + else + # Extract top_left_cell from range + [topleft, nrows, ncols] = parse_sp_range (range); + endif; + + if (nrows >= 1 || emptyrange) + # Check the file handle struct + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || ~strcmp (char (xls.xtype), 'COM'); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if test1 + error ("Invalid file pointer struct"); + endif + app = xls.app; + wb = xls.workbook; + wb_cnt = wb.Worksheets.count; + old_sh = 0; + if (isnumeric (wsh)) + if (wsh < 1 || wsh > wb_cnt) + errstr = sprintf ("Worksheet number: %d out of range 1-%d", wsh, wb_cnt); + error (errstr) + return + else + old_sh = wsh; + endif + else + # Find worksheet number corresponding to name in wsh + wb_cnt = wb.Worksheets.count; + for ii =1:wb_cnt + sh_name = wb.Worksheets(ii).name; + if (strcmp (sh_name, wsh)) old_sh = ii; endif + endfor + if (~old_sh) + errstr = sprintf ("Worksheet name \"%s\" not present", wsh); + error (errstr) + else + wsh = old_sh; + endif + endif + + sh = wb.Worksheets (wsh); + + if (emptyrange) + allcells = sh.UsedRange; + obj = allcells.Value; + else + # Get object from Excel sheet, starting at cell top_left_cell + r = sh.Range (topleft); + r = r.Resize (nrows, ncols); + obj = r.Value; + delete (r); + endif; + # Take care of actual singe cell range + if (isnumeric (obj) || ischar (obj)) + obj = {obj}; + endif + # If we get here, all seems to have gone OK + rstatus = 1; + + else + error ("No data read from Excel file"); + rstatus = 0; + + endif + +endfunction + + +#================================================================================== +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jpoi2oct (@var{xls}) +## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jpoi2oct (@var{xls}, @var{wsh}) +## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jpoi2oct (@var{xls}, @var{wsh}, @var{range}) +## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel +## file pointed to in struct @var{xls} into the cell array @var{obj}. +## @var{range} can be a range or just the top left cell of the range. +## +## xls2jpoi2oct should not be invoked directly but rather through xls2oct. +## +## Examples: +## +## @example +## [Arr, status, xls] = xls2jpoi2oct (xls, 'Second_sheet', 'B3:AY41'); +## B = xls2jpoi2oct (xls, 'Second_sheet', 'B3'); +## @end example +## +## @seealso xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite, oct2jpoi2xls +## +## @end deftypefn + +## Author: Philip Nienhuis +## Created: 2009-11-23 +## Last updated 2009-12-11 + +function [ rawarr, xls, status ] = xls2jpoi2oct (xls, wsh, cellrange=[]) + + persistent ctype; + if (isempty (ctype)) + # Get enumrated cell types. Beware as they start at 0 not 1 + ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); + ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); + ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); + ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); + ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BOOLEAN'); + ctype(6) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_ERROR'); + endif + + status = 0; jerror = 0; + + # Check if xls struct pointer seems valid + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || ~strcmp (char (xls.xtype), 'POI'); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if test1 + error ("Invalid xls file struct"); + else + wb = xls.workbook; + endif + + # Check if requested worksheet exists in the file & if so, get pointer + nr_of_sheets = wb.getNumberOfSheets (); + if (isnumeric (wsh)) + if (wsh > nr_of_sheets), error (sprintf ("Worksheet # %d bigger than nr. of sheets (%d) in file %s", wsh, nr_of_sheets, xls.filename)); endif + sh = wb.getSheetAt (wsh - 1); # POI sheet count 0-based + printf ("(Reading from worksheet %s)\n", sh.getSheetName ()); + else + sh = wb.getSheet (wsh); + if (isempty (sh)), error (sprintf("Worksheet %s not found in file %s", wsh, xls.filename)); endif + end + + # Check ranges + firstrow = sh.getFirstRowNum (); + lastrow = sh.getLastRowNum (); + if (isempty (cellrange)) + # Get used range by searching (slow...). Beware, it can be bit unreliable + lcol = 65535; # FIXME for OOXML + rcol = 0; + for ii=firstrow:lastrow + irow = sh.getRow (ii); + if (~isempty (irow)) + scol = (irow.getFirstCellNum).intValue (); + lcol = min (lcol, scol); + ecol = (irow.getLastCellNum).intValue () - 1; + rcol = max (rcol, ecol); + # Keep track of lowermost non-empty row as getLastRowNum() is unreliable + if ~(irow.getCell(scol).getCellType () == ctype(4) && irow.getCell(ecol).getCellType () == ctype(4)) + botrow = ii; + endif + endif + endfor + lastrow = min (lastrow, botrow); + nrows = lastrow - firstrow + 1; + ncols = rcol - lcol + 1; + else + # Translate range to HSSF POI row & column numbers + [topleft, nrows, ncols, trow, lcol] = parse_sp_range (cellrange); + firstrow = max (trow-1, firstrow); + lastrow = firstrow + nrows - 1; + lcol = lcol -1; # POI rows & column # 0-based + endif + + # Create formula evaluator (needed to infer proper cell type into rawarr) + # NB formula evaluation is not very reliable in POI + frm_eval = wb.getCreationHelper().createFormulaEvaluator (); + + #wb.clearAllCachedResultsValues(); # does not work + + # Read contents into rawarr + rawarr = cell (nrows, ncols); # create placeholder + for ii = firstrow:lastrow + irow = sh.getRow (ii); + if ~isempty (irow) + scol = (irow.getFirstCellNum).intValue (); + ecol = (irow.getLastCellNum).intValue () - 1; + for jj = max (scol, lcol) : min (lcol+ncols-1, ecol) + cell = irow.getCell (jj); + if ~isempty (cell) + # Process cell contents + type_of_cell = cell.getCellType (); + if (type_of_cell == ctype(3)) # Formula + try + cell = frm_eval.evaluate (cell); + type_of_cell = cell.getCellType(); + switch type_of_cell + case ctype (1) # Numeric + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumberValue (); + case ctype(2) # String + rawarr (ii+1-firstrow, jj+1-lcol) = char (cell.getStringValue ()); + case ctype (5) # Boolean + rawarr (ii+1-firstrow, jj+1-lcol) = cell.BooleanValue (); + otherwise + # Nothing to do here + endswitch + catch + # In case of errors we copy the formula as text into rawarr + rawarr (ii+1-firstrow, jj+1-lcol) = ["=" cell.getCellFormula]; + type_of_cell = ctype (4); + if (~jerror) + warning ("Java errors in worksheet formulas (converted to string)"); + endif + ++jerror; # We only need one warning + end_try_catch + else + if (~isnumeric (type_of_cell)) type_of_cell = 4; endif + switch type_of_cell + case ctype(1) # 0 Numeric + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); + case ctype(2) # 1 String + rawarr (ii+1-firstrow, jj+1-lcol) = char (cell.getRichStringCellValue ()); +# case ctype(3) # 2 Formula (if still at all needed). +# try # Provisionally we simply take the result +# rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); +# catch +# # In case of errors we copy the formula as text into rawarr +# rawarr (ii+1-firstrow, jj+1-lcol) = ["=" cell.getCellFormula]; +# type_of_cell = ctype (4); +# if (~jerror) +# warning ("Java errors in worksheet formulas (converted to string)"); +# endif +# ++jerror; +# end + case ctype(4) # 3 Blank + # Blank; ignore until further notice + case ctype(5) # 4 Boolean + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getBooleanCellValue (); + otherwise # 5 Error + # Error; ignore + endswitch + endif + endif + endfor + endif + endfor + + if (jerror > 0) printf ("%d Java formula evalation errors\n", jerror); endif + + # Crop rawarr from empty outer rows & columns like Excel does + emptr = cellfun('isempty', rawarr); + irowt = 1; + while (all (emptr(irowt, :))), irowt++; endwhile + irowb = nrows; + while (all (emptr(irowb, :))), irowb--; endwhile + icoll = 1; + while (all (emptr(:, icoll))), icoll++; endwhile + icolr = ncols; + while (all (emptr(:, icolr))), icolr--; endwhile + # Crop textarray + rawarr = rawarr(irowt:irowb, icoll:icolr); + status = 1; + + xls.limits = [lcol+icoll, lcol+icolr; firstrow+irowt, firstrow+irowb]; + +endfunction + + +#================================================================================== +## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jxla2oct (@var{xls}) +## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jxla2oct (@var{xls}, @var{wsh}) +## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jxla2oct (@var{xls}, @var{wsh}, @var{range}) +## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel +## file pointed to in struct @var{xls} into the cell array @var{obj}. +## @var{range} can be a range or just the top left cell of the range. +## +## xls2jxla2oct should not be invoked directly but rather through xls2oct. +## +## Examples: +## +## @example +## [Arr, status, xls] = xls2jxla2oct (xls, 'Second_sheet', 'B3:AY41'); +## B = xls2jxla2oct (xls, 'Second_sheet'); +## @end example +## +## @seealso xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite, oct2jxla2xls +## +## @end deftypefn + +## Author: Philip Nienhuis +## Created: 2009-12-04 +## Last updated 2009-12-11 + +function [ rawarr, xls, status ] = xls2jxla2oct (xls, wsh, cellrange=[]) + + persistent ctype; + if (isempty (ctype)) + ctype = cell (11, 1); + # Get enumerated cell types. Beware as they start at 0 not 1 + ctype(1,1) = (java_get ('jxl.CellType', 'BOOLEAN')).toString (); + ctype(2,1) = (java_get ('jxl.CellType', 'BOOLEAN_FORMULA')).toString (); + ctype(3,1) = (java_get ('jxl.CellType', 'DATE')).toString (); + ctype(4,1) = (java_get ('jxl.CellType', 'DATE_FORMULA')).toString (); + ctype(5,1) = (java_get ('jxl.CellType', 'EMPTY')).toString (); + ctype(6,1) = (java_get ('jxl.CellType', 'ERROR')).toString (); + ctype(7,1) = (java_get ('jxl.CellType', 'FORMULA_ERROR')).toString (); + ctype(8,1) = (java_get ('jxl.CellType', 'NUMBER')).toString (); + ctype(9,1) = (java_get ('jxl.CellType', 'LABEL')).toString (); + ctype(10,1) = (java_get ('jxl.CellType', 'NUMBER_FORMULA')).toString (); + ctype(11,1) = (java_get ('jxl.CellType', 'STRING_FORMULA')).toString (); + endif + + status = 0; + + # Check if xls struct pointer seems valid + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || ~strcmp (char (xls.xtype), 'JXL'); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if test1 + error ("Invalid xls file struct"); + else + wb = xls.workbook; + endif + + # Check if requested worksheet exists in the file & if so, get pointer + nr_of_sheets = wb.getNumberOfSheets (); + shnames = char (wb.getSheetNames ()); + if (isnumeric (wsh)) + if (wsh > nr_of_sheets), error (sprintf ("Worksheet # %d bigger than nr. of sheets (%d) in file %s", wsh, nr_of_sheets, xls.filename)); endif + sh = wb.getSheet (wsh - 1); # POI sheet count 0-based + printf ("(Reading from worksheet %s)\n", shnames {wsh}); + else + sh = wb.getSheet (wsh); + if (isempty (sh)), error (sprintf ("Worksheet %s not found in file %s", wsh, xls.filename)); endif + end + + # Check ranges + firstrow = 0; + lcol = 0; + + if (isempty (cellrange)) + nrows = sh.getRows (); + lastrow = nrows - 1; + ncols = sh.getColumns (); + trow = firstrow; + rcol = ncols - 1; + else + # Translate range to HSSF POI row & column numbers + [dummy, nrows, ncols, trow, lcol] = parse_sp_range (cellrange); + firstrow = max (trow-1, firstrow); + lastrow = firstrow + nrows - 1; + lcol = lcol - 1; # POI rows & column # 0-based + endif + + # Read contents into rawarr + rawarr = cell (nrows, ncols); # create placeholder + for jj = lcol : lcol+ncols-1 + for ii = firstrow:lastrow + cell = sh.getCell (jj, ii); + type_of_cell = char (cell.getType ()); + switch type_of_cell + case ctype {1, 1} + # Boolean + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); + case ctype {2, 1} + # Boolean formula + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); + case ctype {3, 1} + # Date + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); + case ctype {4, 1} + # Date Formula + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); + case ctype {5, 1} + # Empty. Nothing to do here + case ctype {6, 1} + # Error. Nothing to do here + case ctype {7, 1} + # Formula Error. Nothing to do here + case ctype {8, 1} + # Number + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); + case ctype {9, 1} + # String + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getString (); + case ctype {10, 1} + # NumericalFormula + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); + case ctype {11, 1} + # String Formula + rawarr (ii+1-firstrow, jj+1-lcol) = cell.getString (); + endswitch + endfor + endfor + + # Crop rawarr from empty outer rows & columns just like Excel does + emptr = cellfun('isempty', rawarr); + irowt = 1; + while (all (emptr(irowt, :))), irowt++; endwhile + irowb = nrows; + while (all (emptr(irowb, :))), irowb--; endwhile + icoll = 1; + while (all (emptr(:, icoll))), icoll++; endwhile + icolr = ncols; + while (all (emptr(:, icolr))), icolr--; endwhile + # Crop textarray + rawarr = rawarr(irowt:irowb, icoll:icolr); + status = 1; + + xls.limits = [lcol+icoll, lcol+icolr; firstrow+irowt, firstrow+irowb]; + +endfunction + Modified: trunk/octave-forge/main/io/inst/xlsfinfo.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsfinfo.m 2009-12-30 15:10:35 UTC (rev 6681) +++ trunk/octave-forge/main/io/inst/xlsfinfo.m 2009-12-30 15:50:56 UTC (rev 6682) @@ -54,7 +54,7 @@ ## Author: Philip Nienhuis <prn...@us...> ## Created: 2009-10-27 -## Latest update (Java / POI / xlsopen): 2009-12-11 +## Latest update (Java / POI / xlsopen): 2009-12-30 function [ filetype, sh_names, fformat ] = xlsfinfo (filename) @@ -81,7 +81,7 @@ endfor if (ws_cnt > 0 || ch_cnt > 0) fformat = "xlWorkbookNormal"; endif - elseif (strcmp(xls.xtype, 'POI')) + elseif (strcmp (xls.xtype, 'POI')) sh_cnt = xls.workbook.getNumberOfSheets(); sh_names = cell (sh_cnt, 2); for ii=1:sh_cnt @@ -92,7 +92,7 @@ endfor if (sh_cnt > 0) fformat = "xlWorkbookNormal"; endif - elseif (strcmp(xls.xtype, 'JXL')) + elseif (strcmp (xls.xtype, 'JXL')) sh_cnt = xls.workbook.getNumberOfSheets (); sh_names = cell (sh_cnt, 2); sh_names(:,1) = char (xls.workbook.getSheetNames ()); @@ -103,6 +103,9 @@ # elseif <Other Excel interfaces below> + else + error (sprintf ("xlsfinfo: unknown Excel .xls interface - %s.", xls.xtype)); + endif xlsclose (xls); Modified: trunk/octave-forge/main/io/inst/xlsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsopen.m 2009-12-30 15:10:35 UTC (rev 6681) +++ trunk/octave-forge/main/io/inst/xlsopen.m 2009-12-30 15:50:56 UTC (rev 6682) @@ -29,10 +29,11 @@ ## are referred to as COM, POI and JXL, resp., and are preferred in that ## order by default (depending on their presence). ## -## @var{filename} must be a valid .xls Excel file name. If @var{filename} -## does not contain any directory path, the file is saved in the current -## directory. (Support for .xlsx (Excel 2007 OOXML) will be added later, based -## on Java and Apache POI.) +## @var{filename} should be a valid .xls Excel file name; but if you use the +## COM interface you can specify any extension that your installed Excel version +## can read AND write. If @var{filename} does not contain any directory path, +## the file is saved in the current directory. (Support for .xlsx (Excel 2007 +## OOXML) based on Java and Apache POI will be added later). ## ## If @var{readwrite} is set to 0 (default value) or omitted, the Excel file ## is opened for reading. If @var{readwrite} is set to True or 1, an Excel @@ -61,7 +62,7 @@ ## Author: Philip Nienhuis ## Created: 2009-11-29 -## Last updated 2009-12-07 +## Last updated 2009-12-30 function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[]) @@ -121,18 +122,8 @@ xlsinterfaces = getxlsinterfaces (xlsinterfaces); -# Supported interfaces determined; now check Excel file type. - +# Supported interfaces determined; Excel file type check moved to seperate interfaces. chk1 = strcmp (tolower (filename(end-3:end)), '.xls'); -# chk2 = strcmp (tolower (filename(end-4:end)), '.xlsx'); -# if (xlsinterfaces.POI) -# if ~(chk1 || chk2) -# error ("xlsopen: only .xls or .xlsx files can be processed reliably"); -# end -# elseif (~chk1) - if (~chk1) - error ("Currently xls2oct can only read reliably from .xls files") - endif xls = struct ("xtype", 'NONE', "app", [], "filename", [], "workbook", [], "changed", 0, "limits", []); @@ -154,6 +145,9 @@ xls.filename = filename; elseif (xlsinterfaces.JXL) + if (~chk1) + error ("Currently xls2oct / JXL can only read reliably from .xls files") + endif xls.xtype = 'JXL'; xlsin = java_new ('java.io.File', filename); if (xwrite == 2) @@ -168,6 +162,9 @@ xls.filename = filename; elseif (xlsinterfaces.POI) + if (~chk1) + error ("Currently xls2oct / POI can only read reliably from .xls files") + endif xls.xtype = 'POI'; # Get handle to workbook if (xwrite == 2) @@ -252,7 +249,7 @@ ## Author: Philip Nienhuis ## Created: 2009-11-29 -## Last updated 2009-12-11 +## Last updated 2009-12-27 function [xlsinterfaces] = getxlsinterfaces (xlsinterfaces) @@ -303,7 +300,7 @@ warning ("\n Java support OK but not all required classes (.jar) in classpath"); endif catch - # COM non-existent + # POI non-existent end_try_catch endif @@ -330,7 +327,7 @@ warning ("\nJava support OK but required classes (.jar) not all in classpath"); endif catch - # COM non-existent + # JXL non-existent end_try_catch endif Modified: trunk/octave-forge/main/io/inst/xlsread.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsread.m 2009-12-30 15:10:35 UTC (rev 6681) +++ trunk/octave-forge/main/io/inst/xlsread.m 2009-12-30 15:50:56 UTC (rev 6682) @@ -102,10 +102,9 @@ ## ## @example ## [An, Tn, Ra, limits] = xlsread ('Sales2009.xls', 'Third_sheet'); -## (which returns the numeric contents in range C3:AB40 in worksheet -## 'Third_sheet' in file test4.xls into array An, the text data into -## array Tn, the raw cell data into cell array Ra and the ranges from -## where the actual data came in limits) +## (which returns all data in worksheet 'Third_sheet' in file test4.xls +## into array An, the text data into array Tn, the raw cell data into +## cell array Ra and the ranges from where the actual data came in limits) ## @end example ## ## @seealso xlswrite, xlsopen, xls2oct, xlsclose, xlsfinfo, oct2xls @@ -114,7 +113,7 @@ ## Author: Philip Nienhuis ## Created: 2009-10-16 -## Latest update: 2009-12-11 +## Latest update: 2009-12-29 function [ numarr, txtarr, rawarr, lims ] = xlsread (fn, wsh, datrange, reqintf=[]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2009-12-30 16:04:56
|
Revision: 6684 http://octave.svn.sourceforge.net/octave/?rev=6684&view=rev Author: prnienhuis Date: 2009-12-30 16:04:47 +0000 (Wed, 30 Dec 2009) Log Message: ----------- No more needed; they are now folded into xls2oct and oct2xls. These scripts were not meant to be invoked directly anyway. Removed Paths: ------------- trunk/octave-forge/main/io/inst/oct2com2xls.m trunk/octave-forge/main/io/inst/oct2jpoi2xls.m trunk/octave-forge/main/io/inst/oct2jxla2xls.m trunk/octave-forge/main/io/inst/xls2com2oct.m trunk/octave-forge/main/io/inst/xls2jpoi2oct.m trunk/octave-forge/main/io/inst/xls2jxla2oct.m Deleted: trunk/octave-forge/main/io/inst/oct2com2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2com2xls.m 2009-12-30 15:55:45 UTC (rev 6683) +++ trunk/octave-forge/main/io/inst/oct2com2xls.m 2009-12-30 16:04:47 UTC (rev 6684) @@ -1,202 +0,0 @@ -## Copyright (C) 2007 by Michael Goffioul <michael.goffioul at swing.be> -## -## Adapted by P.R. Nienhuis <prnienhuis at users.sf.net> (2009) -## for more flexible writing into Excel worksheets through COM. -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; If not, see <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}) -## @deftypefnx {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}, @var{wsh}) -## @deftypefnx {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}, @var{wsh}, @var{top_left_cell}) -## Save matrix @var{obj} into worksheet @var{wsh} in Excel file pointed -## to in struct @var{xlsi}. All elements of @var{obj} are converted into -## Excel cells, starting at cell @var{top_left_cell}. Return argument -## @var{xlso} is @var{xlsi} with updated fields. -## -## oct2com2xls should not be invoked directly but rather through oct2xls. -## -## Excel invocations may be left running invisibly in case of COM errors. -## -## Example: -## -## @example -## xls = oct2com2xls (rand (10, 15), xls, 'Third_sheet', 'BF24'); -## @end example -## -## @seealso oct2xls, xls2oct, xlsopen, xlsclose, xlswrite, xlsread, xls2com2oct -## -## @end deftypefn - -## Author: Philip Nienhuis -## Rewritten: 2009-09-26 -## Last updated 2009-12-11 - -function [ xls, status ] = oct2com2xls (obj, xls, wsh, top_left_cell='A1') - - # define some constants not yet in __COM__.cc - xlWorksheet = -4167; # xlChart= 4; - - # scratch vars - status = 0; - - # Preliminary sanity checks - if (nargin < 2) error ("oct2com2xls needs a minimum of 2 arguments."); endif - if (nargin == 2) wsh = 1; endif - if (~iscell (obj)) error ("Cell array expected as input argument"); endif - if (~strcmp (tolower (xls.filename(end-3:end)), '.xls')) - error ("oct2com2xls can only write to Excel .xls files") - endif - if (isnumeric (wsh)) - if (wsh < 1) error ("Illegal worksheet number: %i\n", wsh); endif - elseif (size (wsh, 2) > 31) - error ("Illegal worksheet name - too long") - endif - if (isempty (obj)) - warning ("Request to write empty matrix."); - rstatus = 1; - return; - endif - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'COM'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid file pointer struct"); - endif - - # Cleanup NaNs. Start with backing up strings, empty & boolean cells, - # then set text cells to 0 - obj2 = cell (size (obj)); - txtptr = cellfun ('isclass', obj, 'char'); - if (any(txtptr)) obj2{txtptr} = obj{txtptr}; obj{txtptr} = 0; endif - eptr = cellfun ('isempty', obj); - if (any (eptr)) obj{eptr} = 0; endif - lptr = cellfun ("islogical" , obj); - if (any (lptr)) obj2{lptr} = obj{lptr}; obj{lptr} = 0; endif - - ptr = cellfun ("isnan", obj); - if (any (ptr)) obj{ptr} = []; endif - - # Restore text & booleans - if (any (txtptr)) obj{txtptr} = obj2{txtptr}; endif - if (any (lptr)) obj{lptr} = obj2{lptr}; endif - clear obj2 txtptr eptr lptr ptr; - - if (xls.changed < 2) - # Existing file. Some involved investigation is needed to preserve - # existing data that shouldn't be touched. - # - # See if desired *sheet* name exists. - old_sh = 0; - ws_cnt = xls.workbook.Sheets.count; - if (isnumeric (wsh)) - if (wsh <= ws_cnt) - # Here we check for sheet *position* in the sheet stack - # rather than a name like "Sheet<Number>" - old_sh = wsh; - else - # wsh > nr of sheets; proposed new sheet name. - # This sheet name can already exist to the left in the sheet stack! - shnm = sprintf ("Sheet%d", wsh); shnm1 = shnm; - endif - endif - if (~old_sh) - # Check if the requested (or proposed) sheet already exists - # COM objects are not OO (yet?), so we need a WHILE loop - ii = 1; jj = 1; - while ((ii <= ws_cnt) && ~old_sh) - # Get existing sheet names one by one - sh_name = xls.workbook.Sheets(ii).name; - if (~isnumeric (wsh) && strcmp (sh_name, wsh)) - # ...and check with requested sheet *name*... - old_sh = ii; - elseif (isnumeric (wsh) && strcmp (sh_name, shnm)) - # ... or proposed new sheet name (corresp. to requested sheet *number*) - shnm = [shnm "_"]; - ii = 0; # Also check if this new augmented sheet name exists... - if (strmatch (shnm1, sh_name)), jj++; endif - if (jj > 5) # ... but not unlimited times... - error (sprintf (" > 5 sheets named [_]Sheet%d already present!", wsh)); - endif - endif - ++ii; - endwhile - endif - - if (old_sh) - # Requested sheet exists. Check if it is a *work*sheet - if ~(xls.workbook.Sheets(old_sh).Type == xlWorksheet) - # Error as you can't write data to this - error (sprintf ("Existing sheet '%s' is not type worksheet.", wsh)); - else - # Simply point to the relevant sheet - sh = xls.workbook.Worksheets (old_sh); - endif - else - # Add a new worksheet. Earlier it was checked whether this is safe - sh = xls.workbook.Worksheets.Add (); - if (~isnumeric (wsh)) - sh.Name = wsh; - else - sh.Name = shnm; - printf ("Writing to worksheet %s\n", shnm); - endif - # Prepare to move new sheet to right of the worksheet stack anyway - ws_cnt = xls.workbook.Worksheets.count; # New count needed - # Find where Excel has left it. We have to, depends on Excel version :-( - ii = 1; - while ((ii < ws_cnt+1) && ~strcmp (sh.Name, xls.workbook.Worksheets(ii).Name) == 1) - ++ii; - endwhile - # Excel can't move it beyond the current last one, so we need a trick. - # First move it to just before the last one.... - xls.workbook.Worksheets(ii).Move (before = xls.workbook.Worksheets(ws_cnt)); - # ....then move the last one before the new sheet. - xls.workbook.Worksheets (ws_cnt).Move (before = xls.workbook.Worksheets(ws_cnt - 1)); - endif - xls.changed = 1; - - else - # The easy case: a new Excel file. - # Workbook was created in xlsopen. Write to first worksheet: - sh = xls.workbook.Worksheets (1); - # Delete empty non-used sheets, last one first - xls.app.Application.DisplayAlerts = 0; - xls.workbook.Worksheets(3).Delete(); xls.workbook.Worksheets(2).Delete(); - xls.app.Application.DisplayAlerts = 1; - - # Rename the sheet - if (isnumeric(wsh)) - sh.Name = sprintf("Sheet%i", wsh); - else - sh.Name = wsh; - endif - xls.changed = 2; - endif - - # MG's original part. - # Save object in Excel sheet, starting at cell top_left_cell - if (~isempty(obj)) - r = sh.Range (top_left_cell); - r = r.Resize (size (obj, 1), size (obj, 2)); - r.Value = obj; - delete (r); - endif - - # If we get here, all went OK - status = 1; - -endfunction \ No newline at end of file Deleted: trunk/octave-forge/main/io/inst/oct2jpoi2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2jpoi2xls.m 2009-12-30 15:55:45 UTC (rev 6683) +++ trunk/octave-forge/main/io/inst/oct2jpoi2xls.m 2009-12-30 16:04:47 UTC (rev 6684) @@ -1,159 +0,0 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls ( @var{arr}, @var{xlsi}) -## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}) -## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{topleft}) -## -## Add data in 1D/2D CELL array @var{arr} into a range with upper left -## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel -## spreadsheet file pointed to in structure @var{range}. -## Return argument @var{xlso} equals supplied argument @var{xlsi} and is -## updated by oct2java2xls. -## -## oct2jpoi2xls should not be invoked directly but rather through oct2xls. -## -## Example: -## -## @example -## [xlso, status] = xls2jpoi2oct ('arr', xlsi, 'Third_sheet', 'AA31'); -## @end example -## -## @seealso oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite -## -## @end deftypefn - -## Author: Philip Nienhuis -## Created: 2009-11-26 -## Last updated 2009-12-11 - -function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, topleftcell="A1") - - persistent ctype; - if (isempty (ctype)) - # Get cell types. Beware as they start at 0 not 1 - ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); - ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); - ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); - ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); - ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BOOLEAN'); - ctype(6) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_ERROR'); - endif - - # scratch vars - rstatus = 0; changed = 1; - - # Preliminary sanity checks - if (isempty (obj)) - warning ("Request to write empty matrix."); - rstatus = 1; - return; - elseif (~iscell(obj)) - error ("First argument is not a cell array"); - endif - if (nargin < 2) error ("oct2jpoi2xls needs a minimum of 2 arguments."); endif - if (nargin == 2) wsh = 1; endif - if (~strmatch(tolower(xls.filename(end-4:end)), '.xls')) - error ("oct2jpoi2xls can only write to Excel .xls or .xlsx files") - endif - # Check if xls struct pointer seems valid - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'POI'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 error ("Invalid xls file struct"); endif - - # Check if requested worksheet exists in the file & if so, get pointer - nr_of_sheets = xls.workbook.getNumberOfSheets(); - if (isnumeric (wsh)) - if (wsh > nr_of_sheets) - # Watch out as a sheet called Sheet%d can exist with a lower index... - strng = sprintf ("Sheet%d", wsh); - ii = 1; - while (~isempty (xls.workbook.getSheet (strng)) && (ii < 5)) - strng = ['_' strng]; - ++ii; - endwhile - if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif - sh = xls.workbook.createSheet (strng); - else - sh = xls.workbook.getSheetAt (wsh - 1); # POI sheet count 0-based - endif - printf ("(Writing to worksheet %s)\n", sh.getSheetName()); - else - sh = xls.workbook.getSheet (wsh); - if (isempty(sh)) - # Sheet not found, just create it - sh = xls.workbook.createSheet (wsh); - xls.changed = 2; - endif - endif - - # Beware of strings variables interpreted as char arrays; change them to cell. - if (ischar (obj)) obj = {obj}; endif - - [topleft, nrows, ncols, trow, lcol] = parse_sp_range (topleftcell); - [nrows, ncols] = size (obj); - - # Prepare type array - typearr = ctype(4) * ones (nrows, ncols); # type "BLANK", provisionally - obj2 = cell (size (obj)); # Temporary storage for strings - - txtptr = cellfun ('isclass', obj, 'char'); # type "STRING" replaced by "NUMERIC" - obj2(txtptr) = obj(txtptr); obj(txtptr) = ctype(1); # Save strings in a safe place - - emptr = cellfun ("isempty", obj); - obj(emptr) = ctype(1); # Set empty cells to NUMERIC - - lptr = cellfun ("islogical" , obj); # Find logicals... - obj2(lptr) = obj(lptr); # .. and set them to BOOLEAN - - ptr = cellfun ("isnan", obj); # Find NaNs & set to BLANK - typearr(ptr) = ctype(4); typearr(~ptr) = ctype(1); # All other cells are now numeric - - obj(txtptr) = obj2(txtptr); # Copy strings back into place - obj(lptr) = obj2(lptr); - typearr(txtptr) = ctype(2); # ...and clean up - typearr(emptr) = ctype(4); - typearr(lptr) = ctype(5); # BOOLEAN - - # Create formula evaluator (needed to be able to write boolean values!) - frm_eval = xls.workbook.getCreationHelper().createFormulaEvaluator(); - - for ii=1:nrows - ll = ii + trow - 2; # Java POI's row count = 0-based - row = sh.getRow (ll); - if (isempty (row)) row = sh.createRow (ll); endif - for jj=1:ncols - kk = jj + lcol - 2; # POI's column count is also 0-based - cell = row.createCell (kk, typearr(ii,jj)); - if (typearr(ii, jj) == ctype(5)) - cell = row.createCell (kk, ctype(3)); - # Provisionally we make do with formulas evaluated immediately 8-Z - if obj{ii, jj} bool = '(1=1)'; else bool = '(1=0)'; endif - cell.setCellFormula (bool); frm_eval.evaluateInCell (cell); - elseif ~(typearr(ii, jj) == 3) - # Just put text or number in cell - cell.setCellValue (obj{ii, jj}); - endif - endfor - endfor - - rstatus = 1; - -endfunction Deleted: trunk/octave-forge/main/io/inst/oct2jxla2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2jxla2xls.m 2009-12-30 15:55:45 UTC (rev 6683) +++ trunk/octave-forge/main/io/inst/oct2jxla2xls.m 2009-12-30 16:04:47 UTC (rev 6684) @@ -1,159 +0,0 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls ( @var{arr}, @var{xlsi}) -## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}) -## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{topleft}) -## -## Add data in 1D/2D CELL array @var{arr} into a range with upper left -## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel -## spreadsheet file pointed to in structure @var{range}. -## Return argument @var{xlso} equals supplied argument @var{xlsi} and is -## updated by oct2jxla2xls. -## -## oct2jxla2xls should not be invoked directly but rather through oct2xls. -## -## Example: -## -## @example -## [xlso, status] = oct2jxla2oct ('arr', xlsi, 'Third_sheet', 'AA31'); -## @end example -## -## @seealso oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite, xls2jxla2oct -## -## @end deftypefn - -## Author: Philip Nienhuis -## Created: 2009-12-04 -## Last updated 2009-12-11 - -function [ xls, rstatus ] = oct2jxla2xls (obj, xls, wsh, topleftcell="A1") - - persistent ctype; - if (isempty (ctype)) - ctype = [1, 2, 3, 4, 5]; - # Boolean, Number, String, NaN, Empty - endif - - # scratch vars - rstatus = 0; changed = 1; - - # Preliminary sanity checks - if (isempty (obj)) - warning ("Request to write empty matrix."); - rstatus = 1; - return; - elseif (~iscell(obj)) - error ("First argument is not a cell array"); - endif - if (nargin < 2) error ("oct2java2xls needs a minimum of 2 arguments."); endif - if (nargin == 2) wsh = 1; endif - if (~strmatch(tolower(xls.filename(end-4:end)), '.xls')) # FIXME for OOXML - error ("oct2java2xls can only write to Excel .xls files") - endif - - # Prepare workbook pointer if needed - if (xls.changed < 2) - # Create writable copy of workbook. If 2 a writable wb was made in xlsopen - xlsout = java_new ('java.io.File', xls.filename); - wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsout, xls.workbook); - xls.changed = 1; # For in case we come from reading the file - xls.workbook = wb; - else - wb = xls.workbook; - endif - - # Check if requested worksheet exists in the file & if so, get pointer - nr_of_sheets = xls.workbook.getNumberOfSheets(); # 1 based !! - if (isnumeric (wsh)) - if (wsh > nr_of_sheets) - # Watch out as a sheet called Sheet%d can exist with a lower index... - strng = sprintf ("Sheet%d", wsh); - ii = 1; - while (~isempty (wb.getSheet (strng)) && (ii < 5)) - strng = ['_' strng]; - ++ii; - endwhile - if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif - sh = wb.createSheet (strng, nr_of_sheets); ++nr_of_sheets; - else - sh = wb.getSheet (wsh - 1); # POI sheet count 0-based - endif - shnames = char(wb.getSheetNames ()); - printf ("(Writing to worksheet %s)\n", shnames {nr_of_sheets, 1}); - else - sh = wb.getSheet (wsh); - if (isempty(sh)) - # Sheet not found, just create it - sh = wb.createSheet (wsh, nr_of_sheets); - ++nr_of_sheets; - xls.changed = 2; - endif - endif - - # Beware of strings variables interpreted as char arrays; change them to cell. - if (ischar (obj)) obj = {obj}; endif - - [topleft, nrows, ncols, trow, lcol] = parse_sp_range (topleftcell); - [nrows, ncols] = size (obj); - - # Prepare type array to speed up writing - typearr = 5 * ones (nrows, ncols); # type "EMPTY", provisionally - obj2 = cell (size (obj)); # Temporary storage for strings - - txtptr = cellfun ('isclass', obj, 'char'); # type "STRING" replaced by "NUMERIC" - obj2(txtptr) = obj(txtptr); obj(txtptr) = 3; # Save strings in a safe place - - emptr = cellfun ("isempty", obj); - obj(emptr) = 5; # Set empty cells to NUMERIC - - lptr = cellfun ("islogical" , obj); # Find logicals... - obj2(lptr) = obj(lptr); # .. and set them to BOOLEAN - - ptr = cellfun ("isnan", obj); # Find NaNs & set to BLANK - typearr(ptr) = 4; typearr(~ptr) = 2; # All other cells are now numeric - - obj(txtptr) = obj2(txtptr); # Copy strings back into place - obj(lptr) = obj2(lptr); - typearr(txtptr) = 3; # ...and clean up - typearr(emptr) = 5; - typearr(lptr) = 1; # BOOLEAN - - # Write date to worksheet - for ii=1:nrows - ll = ii + trow - 2; # Java JExcelAPI's row count = 0-based - for jj=1:ncols - kk = jj + lcol - 2; # JExcelAPI's column count is also 0-based - switch typearr(ii, jj) - case 1 # Boolean - tmp = java_new ('jxl.write.Boolean', kk, ll, obj{ii, jj}); - sh.addCell (tmp); - case 2 # Numerical - tmp = java_new ('jxl.write.Number', kk, ll, obj{ii, jj}); - sh.addCell (tmp); - case 3 # String - tmp = java_new ('jxl.write.Label', kk, ll, obj{ii, jj}); - sh.addCell (tmp); - otherwise - # Just skip - endswitch - endfor - endfor - - rstatus = 1; - -endfunction Deleted: trunk/octave-forge/main/io/inst/xls2com2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2com2oct.m 2009-12-30 15:55:45 UTC (rev 6683) +++ trunk/octave-forge/main/io/inst/xls2com2oct.m 2009-12-30 16:04:47 UTC (rev 6684) @@ -1,124 +0,0 @@ -## Copyright (C)2009 P.R. Nienhuis, <pr.nienhuis at hccnet.nl> -## -## based on mat2xls by Michael Goffioul (2007) <mic...@sw...> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; If not, see <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2com2oct (@var{xls}) -## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2com2oct (@var{xls}, @var{wsh}) -## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2com2oct (@var{xls}, @var{wsh}, @var{range}) -## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel -## file pointed to in struct @var{xls} into the cell array @var{obj}. -## -## xls2com2oct should not be invoked directly but rather through xls2oct. -## -## Examples: -## -## @example -## [Arr, status, xls] = xls2com2oct (xls, 'Second_sheet', 'B3:AY41'); -## Arr = xls2com2oct (xls, 'Second_sheet'); -## @end example -## -## @seealso xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite -## -## @end deftypefn - -## Author: Philip Nienhuis -## Created: 2009-09-23 -## Last updated 2009-12-11 - -function [obj, xls, rstatus ] = xls2com2oct (xls, wsh, range) - - rstatus = 0; obj = {}; - - # Basic checks - if (nargin < 2) error ("xls2com2oct needs a minimum of 2 arguments."); endif - if (size (wsh, 2) > 31) - warning ("Worksheet name too long - truncated") - wsh = wsh(1:31); - endif - - nrows = 0; - emptyrange = 0; - if ((nargin == 2) || (isempty (range))) - emptyrange = 1; - else - # Extract top_left_cell from range - [topleft, nrows, ncols] = parse_sp_range (range); - endif; - - if (nrows >= 1 || emptyrange) - # Check the file handle struct - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'COM'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid file pointer struct"); - endif - app = xls.app; - wb = xls.workbook; - wb_cnt = wb.Worksheets.count; - old_sh = 0; - if (isnumeric (wsh)) - if (wsh < 1 || wsh > wb_cnt) - errstr = sprintf ("Worksheet number: %d out of range 1-%d", wsh, wb_cnt); - error (errstr) - return - else - old_sh = wsh; - endif - else - # Find worksheet number corresponding to name in wsh - wb_cnt = wb.Worksheets.count; - for ii =1:wb_cnt - sh_name = wb.Worksheets(ii).name; - if (strcmp (sh_name, wsh)) old_sh = ii; endif - endfor - if (~old_sh) - errstr = sprintf ("Worksheet name \"%s\" not present", wsh); - error (errstr) - else - wsh = old_sh; - endif - endif - - sh = wb.Worksheets (wsh); - - if (emptyrange) - allcells = sh.UsedRange; - obj = allcells.Value; - else - # Get object from Excel sheet, starting at cell top_left_cell - r = sh.Range (topleft); - r = r.Resize (nrows, ncols); - obj = r.Value; - delete (r); - endif; - # Take care of actual singe cell range - if (isnumeric (obj) || ischar (obj)) - obj = {obj}; - endif - # If we get here, all seems to have gone OK - rstatus = 1; - - else - error ("No data read from Excel file"); - rstatus = 0; - - endif - -endfunction Deleted: trunk/octave-forge/main/io/inst/xls2jpoi2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2jpoi2oct.m 2009-12-30 15:55:45 UTC (rev 6683) +++ trunk/octave-forge/main/io/inst/xls2jpoi2oct.m 2009-12-30 16:04:47 UTC (rev 6684) @@ -1,202 +0,0 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jpoi2oct (@var{xls}) -## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jpoi2oct (@var{xls}, @var{wsh}) -## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jpoi2oct (@var{xls}, @var{wsh}, @var{range}) -## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel -## file pointed to in struct @var{xls} into the cell array @var{obj}. -## @var{range} can be a range or just the top left cell of the range. -## -## xls2jpoi2oct should not be invoked directly but rather through xls2oct. -## -## Examples: -## -## @example -## [Arr, status, xls] = xls2jpoi2oct (xls, 'Second_sheet', 'B3:AY41'); -## B = xls2jpoi2oct (xls, 'Second_sheet', 'B3'); -## @end example -## -## @seealso xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite, oct2jpoi2xls -## -## @end deftypefn - -## Author: Philip Nienhuis -## Created: 2009-11-23 -## Last updated 2009-12-11 - -function [ rawarr, xls, status ] = xls2jpoi2oct (xls, wsh, cellrange=[]) - - persistent ctype; - if (isempty (ctype)) - # Get enumrated cell types. Beware as they start at 0 not 1 - ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); - ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); - ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); - ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); - ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BOOLEAN'); - ctype(6) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_ERROR'); - endif - - status = 0; jerror = 0; - - # Check if xls struct pointer seems valid - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'POI'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid xls file struct"); - else - wb = xls.workbook; - endif - - # Check if requested worksheet exists in the file & if so, get pointer - nr_of_sheets = wb.getNumberOfSheets (); - if (isnumeric (wsh)) - if (wsh > nr_of_sheets), error (sprintf ("Worksheet # %d bigger than nr. of sheets (%d) in file %s", wsh, nr_of_sheets, xls.filename)); endif - sh = wb.getSheetAt (wsh - 1); # POI sheet count 0-based - printf ("(Reading from worksheet %s)\n", sh.getSheetName ()); - else - sh = wb.getSheet (wsh); - if (isempty (sh)), error (sprintf("Worksheet %s not found in file %s", wsh, xls.filename)); endif - end - - # Check ranges - firstrow = sh.getFirstRowNum (); - lastrow = sh.getLastRowNum (); - if (isempty (cellrange)) - # Get used range by searching (slow...). Beware, it can be bit unreliable - lcol = 65535; # FIXME for OOXML - rcol = 0; - for ii=firstrow:lastrow - irow = sh.getRow (ii); - if (~isempty (irow)) - scol = (irow.getFirstCellNum).intValue (); - lcol = min (lcol, scol); - ecol = (irow.getLastCellNum).intValue () - 1; - rcol = max (rcol, ecol); - # Keep track of lowermost non-empty row as getLastRowNum() is unreliable - if ~(irow.getCell(scol).getCellType () == ctype(4) && irow.getCell(ecol).getCellType () == ctype(4)) - botrow = ii; - endif - endif - endfor - lastrow = min (lastrow, botrow); - nrows = lastrow - firstrow + 1; - ncols = rcol - lcol + 1; - else - # Translate range to HSSF POI row & column numbers - [topleft, nrows, ncols, trow, lcol] = parse_sp_range (cellrange); - firstrow = max (trow-1, firstrow); - lastrow = firstrow + nrows - 1; - lcol = lcol -1; # POI rows & column # 0-based - endif - - # Create formula evaluator (needed to infer proper cell type into rawarr) - # NB formula evaluation is not very reliable in POI - frm_eval = wb.getCreationHelper().createFormulaEvaluator (); - - #wb.clearAllCachedResultsValues(); # does not work - - # Read contents into rawarr - rawarr = cell (nrows, ncols); # create placeholder - for ii = firstrow:lastrow - irow = sh.getRow (ii); - if ~isempty (irow) - scol = (irow.getFirstCellNum).intValue (); - ecol = (irow.getLastCellNum).intValue () - 1; - for jj = max (scol, lcol) : min (lcol+ncols-1, ecol) - cell = irow.getCell (jj); - if ~isempty (cell) - # Process cell contents - type_of_cell = cell.getCellType (); - if (type_of_cell == ctype(3)) # Formula - try - cell = frm_eval.evaluate (cell); - type_of_cell = cell.getCellType(); - switch type_of_cell - case ctype (1) # Numeric - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumberValue (); - case ctype(2) # String - rawarr (ii+1-firstrow, jj+1-lcol) = char (cell.getStringValue ()); - case ctype (5) # Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = cell.BooleanValue (); - otherwise - # Nothing to do here - endswitch - catch - # In case of errors we copy the formula as text into rawarr - rawarr (ii+1-firstrow, jj+1-lcol) = ["=" cell.getCellFormula]; - type_of_cell = ctype (4); - if (~jerror) - warning ("Java errors in worksheet formulas (converted to string)"); - endif - ++jerror; # We only need one warning - end_try_catch - else - if (~isnumeric (type_of_cell)) type_of_cell = 4; endif - switch type_of_cell - case ctype(1) # 0 Numeric - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); - case ctype(2) # 1 String - rawarr (ii+1-firstrow, jj+1-lcol) = char (cell.getRichStringCellValue ()); -# case ctype(3) # 2 Formula (if still at all needed). -# try # Provisionally we simply take the result -# rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); -# catch -# # In case of errors we copy the formula as text into rawarr -# rawarr (ii+1-firstrow, jj+1-lcol) = ["=" cell.getCellFormula]; -# type_of_cell = ctype (4); -# if (~jerror) -# warning ("Java errors in worksheet formulas (converted to string)"); -# endif -# ++jerror; -# end - case ctype(4) # 3 Blank - # Blank; ignore until further notice - case ctype(5) # 4 Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getBooleanCellValue (); - otherwise # 5 Error - # Error; ignore - endswitch - endif - endif - endfor - endif - endfor - - if (jerror > 0) printf ("%d Java formula evalation errors\n", jerror); endif - - # Crop rawarr from empty outer rows & columns like Excel does - emptr = cellfun('isempty', rawarr); - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nrows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = ncols; - while (all (emptr(:, icolr))), icolr--; endwhile - # Crop textarray - rawarr = rawarr(irowt:irowb, icoll:icolr); - status = 1; - - xls.limits = [lcol+icoll, lcol+icolr; firstrow+irowt, firstrow+irowb]; - -endfunction Deleted: trunk/octave-forge/main/io/inst/xls2jxla2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2jxla2oct.m 2009-12-30 15:55:45 UTC (rev 6683) +++ trunk/octave-forge/main/io/inst/xls2jxla2oct.m 2009-12-30 16:04:47 UTC (rev 6684) @@ -1,162 +0,0 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jxla2oct (@var{xls}) -## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jxla2oct (@var{xls}, @var{wsh}) -## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = xls2jxla2oct (@var{xls}, @var{wsh}, @var{range}) -## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel -## file pointed to in struct @var{xls} into the cell array @var{obj}. -## @var{range} can be a range or just the top left cell of the range. -## -## xls2jxla2oct should not be invoked directly but rather through xls2oct. -## -## Examples: -## -## @example -## [Arr, status, xls] = xls2jxla2oct (xls, 'Second_sheet', 'B3:AY41'); -## B = xls2jxla2oct (xls, 'Second_sheet'); -## @end example -## -## @seealso xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite, oct2jxla2xls -## -## @end deftypefn - -## Author: Philip Nienhuis -## Created: 2009-12-04 -## Last updated 2009-12-11 - -function [ rawarr, xls, status ] = xls2jxla2oct (xls, wsh, cellrange=[]) - - persistent ctype; - if (isempty (ctype)) - ctype = cell (11, 1); - # Get enumerated cell types. Beware as they start at 0 not 1 - ctype(1,1) = (java_get ('jxl.CellType', 'BOOLEAN')).toString (); - ctype(2,1) = (java_get ('jxl.CellType', 'BOOLEAN_FORMULA')).toString (); - ctype(3,1) = (java_get ('jxl.CellType', 'DATE')).toString (); - ctype(4,1) = (java_get ('jxl.CellType', 'DATE_FORMULA')).toString (); - ctype(5,1) = (java_get ('jxl.CellType', 'EMPTY')).toString (); - ctype(6,1) = (java_get ('jxl.CellType', 'ERROR')).toString (); - ctype(7,1) = (java_get ('jxl.CellType', 'FORMULA_ERROR')).toString (); - ctype(8,1) = (java_get ('jxl.CellType', 'NUMBER')).toString (); - ctype(9,1) = (java_get ('jxl.CellType', 'LABEL')).toString (); - ctype(10,1) = (java_get ('jxl.CellType', 'NUMBER_FORMULA')).toString (); - ctype(11,1) = (java_get ('jxl.CellType', 'STRING_FORMULA')).toString (); - endif - - status = 0; - - # Check if xls struct pointer seems valid - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'JXL'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid xls file struct"); - else - wb = xls.workbook; - endif - - # Check if requested worksheet exists in the file & if so, get pointer - nr_of_sheets = wb.getNumberOfSheets (); - shnames = char (wb.getSheetNames ()); - if (isnumeric (wsh)) - if (wsh > nr_of_sheets), error (sprintf ("Worksheet # %d bigger than nr. of sheets (%d) in file %s", wsh, nr_of_sheets, xls.filename)); endif - sh = wb.getSheet (wsh - 1); # POI sheet count 0-based - printf ("(Reading from worksheet %s)\n", shnames {wsh}); - else - sh = wb.getSheet (wsh); - if (isempty (sh)), error (sprintf ("Worksheet %s not found in file %s", wsh, xls.filename)); endif - end - - # Check ranges - firstrow = 0; - lcol = 0; - - if (isempty (cellrange)) - nrows = sh.getRows (); - lastrow = nrows - 1; - ncols = sh.getColumns (); - trow = firstrow; - rcol = ncols - 1; - else - # Translate range to HSSF POI row & column numbers - [dummy, nrows, ncols, trow, lcol] = parse_sp_range (cellrange); - firstrow = max (trow-1, firstrow); - lastrow = firstrow + nrows - 1; - lcol = lcol - 1; # POI rows & column # 0-based - endif - - # Read contents into rawarr - rawarr = cell (nrows, ncols); # create placeholder - for jj = lcol : lcol+ncols-1 - for ii = firstrow:lastrow - cell = sh.getCell (jj, ii); - type_of_cell = char (cell.getType ()); - switch type_of_cell - case ctype {1, 1} - # Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {2, 1} - # Boolean formula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {3, 1} - # Date - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {4, 1} - # Date Formula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {5, 1} - # Empty. Nothing to do here - case ctype {6, 1} - # Error. Nothing to do here - case ctype {7, 1} - # Formula Error. Nothing to do here - case ctype {8, 1} - # Number - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {9, 1} - # String - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getString (); - case ctype {10, 1} - # NumericalFormula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {11, 1} - # String Formula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getString (); - endswitch - endfor - endfor - - # Crop rawarr from empty outer rows & columns just like Excel does - emptr = cellfun('isempty', rawarr); - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nrows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = ncols; - while (all (emptr(:, icolr))), icolr--; endwhile - # Crop textarray - rawarr = rawarr(irowt:irowb, icoll:icolr); - status = 1; - - xls.limits = [lcol+icoll, lcol+icolr; firstrow+irowt, firstrow+irowb]; - -endfunction This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-01-03 22:30:42
|
Revision: 6697 http://octave.svn.sourceforge.net/octave/?rev=6697&view=rev Author: prnienhuis Date: 2010-01-03 22:30:17 +0000 (Sun, 03 Jan 2010) Log Message: ----------- Fixed OOXML support. Updated calccelladdress.m to deal with OOXML's somewhat excessive column capacity (16384). parse_sp_range.m needs a related update too (will come next days). Because of Java bugs I gave up on properly adding boolean values to .xls files in oct2xls when using POI; now 1 or 0 are written rather than TRUE or FALSE, resp. Also all help texts have been updated. Modified Paths: -------------- trunk/octave-forge/main/io/inst/calccelladdress.m trunk/octave-forge/main/io/inst/oct2xls.m trunk/octave-forge/main/io/inst/xls2oct.m trunk/octave-forge/main/io/inst/xlsclose.m trunk/octave-forge/main/io/inst/xlsfinfo.m trunk/octave-forge/main/io/inst/xlsopen.m trunk/octave-forge/main/io/inst/xlsread.m trunk/octave-forge/main/io/inst/xlswrite.m Modified: trunk/octave-forge/main/io/inst/calccelladdress.m =================================================================== --- trunk/octave-forge/main/io/inst/calccelladdress.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/calccelladdress.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -17,7 +17,8 @@ ## calccelladdress - compute spreadsheet style cell address from ## row & column index. ## -## Max column index currently set to 1378 (ODS has max 1024) +## Max column index currently set to 18278 (max ODS: 1024, OOXML: 16384). +## Row limits for ODF and OOXML are 65536 and 1048576, resp. ## Author: Philip Nienhuis <prnienhuis at users.sf.net> ## Created: 2009-12-12 @@ -27,15 +28,19 @@ if (nargin < 4) error ("calccelladdress: not enough arguments.") endif colnr = lcol + column - 1; - if (colnr> 1378) error ("Column nr > 1378"); endif - str = char (rem ((colnr-1), 26) + 'A'); - if (colnr > 26 && colnr < 703) - tmp = char (floor ((colnr - 27) / 26) + 'A'); + if (colnr > 18278) error ("Column nr > 18278"); endif + rem1 = rem ((colnr-1), 26); + str = char (rem1 + 'A'); # A-Z; rightmost digit + if (colnr > 26 && colnr < 703) # AA-ZZ + tmp = char (floor(colnr - rem1) / 26 - 1 + 'A'); # Leftmost digit str = [tmp str]; - elseif (colnr > 702 && colnr < 1379) - tmp = char (floor ((colnr - 703) / 26) + 'A'); - str = ['A' tmp str]; - endif + elseif (colnr > 702 && colnr < 18279) # AAA-ZZZ + rem2 = rem ((colnr - 26 - rem1) - 1, 676); + str2 = char (rem2 / 26 + 'A'); # Middle digit + colnr = colnr - rem2 - rem1; + str3 = char (colnr / 676 - 1 + 'A'); # Leftmost digit + str = [str3 str2 str]; + endif celladdress = sprintf ("%s%d", str, trow + row - 1); endfunction \ No newline at end of file Modified: trunk/octave-forge/main/io/inst/oct2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2xls.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/oct2xls.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -71,7 +71,7 @@ ## Author: Philip Nienhuis ## Created: 2009-12-01 -## Latest update: 2009-12-30 +## Latest update: 2010-01-03 (OOXML support) function [ xls, rstatus ] = oct2xls (obj, xls, wsh, topleft='A1') @@ -351,7 +351,7 @@ ## Author: Philip Nienhuis ## Created: 2009-11-26 -## Last updated 2009-12-11 +## Last updated 2010-01-03 function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, topleftcell="A1") @@ -440,12 +440,13 @@ obj(txtptr) = obj2(txtptr); # Copy strings back into place obj(lptr) = obj2(lptr); + typearr(txtptr) = ctype(2); # ...and clean up typearr(emptr) = ctype(4); - typearr(lptr) = ctype(5); # BOOLEAN + typearr(lptr) = ctype(5); # BOOLEAN, temp NUMERIC # Create formula evaluator (needed to be able to write boolean values!) - frm_eval = xls.workbook.getCreationHelper().createFormulaEvaluator(); + frm_eval = xls.workbook.getCreationHelper ().createFormulaEvaluator (); for ii=1:nrows ll = ii + trow - 2; # Java POI's row count = 0-based @@ -453,14 +454,10 @@ if (isempty (row)) row = sh.createRow (ll); endif for jj=1:ncols kk = jj + lcol - 2; # POI's column count is also 0-based - cell = row.createCell (kk, typearr(ii,jj)); - if (typearr(ii, jj) == ctype(5)) - cell = row.createCell (kk, ctype(3)); - # Provisionally we make do with formulas evaluated immediately 8-Z - if obj{ii, jj} bool = '(1=1)'; else bool = '(1=0)'; endif - cell.setCellFormula (bool); frm_eval.evaluateInCell (cell); - elseif ~(typearr(ii, jj) == 3) - # Just put text or number in cell + if (typearr(ii, jj) == ctype(4)) + cell = row.createCell (kk, ctype(4)); + else + cell = row.createCell (kk, typearr(ii,jj)); cell.setCellValue (obj{ii, jj}); endif endfor Modified: trunk/octave-forge/main/io/inst/xls2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2oct.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/xls2oct.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -86,8 +86,9 @@ ## @end deftypefn ## Author: Philip Nienhuis -## Created: 2009-10-16 -## Latest update: 2009-12-30 +## Created: 2010-10-16 +## Latest update: 2009-01-03 (added OOXML support & cleaned up code. Excel +## INDIRECT function still not working OK) function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh, datrange='') @@ -397,24 +398,12 @@ rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); case ctype(2) # 1 String rawarr (ii+1-firstrow, jj+1-lcol) = char (cell.getRichStringCellValue ()); -# case ctype(3) # 2 Formula (if still at all needed). -# try # Provisionally we simply take the result -# rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); -# catch -# # In case of errors we copy the formula as text into rawarr -# rawarr (ii+1-firstrow, jj+1-lcol) = ["=" cell.getCellFormula]; -# type_of_cell = ctype (4); -# if (~jerror) -# warning ("Java errors in worksheet formulas (converted to string)"); -# endif -# ++jerror; -# end case ctype(4) # 3 Blank # Blank; ignore until further notice case ctype(5) # 4 Boolean rawarr (ii+1-firstrow, jj+1-lcol) = cell.getBooleanCellValue (); otherwise # 5 Error - # Error; ignore + # Formula (treated above) or error; ignore endswitch endif endif Modified: trunk/octave-forge/main/io/inst/xlsclose.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsclose.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/xlsclose.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -44,7 +44,7 @@ ## Author: Philip Nienhuis ## Created: 2009-11-29 -## Latest update: 2009-12-11 +## Latest update: 2010-01-03 (checked OOXML support) function [ xls ] = xlsclose (xls) @@ -60,16 +60,7 @@ # 51 = .xlsx - xlOpenXMLWorkbook (without macro's in 2007) # 52 = .xlsm - xlOpenXMLWorkbookMacroEnabled (with or without macro's in 2007) # 56 = .xls - xlExcel8 (97-2003 format in Excel 2007) - # - # Probably to be incorporated as wb.SaveAs (filename, FileFormatNum)? - # where filename is properly canonicalized with proper extension. - # This functionality is not tried or implemented yet as there are no - # checks if the installed Excel version can actually write the - # desired formats; e.g., stock Excel 97 cannot write .xlsx; & Excel - # always gives a pop-up when about to write non-native formats. - # Moreover, in case of .csv, .wks, .txt we'll have to do something - # about gracefully ignoring the worksheet pointer. - # All To Be Sorted Out some time.... + unwind_protect xls.app.Application.DisplayAlerts = 0; if (xls.changed > 0) Modified: trunk/octave-forge/main/io/inst/xlsfinfo.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsfinfo.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/xlsfinfo.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -42,6 +42,9 @@ ## specified. This can sometimes be handy to get an idea of used cell ranges ## in each worksheet (the COM/Excel interface can't supply this information). ## +## For use on OOXML spreadsheets one needs full POI support (see xlsopen) and +## 'poi' needs to be specified for @var{reqintf}. +## ## Examples: ## ## @example Modified: trunk/octave-forge/main/io/inst/xlsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsopen.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/xlsopen.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -28,12 +28,14 @@ ## installed on your computer + proper javaclasspath set. These interfaces ## are referred to as COM, POI and JXL, resp., and are preferred in that ## order by default (depending on their presence). +## For OOXML support, in addition to Apache POI support you also need the +## following jars in your javaclasspath: poi-ooxml-schemas-3.5.jar, +## xbean.jar and dom4j-1.6.1.jar (or later versions). ## -## @var{filename} should be a valid .xls Excel file name; but if you use the +## @var{filename} should be a valid .xls or xlsx Excel file name; but if you use the ## COM interface you can specify any extension that your installed Excel version ## can read AND write. If @var{filename} does not contain any directory path, -## the file is saved in the current directory. (Support for .xlsx (Excel 2007 -## OOXML) based on Java and Apache POI will be added later). +## the file is saved in the current directory. ## ## If @var{readwrite} is set to 0 (default value) or omitted, the Excel file ## is opened for reading. If @var{readwrite} is set to True or 1, an Excel @@ -62,7 +64,7 @@ ## Author: Philip Nienhuis ## Created: 2009-11-29 -## Last updated 2009-12-30 +## Last updated 2010-01-03 (Added OOXML support) function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[]) @@ -124,6 +126,7 @@ # Supported interfaces determined; Excel file type check moved to seperate interfaces. chk1 = strcmp (tolower (filename(end-3:end)), '.xls'); + chk2 = strcmp (tolower (filename(end-4:end-1)), '.xls'); xls = struct ("xtype", 'NONE', "app", [], "filename", [], "workbook", [], "changed", 0, "limits", []); @@ -162,15 +165,19 @@ xls.filename = filename; elseif (xlsinterfaces.POI) - if (~chk1) - error ("Currently xls2oct / POI can only read reliably from .xls files") + if ~(chk1 || chk2) + error ("Unsupported file format for xls2oct / Apache POI.") endif xls.xtype = 'POI'; # Get handle to workbook if (xwrite == 2) - wb = java_new ('org.apache.poi.hssf.usermodel.Workbook'); + if (chk1) + wb = java_new ('org.apache.poi.hssf.usermodel.HSSFWorkbook'); + elseif (chk2) + wb = java_new ('org.apache.poi.xssf.usermodel.XSSFWorkbook'); + endif + xls.app = 'new_POI' else - # Get handle to xls-file. OOXML not working here despite POI Javadocs try xlsin = java_new ('java.io.FileInputStream', filename); wb = java_invoke ('org.apache.poi.ss.usermodel.WorkbookFactory', 'create', xlsin); Modified: trunk/octave-forge/main/io/inst/xlsread.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsread.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/xlsread.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -66,6 +66,8 @@ ## The optional last argument @var{reqintf} can be used to override ## the automatic selection by xlsread of one interface out of the ## supported ones: COM/Excel, Java/Apache POI, or Java/JExcelAPI. +## For reading from OOXML files a value of 'poi' must be specified +## for @var{reqintf} (see help for xlsopen). ## ## Erroneous data and empty cells are set to NaN in @var{numarr} and ## turn up empty in @var{txtarr} and @var{rawarr}. Date/time values in Modified: trunk/octave-forge/main/io/inst/xlswrite.m =================================================================== --- trunk/octave-forge/main/io/inst/xlswrite.m 2010-01-03 22:21:52 UTC (rev 6696) +++ trunk/octave-forge/main/io/inst/xlswrite.m 2010-01-03 22:30:17 UTC (rev 6697) @@ -18,7 +18,7 @@ ## @deftypefn {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}) ## @deftypefnx {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}, @var{wsh}) ## @deftypefnx {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}) -## @deftypefnx {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}, @var{reqintf) +## @deftypefnx {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}, @var{reqintf}) ## Add data in 1D/2D array @var{arr} to worksheet @var{wsh} in Excel ## spreadsheet file @var{filename} in range @var{range}. ## @@ -63,6 +63,8 @@ ## The optional last argument @var{reqintf} can be used to override ## the automatic selection by xlsread of one interface out of the ## supported ones: COM/Excel, Java/Apache POI, or Java/JExcelAPI. +## For writing to OOXML files (.xlsx) a value of 'poi' (case-insensitive) +## must be specified for @var{reqintf}. ## ## xlswrite is a mere wrapper for various scripts which find out what ## Excel interface to use (COM, Java/POI) plus code to mimic the other @@ -87,7 +89,7 @@ ## Author: Philip Nienhuis ## Created: 2009-10-16 -## Latest update: 2009-12-11 +## Latest update: 2010-01-04 (Adapted range capacity checks to OOXML) function [ rstatus ] = xlswrite (filename, arr, arg3, arg4, arg5) @@ -103,10 +105,14 @@ elseif (nargin == 2) # Assume first worksheet and full worksheet starting at A1 wsh = 1; - range = "A1:IV65536"; + if (strcmp (tolower (filename(end-4:end-1)), 'xls') + range = "A1:XFD1048576"; # OOXML has ridiculously large limits + else + range = "A1:IV65536"; # Regular xls limits + endif elseif (nargin == 3) # Find out whether 3rd argument = worksheet or range - if (isnumeric(arg3) || (isempty(findstr(arg3, ':')) && ~isempty(arg3))) + if (isnumeric (arg3) || (isempty (findstr (arg3, ':')) && ~isempty (arg3))) # Apparently a worksheet specified wsh = arg3; range = "A1:IV65536"; # FIXME for OOXML (larger sheet ranges) @@ -132,8 +138,8 @@ [nr, nc] = size (arr); if ((nr > nrows) || (nc > ncols)) # Array too big; truncate - nr = min(nrows, nr); - nc = min(ncols, nc); + nr = min (nrows, nr); + nc = min (ncols, nc); warning ("xlswrite - array truncated to %d by %d to fit in range %s", ... nrows, ncols, range); endif @@ -142,6 +148,6 @@ [xls, rstatus] = oct2xls (arr(1:nr, 1:nc), xls, wsh, topleft); - xlsclose (xls); + xls = xlsclose (xls); endfunction This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-01-03 22:33:53
|
Revision: 6698 http://octave.svn.sourceforge.net/octave/?rev=6698&view=rev Author: prnienhuis Date: 2010-01-03 22:33:41 +0000 (Sun, 03 Jan 2010) Log Message: ----------- Fixed some small bugs; added JOpenDocument support for odsfinfo.m; fixed reading from date/time cells when using jOpenDocument; improved help texts; cleaned up code. Modified Paths: -------------- trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/odsfinfo.m trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/odsread.m Modified: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m 2010-01-03 22:30:17 UTC (rev 6697) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2010-01-03 22:33:41 UTC (rev 6698) @@ -56,7 +56,7 @@ ## ## Erroneous data and empty cells turn up empty in @var{rawarr}. ## Date/time values in OpenOffice.org are returned as numerical values -## with base 1-1-000 (same as octave). But beware that Excel spreadsheets +## with base 1-1-0000 (same as octave). But beware that Excel spreadsheets ## rewritten by OpenOffice.org into .ods format may have numerical date ## cells with base 01-01-1900 (same as MS-Excel). ## Modified: trunk/octave-forge/main/io/inst/odsfinfo.m =================================================================== --- trunk/octave-forge/main/io/inst/odsfinfo.m 2010-01-03 22:30:17 UTC (rev 6697) +++ trunk/octave-forge/main/io/inst/odsfinfo.m 2010-01-03 22:33:41 UTC (rev 6698) @@ -15,8 +15,8 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} [@var{filetype}] = odsfinfo (@var{filename}) -## @deftypefnx {Function File} [@var{filetype}, @var{sh_names}] = odsfinfo (@var{filename}) +## @deftypefn {Function File} [@var{filetype}] = odsfinfo (@var{filename} [, @var{reqintf}]) +## @deftypefnx {Function File} [@var{filetype}, @var{sh_names}] = odsfinfo (@var{filename} [, @var{reqintf}]) ## Query an OpenOffice.org spreadsheet file @var{filename} (with .ods ## suffix) for some info about its contents (viz. sheet names). ## @@ -30,10 +30,14 @@ ## to right) in which they occur in the sheet stack. ## ## If you omit return arguments @var{filetype} and @var{sh_names} altogether, -## odsfinfo returns the sheet names + a guess for the number of rows -## containing actual data to the screen. +## odsfinfo returns the sheet names + (in case of the ODF toolkit interfcae) +## a raw guess for the number of rows containing actual data to the screen +## (actually the number of "table-rows" in ODS). ## -## odsfinfo execution can take its time as the entire spreadsheet has to +## By specifying a value of 'jod' or 'otk' for @var{reqintf} the automatic +## selection of the java interface is bypassed and the specified interface +## will be used (if at all present). +#### odsfinfo execution can take its time as the entire spreadsheet has to ## be parsed to get the sheet names. ## ## Examples: @@ -49,20 +53,20 @@ ## list of sheet names) ## @end example ## -## @seealso odsread, ods2oct +## @seealso odsread, odsopen, ods2oct, odsclose ## ## @end deftypefn ## Author: Philip Nienhuis <pr.nienhuis at users.sf.net> ## Created: 2009-12-17 -## Last updated 2009-12-29 +## Last updated 2010-01-03 (added functionality for JOD as well) -function [ filetype, sheetnames ] = odsfinfo (filename) +function [ filetype, sheetnames ] = odsfinfo (filename, reqintf=[]) onscreen = nargout < 1; + + ods = odsopen (filename, 0, reqintf); - ods = odsopen (filename); - filetype = 'OpenOffice.org Calc Document'; # To save execution time, only proceed if sheet names are wanted @@ -95,11 +99,21 @@ endfor elseif (strcmp (ods.xtype, 'JOD')) - # jOpenDocument doesn't support sheet name extraction (yet?) - printf ("No sheet name support implemented in jOpenDocument.\n") + nr_of_sheets = ods.workbook.getSheetCount (); + sheetnames = cell (nr_of_sheets, 1); + for ii=1:nr_of_sheets + tmp1 = char (ods.workbook.getSheet (ii-1)); + ist = index (tmp1, 'table:name=') + 12; + ien = index (tmp1(ist:end), '" table') - 2 + ist; + sheetnames(ii) = tmp1(ist:ien); + if (onscreen) + # Echo sheet names + printf (" %s\n", sheetnames{ii}); + endif + endfor else - error (sprintf ("odsfinfo: unknown OpenOffice.org .ods interface - %s.", xls.xtype)); +# error (sprintf ("odsfinfo: unknown OpenOffice.org .ods interface - %s.", xls.xtype)); endif endif Modified: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m 2010-01-03 22:30:17 UTC (rev 6697) +++ trunk/octave-forge/main/io/inst/odsopen.m 2010-01-03 22:33:41 UTC (rev 6698) @@ -24,7 +24,7 @@ ## Calling odsopen without specifying a return argument is fairly useless! ## ## To make this function work at all, you need the Java package > 1.2.5 plus -## either ODFtoolkit > 3.5 & xercesImpl, or jOpenDocument installed on your +## either ODFtoolkit > 0.7.5 & xercesImpl, or jOpenDocument installed on your ## computer + proper javaclasspath set. These interfaces are referred to as ## OTK and JOD, resp., and are preferred in that order by default (depending ## on their presence). @@ -58,7 +58,7 @@ ## Created: 2009-12-13 ## Last update: 2009-12-30 -function [ ods ] = odsopen (filename, rw=0, reqinterface = []) +function [ ods ] = odsopen (filename, rw=0, reqinterface=[]) persistent odsinterfaces; persistent chkintf; if (isempty (chkintf)) Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2010-01-03 22:30:17 UTC (rev 6697) +++ trunk/octave-forge/main/io/inst/odsread.m 2010-01-03 22:33:41 UTC (rev 6698) @@ -56,7 +56,8 @@ ## ## The optional last argument @var{reqintf} can be used to override ## the automatic selection by odsread of one interface out of the -## supported ones: Java/ODFtoolkit or Java/jOpenDocument. +## supported ones: Java/ODFtoolkit ('OTK') or Java/jOpenDocument +## ('JOD'). ## ## Erroneous data and empty cells are set to NaN in @var{numarr} and ## turn up empty in @var{txtarr} and @var{rawarr}. Date/time values This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-01-05 22:58:37
|
Revision: 6704 http://octave.svn.sourceforge.net/octave/?rev=6704&view=rev Author: prnienhuis Date: 2010-01-05 22:58:27 +0000 (Tue, 05 Jan 2010) Log Message: ----------- Improved subfunction (for ODFtoolkit support) ods2jotk2oct in file ods2oct.m; almost all table-cell access now uses java methods, only one hack is left (for strings). In ODS there's no reliable way to explore row lengths; keeping track of implicitly read columns is a good way to speed up reading. ods2jotk2oct is much faster now because number-columns-repeated attributes are actively tracked, avoiding unneeded getCellAt() calls for sparsely populated rows - on the premise that the last table-cell in a row (beyond data cells) has a column-number-repeated attribute enclosing all empty columns to the right end. OOo-made ODS files have them neatly but hand-crafted ODS files might lack them. ods2oct.m and thus odsread.m both benefit from these changes. Also a warning is added in odsread when empty cell ranges were read. Modified Paths: -------------- trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/odsread.m Modified: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m 2010-01-05 22:38:14 UTC (rev 6703) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2010-01-05 22:58:27 UTC (rev 6704) @@ -87,9 +87,10 @@ ## Author: Philip Nienhuis ## Created: 2009-12-13 -## Latest update: 2009-12-30 +## Latest update of ods2oct: 2009-12-30 +## Latest update of functions below: 2010-01-05 -function [ rawarr, ods ] = ods2oct (ods, wsh=1, datrange=[]) +function [ rawarr, ods, rstatus ] = ods2oct (ods, wsh=1, datrange=[]) if (strcmp (ods.xtype, 'OTK')) # Read xls file tru Java & ODF toolkit @@ -107,6 +108,7 @@ endfunction + #===================================================================== ## Copyright (C) 2009 Philip Nienhuis <prnienhuis _at- users.sf.net> @@ -131,12 +133,14 @@ ## Author: Philip Nenhuis <pr.nienhuis at users.sf.net> ## Created: 2009-12-24 -## Last update: 2009-12-30 +## Last update: 2010-01-05 -function [ rawarr, ods, status ] = ods2jotk2oct (ods, wsh, crange = []) +function [ rawarr, ods, rstatus ] = ods2jotk2oct (ods, wsh=1, crange = []) # Parts after user gfterry in # http://www.oooforum.org/forum/viewtopic.phtml?t=69060 + + rstatus = 0; # Get contents and table stuff from the workbook odfcont = ods.workbook; # Use a local copy just to be sure. octave @@ -162,10 +166,8 @@ ii = 0; while (++ii <= nr_of_sheets && ischar (wsh)) # Look in first part of the sheet nodeset - tmp1 = char (sheets.item(ii-1))(1:150); - ist = index (tmp1, 'table:name=') + 12; - ien = index (tmp1(ist:end), '" table') - 2 + ist; - if (strcmp (tmp1(ist:ien), wsh)) + sh_name = sheets.item(ii-1).getTableNameAttribute (); + if (strcmp (sh_name, wsh)) # Convert local copy of wsh into a number (pointer) wsh = ii + i; endif @@ -175,7 +177,7 @@ # We already have a numeric sheet pointer. If it's not in range: error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); endif - + # Get table-rows in sheet no. wsh. Sheet count = 1-based (!) str = sprintf ("//table:table[%d]/table:table-row", wsh); sh = xpath.evaluate (str, odfcont, NODESET); @@ -210,72 +212,78 @@ row = sh.item(rowcnt++); nr_of_cells = min (row.getLength (), rcol); rightmcol = max (rightmcol, nr_of_cells); # Keep track of max row length - + # Read column (cell, "table-cell" in ODS speak) by column jj = lcol; r_cols = 0; - while (jj + r_cols <= 1024 && jj <= rcol) - tcell = char (row.getCellAt(jj-1)); - cellcont = getcellcont (tcell); # Parse cell contents, func = below - if (~isempty (cellcont.cvalue)) + while (r_cols <= 1024 && jj <= rcol) + tcell = row.getCellAt(jj-1); ++r_cols; + if (~isempty (tcell)) # If empty it's possibly in columns-repeated/spanned + if ~(index (char(tcell), 'text:p>Err:') || index (char(tcell), 'text:p>#DIV')) - # Get data from cell - switch cellcont.ctype - case {'float', 'currency', 'percentage'} - rawarr(ii, jj) = str2double (cellcont.cvalue); - case 'date' - # Dates are returned as octave datenums, i.e. 0-0-0000 based - str = cellcont.cvalue; - yr = str2num (str(1:4)); - mo = str2num (str(6:7)); - dy = str2num (str(9:10)); - if (index (str, 'T')) - hh = str2num (str(12:13)); - mm = str2num (str(15:16)); - ss = str2num (str(18:19)); - rawarr(ii, jj) = datenum (yr, mo, dy, hh, mm, ss); - else - rawarr(ii, jj) = datenum (yr, mo, dy); - endif - case 'time' - str = cellcont.cvalue; - if (index (str, 'PT')) - hh = str2num (str(3:4)); - mm = str2num (str(6:7)); - ss = str2num (str(9:10)); - rawarr(ii, jj) = datenum (0, 0, 0, hh, mm, ss); - endif - case 'boolean' - if (strcmp (cellcont.cvalue, 'true')) - rawarr(ii, jj) = true; - else - rawarr(ii, jj) = false; - endif - case 'string' - rawarr(ii, jj) = cellcont.cvalue; - otherwise - # Nothing - endswitch + # Get data from cell + ctype = tcell.getOfficeValueTypeAttribute (); + cvalue = tcell.getOfficeValueAttribute (); + switch deblank (ctype) + case {'float', 'currency', 'percentage'} + rawarr(ii, jj) = cvalue; + case 'date' + cvalue = tcell.getOfficeDateValueAttribute (); + # Dates are returned as octave datenums, i.e. 0-0-0000 based + yr = str2num (cvalue(1:4)); + mo = str2num (cvalue(6:7)); + dy = str2num (cvalue(9:10)); + if (index (cvalue, 'T')) + hh = str2num (cvalue(12:13)); + mm = str2num (cvalue(15:16)); + ss = str2num (cvalue(18:19)); + rawarr(ii, jj) = datenum (yr, mo, dy, hh, mm, ss); + else + rawarr(ii, jj) = datenum (yr, mo, dy); + endif + case 'time' + cvalue = tcell.getOfficeTimeValueAttribute (); + if (index (cvalue, 'PT')) + hh = str2num (cvalue(3:4)); + mm = str2num (cvalue(6:7)); + ss = str2num (cvalue(9:10)); + rawarr(ii, jj) = datenum (0, 0, 0, hh, mm, ss); + endif + case 'boolean' + if (strcmp (deblank (cvalue), 'true')) + rawarr(ii, jj) = true; + else + rawarr(ii, jj) = false; + endif + case 'string' + tmp = char (tcell); + # Get string value from between <text:p|r> </text:p|r> tags + ist = index (tmp, '<text'); + if (ist) + ist = ist + 8; ien = index (tmp(ist:end), '</text') + ist - 2; + rawarr(ii, jj) = tmp(ist:ien); + endif + otherwise + # Nothing + endswitch + endif + # Check for repeated columns (often empty columns, viz. to right of data) + # and add to column count + r_cols = r_cols + tcell.getTableNumberColumnsRepeatedAttribute () - 1; endif ++jj; # Next cell - r_cols = cellcont.cols; # Number of repeated columns. endwhile # Check for repeated rows (i.e. condensed in one table-row) - mm = index (char(row), 'number-rows-repeated'); - if (mm) - str = char (row) (1:82); - ist = mm + 22; ien = index (str(ist:end), '"') + ist - 2; - extrarows = str2num (str(ist:ien)); - if (extrarows > 0 && ii + extrarows < 65535) - # Expand table-row - nr_of_rows = nr_of_rows + extrarows - 1; - ii = ii + extrarows - 1; - nrows = min (65536, nrows + extrarows - 1); - brow = min (trow + nrows - 1, nr_of_rows); - # Increase return argument size if needed - tmp = cell (extrarows, 1024); - rawarr = [rawarr; tmp]; - endif + extrarows = row.getTableNumberRowsRepeatedAttribute () - 1; + if (extrarows > 1 && (ii + extrarows) < 65535) + # Expand rawarr cf. table-row + nr_of_rows = nr_of_rows + extrarows; + ii = ii + extrarows; + nrows = min (65536, nrows + extrarows); + brow = min (trow + nrows - 1, nr_of_rows); + # Increase return argument size if needed + tmp = cell (extrarows, 1024); + rawarr = [rawarr; tmp]; endif endwhile @@ -286,87 +294,24 @@ # Crop rawarr from all empty outer rows & columns just like Excel does # & keep track of limits emptr = cellfun('isempty', rawarr); - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nr_of_rows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = rightmcol; - while (all (emptr(:, icolr))), icolr--; endwhile - # Crop textarray - rawarr = rawarr(irowt:irowb, icoll:icolr); - status = 1; - - ods.limits = [lcol+icoll-1, lcol+icolr-1; trow+irowt-1, trow+irowb-1]; - -endfunction - - -## Copyright (C) 2009 by Philip Nienhuis <prnienhuis at users.sf.net> -## -## Parse some data from ODS spreadsheet cells. -## Input = character string <table:table-cell>...</table:table-cell> -## -## Author: Philip Nenhuis <pr.nienhuis at users.sf.net> -## Created: 2009-12-24 -## Last update: 2009-12-27 - -function cellcont = getcellcont (tcell) - - cellcont = struct ("ctype", '', "cvalue", '', "cols", 0); - - # Check for repeated columns (often empty columns, viz. to right of data) - ii = index (tcell, 'number-columns-repeated'); - if (ii) - ist = ii+25; ien = index(tcell(ist:end), '"') + ist - 2; - cellcont.cols = str2num (tcell(ist:ien)); + if (all (all (emptr))) + rawarr = {}; + ods.limits= []; + else + irowt = 1; + while (all (emptr(irowt, :))), irowt++; endwhile + irowb = nr_of_rows; + while (all (emptr(irowb, :))), irowb--; endwhile + icoll = 1; + while (all (emptr(:, icoll))), icoll++; endwhile + icolr = rightmcol; + while (all (emptr(:, icolr))), icolr--; endwhile + # Crop textarray + rawarr = rawarr(irowt:irowb, icoll:icolr); + rstatus = 1; + ods.limits = [lcol+icoll-1, lcol+icolr-1; trow+irowt-1, trow+irowb-1]; endif - # Get cell value type: float / boolean / string / date/.... Skip errors. - ii = index (tcell, 'value-type='); - if (ii && ~index (tcell, 'text:p>Err:') && ~index (tcell, 'text:p>#DIV')) - # Then cell contains useful data. - ist = ii + 12; ien = index (tcell(ist:end), '"') + ist - 2; - cellcont.ctype = tcell(ist:ien); - - if (strcmp (cellcont.ctype, 'string')) - # Get string value from between <text:p|r> </text:p|r> tags - ii = index (tcell, '<text'); - if (ii) - ist = ii + 8; ien = index (tcell(ist:end), '</text') + ist - 2; - cellcont.cvalue = tcell(ist:ien); - endif - - elseif (strcmp (cellcont.ctype, 'date')) - # Get date string - ii = index (tcell, 'date-value='); - if (ii) - ist = ii + 12; ien = index (tcell(ist:end), '"') + ist - 2; - # Return string for the time being - cellcont.cvalue = tcell(ist:ien); - endif - - elseif (strcmp (cellcont.ctype, 'time')) - # Get time string - ii = index (tcell, 'time-value='); - if (ii) - ist = ii + 12; ien = index (tcell(ist:end), '"') + ist - 2; - # Return string for the time being (no pun intended) - cellcont.cvalue = tcell(ist:ien); - endif - - else - # Get cell value as string (float, currency, percentage) - ii = index (tcell, 'value='); - if (ii) - ist = ii + 7; ien = index (tcell(ist:end), '"') + ist - 2; - cellcont.cvalue = tcell(ist:ien); - endif - - endif - endif - endfunction Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2010-01-05 22:38:14 UTC (rev 6703) +++ trunk/octave-forge/main/io/inst/odsread.m 2010-01-05 22:58:27 UTC (rev 6704) @@ -104,16 +104,20 @@ ## Author: Philip Nienhuis <prnienhuis at users.sf.net> ## Created: 2009-12-12 -## Last update: 2009-12-29 +## Last update: 2010-01-05 function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[]) ods = odsopen (filename, 0, reqintf); + + [rawarr, ods, rstatus] = ods2oct (ods, wsh, datrange); + + if (rstatus) + [numarr, txtarr, lim] = parsecell (rawarr, ods.limits); + else + warning (sprintf ("No data read from %s.", filename)); + endif - [rawarr, ods] = ods2oct (ods, wsh, datrange); - - [numarr, txtarr, lim] = parsecell (rawarr, ods.limits); - ods = odsclose (ods); endfunction This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-01-12 20:47:03
|
Revision: 6759 http://octave.svn.sourceforge.net/octave/?rev=6759&view=rev Author: prnienhuis Date: 2010-01-12 20:46:49 +0000 (Tue, 12 Jan 2010) Log Message: ----------- Bugfixes (notably parsing mixed cell arrays before writing); added unwind_protect in xlsread/xlswrite to better get rid of hidden Excel invocations in case of COM errors (and bugs 8-() ); improved Matlab compatibility: spreadsheet cells corresponding to empty array cells are cleared now rather than skipped when writing. Modified Paths: -------------- trunk/octave-forge/main/io/inst/oct2xls.m trunk/octave-forge/main/io/inst/xls2oct.m trunk/octave-forge/main/io/inst/xlsread.m trunk/octave-forge/main/io/inst/xlswrite.m Modified: trunk/octave-forge/main/io/inst/oct2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2xls.m 2010-01-12 16:39:43 UTC (rev 6758) +++ trunk/octave-forge/main/io/inst/oct2xls.m 2010-01-12 20:46:49 UTC (rev 6759) @@ -148,7 +148,10 @@ ## Author: Philip Nienhuis ## Rewritten: 2009-09-26 -## Last updated 2009-12-11 +## Updates: +## 2009-12-11 +## 2010-01-12 Fixed typearr sorting out (was only 1-dim & braces rather than parens)) +## Set cells corresponding to empty array cells empty (cf. Matlab) function [ xls, status ] = oct2com2xls (obj, xls, wsh, top_left_cell='A1') @@ -186,20 +189,22 @@ # Cleanup NaNs. Start with backing up strings, empty & boolean cells, # then set text cells to 0 + obj obj2 = cell (size (obj)); txtptr = cellfun ('isclass', obj, 'char'); - if (any(txtptr)) obj2{txtptr} = obj{txtptr}; obj{txtptr} = 0; endif + if (any (any (txtptr))) obj2(txtptr) = obj(txtptr); obj(txtptr) = 0; endif eptr = cellfun ('isempty', obj); - if (any (eptr)) obj{eptr} = 0; endif + if (any (any (eptr))) obj(eptr) = 0; endif lptr = cellfun ("islogical" , obj); - if (any (lptr)) obj2{lptr} = obj{lptr}; obj{lptr} = 0; endif + if (any (any (lptr))) obj2(lptr) = obj(lptr); obj(lptr) = 0; endif ptr = cellfun ("isnan", obj); - if (any (ptr)) obj{ptr} = []; endif + if (any (any (ptr))) obj{ptr} = []; endif - # Restore text & booleans - if (any (txtptr)) obj{txtptr} = obj2{txtptr}; endif - if (any (lptr)) obj{lptr} = obj2{lptr}; endif + # Restore text, empty cells & booleans + if (any (any (txtptr))) obj(txtptr) = obj2(txtptr); endif + if (any (any (lptr))) obj(lptr) = obj2(lptr); endif + if (any (any (eptr))) obj(eptr) = {[]}; endif clear obj2 txtptr eptr lptr ptr; if (xls.changed < 2) @@ -310,6 +315,7 @@ #==================================================================================== + ## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify @@ -351,7 +357,9 @@ ## Author: Philip Nienhuis ## Created: 2009-11-26 -## Last updated 2010-01-03 +## Updates: +## 2010-01-03 Bugfixes +## 2010-01-12 Added xls.changed = 1 statement to signal successful write function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, topleftcell="A1") @@ -462,7 +470,8 @@ endif endfor endfor - + + xls.changed = 1; rstatus = 1; endfunction @@ -510,7 +519,10 @@ ## Author: Philip Nienhuis ## Created: 2009-12-04 -## Last updated 2009-12-11 +## Updates: +## 2009-12-11 +## 2010-01-12 Fixed skipping empty array values (now Excel-conformant => cell cleared) +## Added xls.changed = 1 statement to signal successful write function [ xls, rstatus ] = oct2jxla2xls (obj, xls, wsh, topleftcell="A1") @@ -619,12 +631,16 @@ case 3 # String tmp = java_new ('jxl.write.Label', kk, ll, obj{ii, jj}); sh.addCell (tmp); + case {4, 5} + tmp = java_new ('jxl.write.Blank', kk, ll); + sh.addCell (tmp); otherwise # Just skip endswitch endfor endfor + xls.changed = 1; rstatus = 1; endfunction Modified: trunk/octave-forge/main/io/inst/xls2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2oct.m 2010-01-12 16:39:43 UTC (rev 6758) +++ trunk/octave-forge/main/io/inst/xls2oct.m 2010-01-12 20:46:49 UTC (rev 6759) @@ -60,6 +60,10 @@ ## Be aware that Excel trims @var{rawarr} from empty outer rows & columns, ## so any returned cell array may turn out to be smaller than requested ## in @var{range}. +## When using COM or POI interface, formulas in cells are evaluated; if +## that fails cached values are retrieved. Those may be outdated +## depending on Excel's "Automatic calculation" settings when the +## spreadsheet was saved. ## ## When reading from merged cells, all array elements NOT corresponding ## to the leftmost or upper Excel cell will be treated as if the @@ -240,6 +244,7 @@ #================================================================================== + ## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify @@ -279,7 +284,7 @@ ## Author: Philip Nienhuis ## Created: 2009-11-23 -## Last updated 2009-12-11 +## Last updated 2010-01-11 - fall back to cached values when formula evaluator fails function [ rawarr, xls, status ] = xls2jpoi2oct (xls, wsh, cellrange=[]) @@ -324,7 +329,7 @@ lastrow = sh.getLastRowNum (); if (isempty (cellrange)) # Get used range by searching (slow...). Beware, it can be bit unreliable - lcol = 65535; # FIXME for OOXML + lcol = 65535; rcol = 0; for ii=firstrow:lastrow irow = sh.getRow (ii); @@ -351,11 +356,8 @@ endif # Create formula evaluator (needed to infer proper cell type into rawarr) - # NB formula evaluation is not very reliable in POI frm_eval = wb.getCreationHelper().createFormulaEvaluator (); - #wb.clearAllCachedResultsValues(); # does not work - # Read contents into rawarr rawarr = cell (nrows, ncols); # create placeholder for ii = firstrow:lastrow @@ -366,12 +368,13 @@ for jj = max (scol, lcol) : min (lcol+ncols-1, ecol) cell = irow.getCell (jj); if ~isempty (cell) - # Process cell contents + # Explore cell contents type_of_cell = cell.getCellType (); if (type_of_cell == ctype(3)) # Formula - try + try # Because not al Excel formulas have been implemented cell = frm_eval.evaluate (cell); type_of_cell = cell.getCellType(); + # Separate switch because form.eval. yields different type switch type_of_cell case ctype (1) # Numeric rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumberValue (); @@ -382,18 +385,16 @@ otherwise # Nothing to do here endswitch + # Set cell type to blank to skip switch below + type_of_cell = ctype(4); catch - # In case of errors we copy the formula as text into rawarr - rawarr (ii+1-firstrow, jj+1-lcol) = ["=" cell.getCellFormula]; - type_of_cell = ctype (4); - if (~jerror) - warning ("Java errors in worksheet formulas (converted to string)"); - endif - ++jerror; # We only need one warning + # In case of formula errors we take the cached results + type_of_cell = cell.getCachedFormulaResultType (); + ++jerror; # We only need one warning even for multiple errors end_try_catch - else - if (~isnumeric (type_of_cell)) type_of_cell = 4; endif - switch type_of_cell + endif + # Preparations done, get data values into data array + switch type_of_cell case ctype(1) # 0 Numeric rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); case ctype(2) # 1 String @@ -403,15 +404,14 @@ case ctype(5) # 4 Boolean rawarr (ii+1-firstrow, jj+1-lcol) = cell.getBooleanCellValue (); otherwise # 5 Error - # Formula (treated above) or error; ignore - endswitch - endif + # Ignore + endswitch endif endfor endif endfor - if (jerror > 0) printf ("%d Java formula evalation errors\n", jerror); endif + if (jerror > 0) warning (sprintf ("oct2xls: %d cached values instead of formula evaluations.\n", jerror)); endif # Crop rawarr from empty outer rows & columns like Excel does emptr = cellfun('isempty', rawarr); @@ -595,4 +595,3 @@ xls.limits = [lcol+icoll, lcol+icolr; firstrow+irowt, firstrow+irowb]; endfunction - Modified: trunk/octave-forge/main/io/inst/xlsread.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsread.m 2010-01-12 16:39:43 UTC (rev 6758) +++ trunk/octave-forge/main/io/inst/xlsread.m 2010-01-12 20:46:49 UTC (rev 6759) @@ -115,67 +115,73 @@ ## Author: Philip Nienhuis ## Created: 2009-10-16 -## Latest update: 2009-12-29 +## Updates: +## 2009-12-29 bug fixes +## 2010-01-12 added unwind_protect to get rid of stray Excel invocations i.c.o. COM errors function [ numarr, txtarr, rawarr, lims ] = xlsread (fn, wsh, datrange, reqintf=[]) -rstatus = 0; + rstatus = 0; -if (nargin < 1) - error ("xlsread: no arguments specified") - numarr = []; txtarr={}; rawarr = {}; - return -elseif (nargin == 1) - wsh = 1; - datrange = ''; -elseif (nargin == 2) - # Find out whether 2nd argument = worksheet or range - if (isnumeric (wsh) || (isempty (findstr(wsh,':')) && ~isempty (wsh))) - # Apparently a worksheet specified - datrange = ''; - else - # Range specified - datrange = wsh; + if (nargin < 1) + error ("xlsread: no arguments specified") + numarr = []; txtarr={}; rawarr = {}; + return + elseif (nargin == 1) wsh = 1; + datrange = ''; + elseif (nargin == 2) + # Find out whether 2nd argument = worksheet or range + if (isnumeric (wsh) || (isempty (findstr(wsh,':')) && ~isempty (wsh))) + # Apparently a worksheet specified + datrange = ''; + else + # Range specified + datrange = wsh; + wsh = 1; + endif endif -endif -# A small gesture for Matlab compatibility. JExcelAPI supports BIFF5. -if (~isempty (reqintf) && strcmp (toupper(reqintf), 'BASIC')) - reqintf= "JXL"; - printf ("BASIC (BIFF5) support request translated to JXL. \n"); -endif + # A small gesture for Matlab compatibility. JExcelAPI supports BIFF5. + if (~isempty (reqintf) && strcmp (toupper(reqintf), 'BASIC')) + reqintf= "JXL"; + printf ("BASIC (BIFF5) support request translated to JXL. \n"); + endif -# Checks done. Get raw data into cell array "rawarr". xlsopen finds out -# what interface to use. If none found, suggest csv + # Checks done. Get raw data into cell array "rawarr". xlsopen finds out + # what interface to use. If none found, suggest csv -# Get pointer array to Excel file -xls = xlsopen (fn, 0, reqintf); + unwind_protect # Needed to catch COM errors & able to close stray Excel invocations + # Get pointer array to Excel file + xls = xlsopen (fn, 0, reqintf); -if (strcmp (xls.xtype, 'COM') || strcmp (xls.xtype, 'POI') || strcmp (xls.xtype, 'JXL')) + if (strcmp (xls.xtype, 'COM') || strcmp (xls.xtype, 'POI') || strcmp (xls.xtype, 'JXL')) - # Get data from Excel file & return handle - [rawarr, xls, rstatus] = xls2oct (xls, wsh, datrange); + # Get data from Excel file & return handle + [rawarr, xls, rstatus] = xls2oct (xls, wsh, datrange); - # Save some results before xls is wiped - rawlimits = xls.limits; - xtype = xls.xtype; - - # Close Excel file - xls = xlsclose (xls); + # Save some results before xls is wiped + rawlimits = xls.limits; + xtype = xls.xtype; - if (rstatus) - [numarr, txtarr, lims] = parsecell (rawarr, rawlimits); - # Wipe lims if using Excel (that doesn't return reliable rawlimits). - # The user can get the limits relative to the rawarr by parsecell (rawarr). - if (strcmp (xtype, 'COM')) lims = []; endif + if (rstatus) + [numarr, txtarr, lims] = parsecell (rawarr, rawlimits); + # Wipe lims if using Excel (that doesn't return reliable rawlimits). + # The user can get the limits relative to the rawarr by parsecell (rawarr). + if (strcmp (xtype, 'COM')) lims = []; endif + else + rawarr = {}; numarr = []; txtarr = {}; + endif + else - rawarr = {}; numarr = []; txtarr = {}; + printf ("\n Error XLSREAD: reading EXCEL .xls file (BIFF-Format) isn\'t supported on this system.\n You need to convert the file into a tab- or comma delimited text file or .csv file\n and then invoke dlmread()\n\n"); + endif -else - printf ("\n Error XLSREAD: reading EXCEL .xls file (BIFF-Format) isn\'t supported on this system.\n You need to convert the file into a tab- or comma delimited text file or .csv file\n and then invoke dlmread()\n\n"); + unwind_protect_cleanup + # Close Excel file + xls = xlsclose (xls); -endif + end_unwind_protect endfunction Modified: trunk/octave-forge/main/io/inst/xlswrite.m =================================================================== --- trunk/octave-forge/main/io/inst/xlswrite.m 2010-01-12 16:39:43 UTC (rev 6758) +++ trunk/octave-forge/main/io/inst/xlswrite.m 2010-01-12 20:46:49 UTC (rev 6759) @@ -89,7 +89,9 @@ ## Author: Philip Nienhuis ## Created: 2009-10-16 -## Latest update: 2010-01-04 (Adapted range capacity checks to OOXML) +## Updates: +## 2010-01-04 (Adapted range capacity checks to OOXML) +## 2010-01-12 (Bug fix; added unwind_protect to xlsopen...xlsclose calls) function [ rstatus ] = xlswrite (filename, arr, arg3, arg4, arg5) @@ -105,7 +107,7 @@ elseif (nargin == 2) # Assume first worksheet and full worksheet starting at A1 wsh = 1; - if (strcmp (tolower (filename(end-4:end-1)), 'xls') + if (strcmp (tolower (filename(end-4:end-1)), 'xls')) range = "A1:XFD1048576"; # OOXML has ridiculously large limits else range = "A1:IV65536"; # Regular xls limits @@ -144,10 +146,14 @@ nrows, ncols, range); endif + unwind_protect # Needed to besure Excel can be closed i.c.o. errors xls = xlsopen (filename, 1, reqintf); [xls, rstatus] = oct2xls (arr(1:nr, 1:nc), xls, wsh, topleft); + unwind_protect_cleanup xls = xlsclose (xls); + end_unwind_protect + endfunction This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-02-12 23:11:40
|
Revision: 6875 http://octave.svn.sourceforge.net/octave/?rev=6875&view=rev Author: prnienhuis Date: 2010-02-12 20:40:23 +0000 (Fri, 12 Feb 2010) Log Message: ----------- Changed "OpenOffice.org" to "OpenOffice_org" in the first help sentence in the function files to cope with imperfect get_first_help_sentence.m; that script truncates the first help sentence on dots. Modified Paths: -------------- trunk/octave-forge/main/io/inst/oct2ods.m trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/odsclose.m trunk/octave-forge/main/io/inst/odsfinfo.m trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/odsread.m trunk/octave-forge/main/io/inst/odswrite.m Modified: trunk/octave-forge/main/io/inst/oct2ods.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2ods.m 2010-02-12 19:20:21 UTC (rev 6874) +++ trunk/octave-forge/main/io/inst/oct2ods.m 2010-02-12 20:40:23 UTC (rev 6875) @@ -20,7 +20,7 @@ ## @deftypefnx {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}, @var{wsh}, @var{range}) ## ## Add data in 1D/2D array @var{arr} into a cell range @var{range} in -## sheet @var{wsh} in an OpenOffice.org Calc spreadsheet file pointed to in +## sheet @var{wsh} in an OpenOffice_org Calc spreadsheet file pointed to in ## structure @var{ods}. @var{ods} must have been made earlier by odsopen(). ## Return argument @var{ods} equals supplied argument @var{ods} and is ## updated by oct2ods. Modified: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m 2010-02-12 19:20:21 UTC (rev 6874) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2010-02-12 20:40:23 UTC (rev 6875) @@ -20,7 +20,7 @@ ## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}, @var{range}) ## ## Read data contained within range @var{range} from worksheet @var{wsh} -## in an OpenOffice.org spreadsheet file pointed to in struct @var{ods}. +## in an OpenOffice_org spreadsheet file pointed to in struct @var{ods}. ## ## ods2oct is a mere wrapper for interface-dependent scripts (e.g., ## ods2jotk2oct and ods2jod2oct) that do the actual reading. Modified: trunk/octave-forge/main/io/inst/odsclose.m =================================================================== --- trunk/octave-forge/main/io/inst/odsclose.m 2010-02-12 19:20:21 UTC (rev 6874) +++ trunk/octave-forge/main/io/inst/odsclose.m 2010-02-12 20:40:23 UTC (rev 6875) @@ -14,7 +14,8 @@ ## along with Octave; see the file COPYING. If not, see ## <http://www.gnu.org/licenses/>. -## odsclose - close an ods spreadsheet file +## odsclose - close an ods (OpenOffice_org) spreadsheet file + ## usage: ods = odsclose (ods) ## Author: Philip Nienhuis Modified: trunk/octave-forge/main/io/inst/odsfinfo.m =================================================================== --- trunk/octave-forge/main/io/inst/odsfinfo.m 2010-02-12 19:20:21 UTC (rev 6874) +++ trunk/octave-forge/main/io/inst/odsfinfo.m 2010-02-12 20:40:23 UTC (rev 6875) @@ -17,7 +17,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} [@var{filetype}] = odsfinfo (@var{filename} [, @var{reqintf}]) ## @deftypefnx {Function File} [@var{filetype}, @var{sh_names}] = odsfinfo (@var{filename} [, @var{reqintf}]) -## Query an OpenOffice.org spreadsheet file @var{filename} (with .ods +## Query an OpenOffice_org spreadsheet file @var{filename} (with .ods ## suffix) for some info about its contents (viz. sheet names). ## ## If @var{filename} is a recognizable OpenOffice.org spreadsheet file, Modified: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m 2010-02-12 19:20:21 UTC (rev 6874) +++ trunk/octave-forge/main/io/inst/odsopen.m 2010-02-12 20:40:23 UTC (rev 6875) @@ -18,7 +18,7 @@ ## @deftypefn {Function File} @var{ods} = odsopen (@var{filename}) ## @deftypefnx {Function File} @var{ods} = odsopen (@var{filename}, @var{readwrite}) ## @deftypefnx {Function File} @var{ods} = odsopen (@var{filename}, @var{readwrite}, @var{reqintf}) -## Get a pointer to an OpenOffice.org spreadsheet in the form of return +## Get a pointer to an OpenOffice_org spreadsheet in the form of return ## argument @var{ods}. ## ## Calling odsopen without specifying a return argument is fairly useless! Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2010-02-12 19:20:21 UTC (rev 6874) +++ trunk/octave-forge/main/io/inst/odsread.m 2010-02-12 20:40:23 UTC (rev 6875) @@ -21,7 +21,7 @@ ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}, @var{wsh}, @var{range}, @var{reqintf}) ## ## Read data contained in range @var{range} from worksheet @var{wsh} -## in OpenOffice.org Calc spreadsheet file @var{filename}. +## in OpenOffice_org Calc spreadsheet file @var{filename}. ## ## You need the octave-forge java package (> 1.2.5) and one or both of ## jopendocument.jar or preferrably: (odfdom.jar & xercesImpl.jar) in Modified: trunk/octave-forge/main/io/inst/odswrite.m =================================================================== --- trunk/octave-forge/main/io/inst/odswrite.m 2010-02-12 19:20:21 UTC (rev 6874) +++ trunk/octave-forge/main/io/inst/odswrite.m 2010-02-12 20:40:23 UTC (rev 6875) @@ -20,7 +20,7 @@ ## @deftypefnx {Function File} @var{rstatus} = odswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} @var{rstatus} = odswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}, @var{reqintf}) ## Add data in 1D/2D array @var{arr} to sheet @var{wsh} in -## OpenOffice.org Calc spreadsheet file @var{filename} in range @var{range}. +## OpenOffice_org Calc spreadsheet file @var{filename} in range @var{range}. ## ## @var{rstatus} returns 1 if write succeeded, 0 otherwise. ## This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-03-01 15:29:07
|
Revision: 6976 http://octave.svn.sourceforge.net/octave/?rev=6976&view=rev Author: prnienhuis Date: 2010-03-01 15:29:00 +0000 (Mon, 01 Mar 2010) Log Message: ----------- Removed check on rt.jar in javaclasspath (turned out to be unnecessary) Modified Paths: -------------- trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/xlsopen.m Modified: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m 2010-02-28 20:43:37 UTC (rev 6975) +++ trunk/octave-forge/main/io/inst/odsopen.m 2010-03-01 15:29:00 UTC (rev 6976) @@ -60,6 +60,7 @@ ## 2009-12-30 ## 2010-01-17 Make sure proper dimensions are checked in parsed javaclasspath ## 2010-01-24 Added warning when trying to create a new spreadsheet using jOpenDocument +## 2010-03-01 Removed check for rt.jar in javaclasspath function [ ods ] = odsopen (filename, rw=0, reqinterface=[]) @@ -84,6 +85,7 @@ usage (sprintf ("Unknown .ods interface \"%s\" requested. Only OTK or JOD supported", reqinterface)); endif odsinterfaces = getodsinterfaces (odsinterfaces); + # Well, is the requested interface supported on the system? if (~odsinterfaces.(toupper (reqinterface))) # No it aint @@ -232,14 +234,14 @@ # in class path. Under *nix the classpath must first be split up if (isunix) tmp1 = strsplit (char(tmp1), ":"); endif if (size (tmp1, 1) > size (tmp1,2)) tmp1 = tmp1'; endif - jpchk = 0; entries = {"rt.jar", "odfdom.jar", "xercesImpl.jar"}; + jpchk = 0; entries = {"odfdom.jar", "xercesImpl.jar"}; for ii=1:size (tmp1, 2) tmp2 = strsplit (char (tmp1(1, ii)), "\\/"); for jj=1:size (entries, 2) if (strmatch (entries{1, jj}, tmp2{size (tmp2, 2)})), ++jpchk; endif endfor endfor - if (jpchk > 2) + if (jpchk >= 2) odsinterfaces.OTK = 1; printf (" Java/ODFtoolkit (OTK) OK. "); chk1 = 1; @@ -260,14 +262,14 @@ # in class path. Under unix the classpath must first be split up if (isunix) tmp1 = strsplit (char(tmp1), ":"); endif if (size (tmp1, 1) > size (tmp1,2)) tmp1 = tmp1'; endif - jpchk = 0; entries = {"rt.jar", "jOpenDocument"}; + jpchk = 0; entries = {"jOpenDocument"}; for ii=1:size (tmp1, 2) tmp2 = strsplit (char (tmp1(1, ii)), "\\/"); for jj=1:size (entries, 2) if (strmatch (entries{1, jj}, tmp2{size (tmp2, 2)})), ++jpchk; endif endfor endfor - if (jpchk > 1) + if (jpchk >= 1) odsinterfaces.JOD = 1; printf (" Java/jOpenDocument (JOD) OK. "); chk1 = 1; Modified: trunk/octave-forge/main/io/inst/xlsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsopen.m 2010-02-28 20:43:37 UTC (rev 6975) +++ trunk/octave-forge/main/io/inst/xlsopen.m 2010-03-01 15:29:00 UTC (rev 6976) @@ -24,7 +24,7 @@ ## Calling xlsopen without specifying a return argument is fairly useless! ## ## To make this function work at all, you need MS-Excel (95 - 2003), and/or -## the Java package > 1.2.5 plus either Apache POI > 3.5 or JExcelAPI +## the Java package > 1.2.6 plus either Apache POI > 3.5 or JExcelAPI ## installed on your computer + proper javaclasspath set. These interfaces ## are referred to as COM, POI and JXL, resp., and are preferred in that ## order by default (depending on their presence). @@ -68,6 +68,7 @@ ## 2010-01-03 Added OOXML support ## 2010-01-10 Changed (java) interface preference order to COM->POI->JXL ## 2010-01-16 Removed echoeing debug info in POI stanza +## 2010-03-01 Removed javaclasspath check for rt.jar function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[]) @@ -95,6 +96,7 @@ usage (sprintf ("Unknown .xls interface \"%s\" requested. Only COM, POI or JXL supported", reqinterface)); endif xlsinterfaces = getxlsinterfaces (xlsinterfaces); + # Well, is the requested interface supported on the system? if (~xlsinterfaces.(toupper (reqinterface))) # No it aint @@ -296,17 +298,17 @@ tmp1 = javaclasspath; # If we get here, at least Java works. Now check for proper entries # in class path. Under *nix the classpath must first be split up - if (isunix) tmp1 = strsplit (char(tmp1), ":"); endif - if (size (tmp1, 1) > size (tmp1,2)) tmp1 = tmp1'; endif + if (isunix) tmp1 = strsplit (char (tmp1), ":"); endif + if (size (tmp1, 1) > size (tmp1, 2)) tmp1 = tmp1'; endif # Check basic .xls (BIFF8) support - jpchk1 = 0; entries1 = {"rt.jar", "poi-3", "poi-ooxml"}; + jpchk1 = 0; entries1 = {"poi-3", "poi-ooxml"}; for ii=1:size (tmp1, 2) tmp2 = strsplit (char (tmp1(1, ii)), "\\/"); for jj=1:size (entries1, 2) if (strmatch (entries1{1, jj}, tmp2{size (tmp2, 2)})), ++jpchk1; endif endfor endfor - if (jpchk1 > 2) + if (jpchk1 > 1) xlsinterfaces.POI = 1; printf (" Java/Apache (POI) OK. "); chk1 = 1; @@ -336,14 +338,14 @@ # in class path. Under unix the classpath must first be split up if (isunix) tmp1 = strsplit (char(tmp1), ":"); endif if (size (tmp1, 1) > size (tmp1,2)) tmp1 = tmp1'; endif - jpchk = 0; entries = {"rt.jar", "jxl.jar"}; + jpchk = 0; entries = {"jxl.jar"}; for ii=1:size (tmp1, 2) tmp2 = strsplit (char (tmp1(1, ii)), "\\/"); for jj=1:size (entries, 2) if (strmatch (entries{1, jj}, tmp2{size (tmp2, 2)})), ++jpchk; endif endfor endfor - if (jpchk > 1) + if (jpchk > 0) xlsinterfaces.JXL = 1; printf (" Java/JExcelAPI (JXL) OK. "); chk1 = 1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-03-04 21:02:31
|
Revision: 6988 http://octave.svn.sourceforge.net/octave/?rev=6988&view=rev Author: prnienhuis Date: 2010-03-04 21:02:24 +0000 (Thu, 04 Mar 2010) Log Message: ----------- Bumped reqd. java version to 1.2.6 & explicitly mention odfdom v. 0.7.5 Modified Paths: -------------- trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/odsread.m Modified: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m 2010-03-04 19:37:36 UTC (rev 6987) +++ trunk/octave-forge/main/io/inst/odsopen.m 2010-03-04 21:02:24 UTC (rev 6988) @@ -23,8 +23,8 @@ ## ## Calling odsopen without specifying a return argument is fairly useless! ## -## To make this function work at all, you need the Java package > 1.2.5 plus -## either ODFtoolkit > 0.7.5 & xercesImpl, or jOpenDocument installed on your +## To make this function work at all, you need the Java package > 1.2.6 plus +## either ODFtoolkit version 0.7.5 & xercesImpl, or jOpenDocument installed on your ## computer + proper javaclasspath set. These interfaces are referred to as ## OTK and JOD, resp., and are preferred in that order by default (depending ## on their presence). @@ -61,6 +61,7 @@ ## 2010-01-17 Make sure proper dimensions are checked in parsed javaclasspath ## 2010-01-24 Added warning when trying to create a new spreadsheet using jOpenDocument ## 2010-03-01 Removed check for rt.jar in javaclasspath +## 2010-03-04 Slight texinfo adaptation (reqd. odfdom version = 0.7.5) function [ ods ] = odsopen (filename, rw=0, reqinterface=[]) Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2010-03-04 19:37:36 UTC (rev 6987) +++ trunk/octave-forge/main/io/inst/odsread.m 2010-03-04 21:02:24 UTC (rev 6988) @@ -23,8 +23,8 @@ ## Read data contained in range @var{range} from worksheet @var{wsh} ## in OpenOffice_org Calc spreadsheet file @var{filename}. ## -## You need the octave-forge java package (> 1.2.5) and one or both of -## jopendocument.jar or preferrably: (odfdom.jar & xercesImpl.jar) in +## You need the octave-forge java package (> 1.2.6) and one or both of +## jopendocument.jar or preferrably: (odfdom.jar 0.7.5 & xercesImpl.jar) in ## your javaclasspath. ## ## Return argument @var{numarr} contains the numeric data, optional @@ -104,7 +104,9 @@ ## Author: Philip Nienhuis <prnienhuis at users.sf.net> ## Created: 2009-12-12 -## Last update: 2010-01-05 +## Updates: +## 2010-01-05 (....) +## 2010-03-04 Slight adaptations in texinfo function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ha...@us...> - 2010-04-17 18:40:43
|
Revision: 7206 http://octave.svn.sourceforge.net/octave/?rev=7206&view=rev Author: hauberg Date: 2010-04-17 18:40:37 +0000 (Sat, 17 Apr 2010) Log Message: ----------- Remove dlmwrite, csvread and csvwrite as they have been in core for a while Removed Paths: ------------- trunk/octave-forge/main/io/inst/csvread.m trunk/octave-forge/main/io/inst/csvwrite.m trunk/octave-forge/main/io/inst/dlmwrite.m Deleted: trunk/octave-forge/main/io/inst/csvread.m =================================================================== --- trunk/octave-forge/main/io/inst/csvread.m 2010-04-16 17:09:30 UTC (rev 7205) +++ trunk/octave-forge/main/io/inst/csvread.m 2010-04-17 18:40:37 UTC (rev 7206) @@ -1,27 +0,0 @@ -## Copyright (C) 2001, 2008 Paul Kienzle -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc. - -## -*- texinfo -*- -## @deftypefn {Function File} {x} = csvread (@var{filename}) -## Read the matrix @var{x} from a file. -## -## This function is equivalent to dlmread (@var{filename}, "," , ...) -## -## @seealso{dlmread, dlmwrite, csvwrite, csv2cell} -## @end deftypefn - -function m = csvread(f,varargin) - m = dlmread(f,',',varargin{:}); Deleted: trunk/octave-forge/main/io/inst/csvwrite.m =================================================================== --- trunk/octave-forge/main/io/inst/csvwrite.m 2010-04-16 17:09:30 UTC (rev 7205) +++ trunk/octave-forge/main/io/inst/csvwrite.m 2010-04-17 18:40:37 UTC (rev 7206) @@ -1,27 +0,0 @@ -## Copyright (C) 2001, 2008 Paul Kienzle -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc. - -## -*- texinfo -*- -## @deftypefn {Function File} {x} = csvwrite (@var{filename}, @var{x}) -## Write the matrix @var{x} to a file. -## -## This function is equivalent to dlmwrite(@var{filename},@var{x},",",...) -## -## @seealso{dlmread, dlmwrite, csvread, csv2cell} -## @end deftypefn - -function m = csvwrite(f,m,varargin) - dlmwrite(f,m,',',varargin{:}); Deleted: trunk/octave-forge/main/io/inst/dlmwrite.m =================================================================== --- trunk/octave-forge/main/io/inst/dlmwrite.m 2010-04-16 17:09:30 UTC (rev 7205) +++ trunk/octave-forge/main/io/inst/dlmwrite.m 2010-04-17 18:40:37 UTC (rev 7206) @@ -1,197 +0,0 @@ -## Copyright (C) 2002, 2008 Paul Kienzle -## -## This program is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} dlmwrite (@var{file}, @var{a}) -## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, @var{delim}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, "attrib1", @var{value1}, "attrib2", @var{value2}, @dots{}) -## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, "-append", @dots{}) -## -## Write the matrix @var{a} to the text @var{file} using delimiters. -## -## @table @var -## @item delim -## the delimiter to use to separate values on a row -## -## @item r -## the number of delimiter-only lines to add to the start of the file -## -## @item c -## the number of delimiters to prepend to each line of data. -## -## @item "-append" -## append to the end of the @var{file}. -## -## @item "append", state -## Either @samp{"on"} or @samp{"off"}. See @samp{"-append"} above. -## -## @item "delimiter", d -## See @var{delim} above. -## -## @item "newline", os -## The character(s) to use to separate each row. Three special cases -## exist for this option. @samp{"unix"} is changed into '\n', -## @samp{"pc"} is changed into '\r\n', and @samp{"mac"} is changed -## into '\r'. Other values for this option are kept as is. -## -## @item "roffset", r -## See @var{r} above. -## -## @item "coffset", c -## See @var{c} above. -## -## @item "precision", p -## The precision to use when writing the file. It can either be a -## format string (as used by fprintf) or a number of significant digits. -## @end table -## -## @example -## @var{A} = reshape(1:16,4,4); -## dlmwrite(@code{"file.csv"}, @var{A}) -## @end example -## -## @example -## dlmwrite (@code{"file.tex"}, @var{a}, "delimiter", "&", "newline", "\\n") -## @end example -## -## @seealso{dlmread, csvread, csvwrite} -## @end deftypefn - -## Author: Paul Kienzle <pki...@us...> -## -## This program was originally granted to the public domain -## -## 2002-03-08 Paul Kienzle <pki...@us...> -## * Initial revision -## 2005-11-27 Bill Denney <bi...@gi...> -## * Significant modifications of the input arguements for additional -## functionality. - -function dlmwrite (file, a, varargin) - - if (nargin < 2 || ! ischar (file)) - ptint_usage (); - endif - - ## set defaults - delim = ","; - r = 0; - c = 0; - newline = "\n"; - precision = "%.16g"; - opentype = "wt"; - - ## process the input arguements - i = 0; - while (i < length (varargin)) - i = i + 1; - if (strcmpi (varargin{i}, "delimiter") || strcmpi(varargin{i}, "delim")) - i = i + 1; - delim = varargin{i}; - elseif (strcmpi (varargin{i}, "newline")) - i = i + 1; - newline = varargin{i}; - if (strcmpi (newline, "unix")) - newline = "\n"; - elseif (strcmpi (newline, "pc")) - newline = "\r\n"; - elseif (strcmpi (newline, "mac")) - newline = "\r"; - endif - elseif (strcmpi (varargin{i}, "roffset")) - i = i + 1; - r = varargin{i}; - elseif (strcmpi (varargin{i}, "coffset")) - i = i + 1; - c = varargin{i}; - elseif (strcmpi (varargin{i}, "precision")) - i = i + 1; - precision = varargin{i}; - if (! strcmpi (class (precision), "char")) - precision = sprintf ("%.%gg", precision); - endif - elseif (strcmpi (varargin{i}, "-append")) - opentype = "at"; - elseif (strcmpi (varargin{i}, "append")) - i = i + 1; - if (strcmpi (varargin{i}, "on")) - opentype = "at"; - elseif (strcmpi (varargin{i}, "off")) - opentype = "wt"; - else - error ("dlmwrite: append must be \"on\" or \"off\"."); - endif - else - if (i == 1) - delim = varargin{i}; - elseif (i == 2) - r = varargin{i}; - elseif (i == 3) - c = varargin{i}; - else - print_usage(); - endif - endif - endwhile - - [fid, msg] = fopen (file, opentype); - if (fid < 0) - error (msg); - else - if (r > 0) - fprintf (fid, "%s", - repmat ([repmat(delim, 1, c + columns(a)-1), newline], 1, r)); - endif - if (iscomplex (a)) - cprecision = regexprep (precision, '^%([-\d.])','%+$1'); - template = [precision, cprecision, "i", ... - repmat([delim, precision, cprecision, "i"], 1, ... - columns(a) - 1), newline ]; - else - template = [precision, repmat([delim, precision], 1, columns(a)-1),... - newline]; - endif - if (c > 0) - template = [repmat(delim, 1, c), template]; - endif - if (iscomplex (a)) - a = a.'; - b = zeros (2*rows(a), columns (a)); - b(1: 2 : end, :) = real (a); - b(2: 2 : end, :) = imag (a); - fprintf (fid, template, b); - else - fprintf (fid, template, a.'); - endif - fclose (fid); - endif -endfunction - -%!test -%! f = tmpnam(); -%! dlmwrite(f,[1,2;3,4],'precision','%5.2f','newline','unix','roffset',1,'coffset',1); -%! fid = fopen(f,"rt"); -%! f1 = char(fread(fid,Inf,'char')'); -%! fclose(fid); -%! dlmwrite(f,[5,6],'precision','%5.2f','newline','unix','coffset',1,'delimiter',',','-append'); -%! dlmwrite(f,[5,6],'precision','%5.2f','delim','\t','-append'); -%! fid = fopen(f,"rt"); -%! f2 = char(fread(fid,Inf,'char')'); -%! fclose(fid); -%! unlink(f); -%! -%! assert(f1,",,\n, 1.00, 2.00\n, 3.00, 4.00\n"); -%! assert(f2,",,\n, 1.00, 2.00\n, 3.00, 4.00\n, 5.00, 6.00\n 5.00\t 6.00\n"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2012-06-08 16:39:20
|
Revision: 10598 http://octave.svn.sourceforge.net/octave/?rev=10598&view=rev Author: prnienhuis Date: 2012-06-08 16:39:09 +0000 (Fri, 08 Jun 2012) Log Message: ----------- Texinfo header (odfdom version) Modified Paths: -------------- trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/odsread.m Modified: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m 2012-06-08 16:33:58 UTC (rev 10597) +++ trunk/octave-forge/main/io/inst/odsopen.m 2012-06-08 16:39:09 UTC (rev 10598) @@ -24,7 +24,7 @@ ## Calling odsopen without specifying a return argument is fairly useless! ## ## To make this function work at all, you need the Java package >= 1.2.5 plus -## ODFtoolkit (version 0.7.5 or 0.8.6) & xercesImpl, and/or jOpenDocument, and/or +## ODFtoolkit (version 0.7.5 or 0.8.6+) & xercesImpl, and/or jOpenDocument, and/or ## OpenOffice.org (or clones) installed on your computer + proper javaclasspath ## set. These interfaces are referred to as OTK, JOD, and UNO resp., and are ## preferred in that order by default (depending on their presence). @@ -59,7 +59,7 @@ ## the jOpenDocument interface is requested) ## @end example ## -## @seealso {odsclose, odsread, ods2oct, odsfinfo, chk_spreadsheet_support} +## @seealso {odsclose, odsread, oct2ods, ods2oct, odsfinfo, chk_spreadsheet_support} ## ## @end deftypefn Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2012-06-08 16:33:58 UTC (rev 10597) +++ trunk/octave-forge/main/io/inst/odsread.m 2012-06-08 16:39:09 UTC (rev 10598) @@ -24,7 +24,7 @@ ## ## You need the octave-forge java package (> 1.2.6) and one or both of ## jopendocument-<version>.jar or preferrably: (odfdom.jar (versions -## 0.7.5, 0.8.6 or 0.8.7) & xercesImpl.jar v. 2.9.1) in your javaclasspath. +## 0.7.5 or 0.8.6+) & xercesImpl.jar v. 2.9.1) in your javaclasspath. ## There is also experimental support invoking OpenOffice.org or clones ## through Java/UNO bridge. ## This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-05-31 15:19:15
|
Revision: 7369 http://octave.svn.sourceforge.net/octave/?rev=7369&view=rev Author: prnienhuis Date: 2010-05-31 15:19:08 +0000 (Mon, 31 May 2010) Log Message: ----------- Added remark in help text about possible significant delays when no range has been specified (as that range must be determined behind the scenes by getusedrange.m first) Modified Paths: -------------- trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/odsread.m trunk/octave-forge/main/io/inst/xls2oct.m trunk/octave-forge/main/io/inst/xlsread.m Modified: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m 2010-05-31 09:29:09 UTC (rev 7368) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2010-05-31 15:19:08 UTC (rev 7369) @@ -34,6 +34,8 @@ ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). +## If no range is specified the occupied cell range will have to be +## determined behind the scenes first; this can take some time. ## ## If only the first argument is specified, ods2oct will try to read ## all contents from the first = leftmost (or the only) worksheet (as @@ -94,6 +96,7 @@ ## 2010-04-06 Benchmarked odfdom versions. v0.7.5 is up to 7 times faster than v0.8! ## So I added a warning for users using odfdom 0.8. ## 2010-04-11 Removed support for odfdom-0.8 - it's painfully slow and unreliable +## 2010-05-31 Updated help text (delay i.c.o. empty range due to getusedrange call) ## ## (Latest update of subfunctions below: 2010-04-13) @@ -361,7 +364,7 @@ ## Author: Philip Nienhuis ## Created: 2009-12-13 -function [ rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, crange) +function [ rawarr, ods, rstatus] = ods_2jod2oct (ods, wsh, crange) persistent months; months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2010-05-31 09:29:09 UTC (rev 7368) +++ trunk/octave-forge/main/io/inst/odsread.m 2010-05-31 15:19:08 UTC (rev 7369) @@ -45,6 +45,8 @@ ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). +## If no range is specified the occupied cell range will have to be +## determined behind the scenes first; this can take some time. ## ## If only the first argument is specified, odsread will try to read ## all contents from the first = leftmost (or the only) worksheet (as @@ -107,6 +109,7 @@ ## Updates: ## 2010-01-05 (....) ## 2010-03-04 Slight adaptations in texinfo +## 2010-05-31 Updated help text (delays i.c.o. empty range due to getusedrange call) function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[]) Modified: trunk/octave-forge/main/io/inst/xls2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2oct.m 2010-05-31 09:29:09 UTC (rev 7368) +++ trunk/octave-forge/main/io/inst/xls2oct.m 2010-05-31 15:19:08 UTC (rev 7369) @@ -31,6 +31,9 @@ ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). +## If no range is specified the occupied cell range will have to be +## determined behind the scenes first; this can take some time for the +## Java-based interfaces. ## ## If only the first argument is specified, xls2oct will try to read ## all contents from the first = leftmost (or the only) worksheet (as @@ -94,7 +97,8 @@ ## Updates: ## 2009-01-03 (added OOXML support & cleaned up code. Excel ## ADDRESS function still not working OK) -## 2010-03-14 Updated help text +## 2010-03-14 Updated help text +## 2010-05-31 Updated help text (delay i.c.o. empty range due to getusedrange call) function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh, datrange='') Modified: trunk/octave-forge/main/io/inst/xlsread.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsread.m 2010-05-31 09:29:09 UTC (rev 7368) +++ trunk/octave-forge/main/io/inst/xlsread.m 2010-05-31 15:19:08 UTC (rev 7369) @@ -40,6 +40,9 @@ ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). +## If no range is specified the occupied cell range will have to be +## determined behind the scenes first; this can take some time for the +## Java-based interfaces. ## ## @var{wsh} is either numerical or text, in the latter case it is ## case-sensitive and it may be max. 31 characters long. @@ -118,6 +121,7 @@ ## Updates: ## 2009-12-29 bug fixes ## 2010-01-12 added unwind_protect to get rid of stray Excel invocations i.c.o. COM errors +## 2010-05-31 Updated help text (delays i.c.o. empty range due to getusedrange call) function [ numarr, txtarr, rawarr, lims ] = xlsread (fn, wsh, datrange, reqintf=[]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-05-31 15:21:33
|
Revision: 7370 http://octave.svn.sourceforge.net/octave/?rev=7370&view=rev Author: prnienhuis Date: 2010-05-31 15:21:26 +0000 (Mon, 31 May 2010) Log Message: ----------- Added remark in help text about some delays when results are echoed to screen. These delays are due to exploring the occupied data range which can take a long time for big spreadsheets esp. for ODS. Modified Paths: -------------- trunk/octave-forge/main/io/inst/odsfinfo.m trunk/octave-forge/main/io/inst/xlsfinfo.m Modified: trunk/octave-forge/main/io/inst/odsfinfo.m =================================================================== --- trunk/octave-forge/main/io/inst/odsfinfo.m 2010-05-31 15:19:08 UTC (rev 7369) +++ trunk/octave-forge/main/io/inst/odsfinfo.m 2010-05-31 15:21:26 UTC (rev 7370) @@ -30,8 +30,9 @@ ## to right) in which they occur in the sheet stack. ## ## If you omit return arguments @var{filetype} and @var{sh_names} altogether, -## odsfinfo returns the sheet names + (in case of the ODF toolkit interface) -## a qualified guess for the actual occupied data range to the screen. +## odsfinfo returns the sheet names and for each sheet the actual occupied +## data ranges to the screen.The occupied cell range will have to be +## determined behind the scenes first; this can take some time. ## ## odsfinfo execution can take its time for large spreadsheets as the entire ## spreadsheet has to be parsed to get the sheet names, let alone exploring @@ -68,6 +69,7 @@ ## 2010-03-18 Separated range exploration (for OTK only yet) in separate function file ## 2010-03-20 "Beautified" output (for OTK ), used range now in more tabular form ## 2010-05-23 Updated jOpenDocument support (can also get occupied data range now) +## 2010-05-31 Added remark about delays when determining occupied data range function [ filetype, sheetnames ] = odsfinfo (filename, reqintf=[]) Modified: trunk/octave-forge/main/io/inst/xlsfinfo.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsfinfo.m 2010-05-31 15:19:08 UTC (rev 7369) +++ trunk/octave-forge/main/io/inst/xlsfinfo.m 2010-05-31 15:21:26 UTC (rev 7370) @@ -37,7 +37,9 @@ ## ## If no return arguments are specified the sheet names are echoed to the ## terminal screen; in case of java interfaces for each sheet the actual -## occupied data range is echoed as well. +## occupied data range is echoed as well. The occupied cell range will have +## to be determined behind the scenes first; this can take some time for the +## Java-based interfaces. ## ## If multiple xls interfaces have been installed @var{reqintf} can be ## specified. This can sometimes be handy to get an idea of used cell ranges @@ -69,6 +71,7 @@ ## 2009-01-01 Echo sheet names to screen, request interface type) ## 2010-03-21 Better tabulated output; occupied date range per sheet echoed ## for Java interfaces (though it may be a bit off in case of JXL) +## 2010-05-31 Added remark about delays when determining occupied data range function [ filetype, sh_names, fformat ] = xlsfinfo (filename, reqintf=[]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-08-03 21:25:03
|
Revision: 7493 http://octave.svn.sourceforge.net/octave/?rev=7493&view=rev Author: prnienhuis Date: 2010-08-03 21:24:56 +0000 (Tue, 03 Aug 2010) Log Message: ----------- Added support for entering formulas, either as text or as literal text strings depending on a new option argument. Based on patch suggested by Benjamin Lindner Modified Paths: -------------- trunk/octave-forge/main/io/inst/oct2ods.m trunk/octave-forge/main/io/inst/oct2xls.m Modified: trunk/octave-forge/main/io/inst/oct2ods.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2ods.m 2010-07-30 21:20:49 UTC (rev 7492) +++ trunk/octave-forge/main/io/inst/oct2ods.m 2010-08-03 21:24:56 UTC (rev 7493) @@ -18,6 +18,7 @@ ## @deftypefn {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}) ## @deftypefnx {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}, @var{wsh}) ## @deftypefnx {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}, @var{wsh}, @var{range}) +## @deftypefnx {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}, @var{wsh}, @var{range}, @var(options)) ## ## Transfer data to an OpenOffice_org Calc spreadsheet previously opened ## by odsopen(). @@ -43,14 +44,24 @@ ## inserted to the right of all existing sheets. The pointer to the ## "active" sheet (shown when Calc opens the file) remains untouched. ## -## If omitted, @var{range} is initially supposed to be 'A1:AMJ65536'. -## The actual range to be used is determined by the size of @var{arr}. +## If omitted, @var{range} is initially supposed to be 'A1:AMJ65536'; +## only a top left cell address can be specified as well. In these cases +## the actual range to be used is determined by the size of @var{arr}. ## Be aware that data array sizes > 2.10^5 elements may exhaust the ## java shared memory space for the default java memory settings. ## For larger arrays appropriate memory settings are needed in the file ## java.opts; then the maximum array size for the java-based spreadsheet ## options is about 5-6.10^5 elements. ## +## Optional argument @var{options}, a structure, can be used to specify +## various write modes. +## Currently the only option field is "formulas_as_text", which -if set +## to 1 or TRUE- specifies that formula strings (i.e., text strings +## starting with "=" and ending in a ")" ) should be entered as litteral +## text strings rather than as spreadsheet formulas (the latter is the +## default). As jOpenDocument doesn't support formula I/O at all yet, +## this option is ignored for the JOD interface. +## ## Data are added to the sheet, ignoring other data already present; ## existing data in the range to be used will be overwritten. ## @@ -62,9 +73,15 @@ ## Examples: ## ## @example -## [ods, status] = ods2oct ('arr', ods, 'Newsheet1', 'AA31:GH165'); +## [ods, status] = ods2oct (arr, ods, 'Newsheet1', 'AA31:GH165'); +## Write array arr into sheet Newsheet1 with upperleft cell at AA31 ## @end example ## +## @example +## [ods, status] = ods2oct ({'String'}, ods, 'Oldsheet3', 'B15:B15'); +## Put a character string into cell B15 in sheet Oldsheet3 +## @end example +## ## @seealso ods2oct, odsopen, odsclose, odsread, odswrite, odsfinfo ## ## @end deftypefn @@ -78,18 +95,24 @@ ## 2010-03-28 Added basic support for ofdom v.0.8. Everything works except adding cols/rows ## 2010-03-29 Removed odfdom-0.8 support, it's simply too buggy :-( Added a warning instead ## 2010-06-01 Almost complete support for upcoming jOpenDocument 1.2b4. 1.2b3 still lacks a bit +## 2010-07-05 Added example for writng character strings +## 2010-07-29 Added option for entering / reading back spreadsheet formulas ## -## Last update of subfunctions below: 2010-06-01 +## Last update of subfunctions below: 2010-08-01 -function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange=[]) +function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange=[], spsh_opts=[]) + if isempty (spsh_opts) + spsh_opts.formulas_as_text = 0; + # Other options here + endif + if (strcmp (ods.xtype, 'OTK')) # Write ods file tru Java & ODF toolkit. - [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh, crange); + [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh, crange, spsh_opts); elseif (strcmp (ods.xtype, 'JOD')) # Write ods file tru Java & jOpenDocument. API still leaves lots to be wished... -# warning ("oct2ods: unreliable writing tru jOpenDocument interface."); [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh, crange); # elseif ---- < Other interfaces here > @@ -142,19 +165,23 @@ ## 2010-04-11 Changed all references to "cell" to "scell" to avoid reserved keyword ## Small bugfix for cases with empty left columns (wrong cell reference) ## 2010-04-13 Fixed bug with stray cell copies beyond added data rectangle +## 2010-07-29 Added formula input support (based on xls patch by Benjamin Lindner) +## 2010-08-01 Added try-catch around formula input +## " Changed range arg to also allow just topleft cell +## 2010-08-03 Moved range checks and type array parsing to separate functions -function [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh=1, crange=[]) +function [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh, crange, spsh_opts) persistent ctype; if (isempty (ctype)) - # Number, String, Boolean, Date, Time, Empty - ctype = [1, 2, 3, 4, 5, 6]; + # Number, Boolean, String, Formula, Empty, Date, Time + ctype = [1, 2, 3, 4, 5, 6, 7]; endif - rstatus = 0; changed = 0; + rstatus = 0; changed = 0; f_errs = 0; - # ODS' current row and column capacity - ROW_CAP = 65536; COL_CAP = 1024; +# # ODS' current row and column capacity +# ROW_CAP = 65536; COL_CAP = 1024; if (isnumeric (c_arr)) c_arr = num2cell (c_arr); @@ -206,54 +233,22 @@ endif # Check size of data array & range / capacity of worksheet & prepare vars - [nr, nc] = size (c_arr); - if (isempty (crange)) - trow = 0; - lcol = 0; - nrows = nr; - ncols = nc; - else - [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); - # Row/col = 0 based in ODFtoolkit - trow = trow - 1; lcol = lcol - 1; + [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, ods.xtype, ods.filename); + --trow; --lcol; # Zero-based row # & col # + if (nrows < nr || ncols < nc) + warning ("Array truncated to fit in range"); + obj = obj(1:nrows, 1:ncols); endif - if (trow > ROW_CAP || lcol > COL_CAP) - celladd = calccelladdress (lcol, trow, 1, 1); - error (sprintf ("Topleft cell (%s) beyond spreadsheet limits (AMJ65536).", celladd)); - endif - # Check spreadsheet capacity beyond requested topleft cell - nrows = min (nrows, ROW_CAP - trow + 1); - ncols = min (ncols, COL_CAP - lcol + 1); - # Check array size and requested range - nrows = min (nrows, nr); - ncols = min (ncols, nc); - if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); endif # Parse data array, setup typarr and throw out NaNs to speed up writing; -# 1Number, 2String, 3Boolean, 4Date, 5Time, 0Empty + typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts, 0); + if ~(spsh_opts.formulas_as_text) + # Find formulas (designated by a string starting with "=" and ending in ")") + fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), c_arr); + typearr(fptr) = ctype(4); # FORMULA + endif - typearr = ones (nrows, ncols); # type "NUMERIC", provisionally - obj2 = cell (size (c_arr)); # Temporary storage for strings - - txtptr = cellfun ('isclass', c_arr, 'char'); # type "STRING" replaced by "NUMERIC" - obj2(txtptr) = c_arr(txtptr); c_arr(txtptr) = 2;# Save strings in a safe place - - emptr = cellfun ("isempty", c_arr); - c_arr(emptr) = 0; # Set empty cells to NUMERIC - - lptr = cellfun ("islogical" , c_arr); # Find logicals... - obj2(lptr) = c_arr(lptr); # .. and set them to BOOLEAN - - ptr = cellfun ("isnan", c_arr); # Find NaNs & set to BLANK - typearr(ptr) = 0; # All other cells are now numeric - - c_arr(txtptr) = obj2(txtptr); # Copy strings back into place - c_arr(lptr) = obj2(lptr); - typearr(txtptr) = 2; # ...and clean up - typearr(emptr) = 0; - typearr(lptr) = 3; # BOOLEAN - # Prepare worksheet for writing. If needed create new sheet if (newsh) @@ -486,18 +481,16 @@ scell.removeChild (tmp); changed = 1; endwhile + scell.removeAttribute ('table:formula'); endif + # Empty cell count stuff done. At last we can add the data switch (typearr (ii, jj)) case 1 # float scell.setOfficeValueTypeAttribute ('float'); scell.setOfficeValueAttribute (c_arr{ii, jj}); - case 2 # string - scell.setOfficeValueTypeAttribute ('string'); - pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', c_arr{ii, jj}); - scell.appendChild (pe); - case 3 # boolean - # Beware, for unpatched-for-booleans java-1.2.7 we must resort to floats + case 2 # boolean + # Beware, for unpatched-for-booleans java-1.2.7- we must resort to floats try # First try the preferred java-boolean way scell.setOfficeValueTypeAttribute ('boolean'); @@ -516,21 +509,42 @@ scell.setOfficeValueAttribute (0); endif end_try_catch - case 4 # Date (implemented but Octave has no "date" data type - yet?) + case 3 # string + scell.setOfficeValueTypeAttribute ('string'); + pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', c_arr{ii, jj}); + scell.appendChild (pe); + case 4 # Formula. + # As we don't know the result type, simply remove previous type info. + # Once OOo Calc reads it, it'll add the missing attributes + scell.removeAttribute ('office:value'); + scell.removeAttribute ('office:value-type'); + # Try-catch not strictly needed, there's no formula validator yet + try + scell.setTableFormulaAttribute (c_arr{ii, jj}); + scell.setOfficeValueTypeAttribute ('string'); + pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', '#Recalc Formula#'); + scell.appendChild (pe); + catch + ++f_errs; + scell.setOfficeValueTypeAttribute ('string'); + pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', c_arr{ii, jj}); + scell.appendChild (pe); + end_try_catch + case {0 5} # Empty. Clear value attributes + if (~newsh) + scell.removeAttribute ('office:value-type'); + scell.removeAttribute ('office:value'); + endif + case 6 # Date (implemented but Octave has no "date" data type - yet?) scell.setOfficeValueTypeAttribute ('date'); [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); str = sprintf ("%4d-%2d-%2dT%2d:%2d:%2d", yy, mo, dd, hh, mi, ss); scell.setOfficeDateValueAttribute (str); - case 5 # Time (implemented but Octave has no "time" data type) + case 7 # Time (implemented but Octave has no "time" data type) scell.setOfficeValueTypeAttribute ('time'); [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); str = sprintf ("PT%2d:%2d:%2d", hh, mi, ss); scell.setOfficeTimeValuettribute (str); - case 0 # Empty. Clear value attributes - if (~newsh) - scell.removeAttribute ('office:value-type'); - scell.removeAttribute ('office:value'); - endif otherwise # Nothing endswitch @@ -544,6 +558,9 @@ endfor + if (f_errs) + printf ("%d formula errors encountered - please check input array\n", f_errs); + endif if (changed) ods.changed = 1; rstatus = 1; @@ -588,8 +605,10 @@ ## " Added check for jOpenDocument version. Adding sheets only works for ## 1.2b3+ (barring bug above) ## 2010-06-02 Fixed first sheet remaining in new spreadsheets +## 2010-08-01 Added option for crange to be only topleft cell address +## " Code cleanup -function [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh=1, crange=[]) +function [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh, crange) # Check jOpenDocument version sh = ods.workbook.getSheet (0); @@ -652,6 +671,12 @@ lcol = 0; nrows = nr; ncols = nc; + elseif (isempty (strfind (deblank (crange), ':'))) + [dummy1, dummy2, dummy3, trow, lcol] = parse_sp_range (crange); + nrows = nr; + ncols = nc; + # Row/col = 0 based in jOpenDocument + trow = trow - 1; lcol = lcol - 1; else [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); # Row/col = 0 based in jOpenDocument @@ -659,8 +684,7 @@ endif if (trow > 65535 || lcol > 1023) - celladd = calccelladdress (lcol + 1, trow + 1); - error (sprintf ("Topleft cell (%s) beyond spreadsheet limits (AMJ65536).", celladd)); + error ("Topleft cell beyond spreadsheet limits (AMJ65536)."); endif # Check spreadsheet capacity beyond requested topleft cell nrows = min (nrows, 65536 - trow); # Remember, lcol & trow are zero-based Modified: trunk/octave-forge/main/io/inst/oct2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2xls.m 2010-07-30 21:20:49 UTC (rev 7492) +++ trunk/octave-forge/main/io/inst/oct2xls.m 2010-08-03 21:24:56 UTC (rev 7493) @@ -17,10 +17,11 @@ ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}) ## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}) -## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}, @var{topleft}) +## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}, @var{range}) +## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}, @var{range}, @var{options}) ## -## Add data in 1D/2D CELL array @var{arr} into a range with upper left -## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel +## Add data in 1D/2D CELL array @var{arr} into a range specified +## in @var{topleft} in worksheet @var{wsh} in an Excel ## spreadsheet file pointed to in structure @var{xls}. ## Return argument @var{xls} equals supplied argument @var{xls} and is ## updated by oct2xls. @@ -44,8 +45,9 @@ ## inserted to the right of all existing worksheets. The pointer to the ## "active" sheet (shown when Excel opens the file) remains untouched. ## -## If omitted, @var{topleft} is supposed to be 'A1'. The actual range to -## be used is determined by the size of @var{arr}. +## If @var{range} is omitted or if only a topleft cell address is specified, +## the topleft cell of @var{range} is supposed to be 'A1' and the actual +## range to be used is determined by the size of @var{arr}. ## ## Data are added to the worksheet, ignoring other data already present; ## existing data in the range to be used will be overwritten. @@ -55,6 +57,14 @@ ## will be written, other array cells corresponding to that cell will be ## ignored. ## +## Optional argument @var{options}, a structure, can be used to specify +## various write modes. +## Currently the only option field is "formulas_as_text", which -if set +## to 1 or TRUE- specifies that formula strings (i.e., text strings +## starting with "=" and ending in a ")" ) should be entered as litteral +## text strings rather than as spreadsheet formulas (the latter is the +## default). +## ## Beware that -if invoked- Excel invocations may be left running silently ## in case of COM errors. Invoke xlsclose with proper pointer struct to ## close them. @@ -67,7 +77,7 @@ ## Examples: ## ## @example -## [xlso, status] = xls2oct ('arr', xlsi, 'Third_sheet', 'AA31'); +## [xlso, status] = xls2oct ('arr', xlsi, 'Third_sheet', 'AA31:AB278'); ## @end example ## ## @seealso xls2oct, xlsopen, xlsclose, xlsread, xlswrite, xlsfinfo @@ -79,26 +89,38 @@ ## Updates: ## 2010-01-03 (OOXML support) ## 2010-03-14 Updated help text section on java memory usage +## 2010-07-27 Added formula writing support (based on patch by Benjamin Lindner) +## 2010-08-01 Added check on input array size vs. spreadsheet capacity +## " Changed argument topleft into range (now compatible with ML); the +## " old argument version (just topleft cell) is still recognized, though -function [ xls, rstatus ] = oct2xls (obj, xls, wsh, topleft='A1') +function [ xls, rstatus ] = oct2xls (obj, xls, wsh, crange=[], spsh_opts=[]) + # Make sure input array is a cell array if (isnumeric (obj)) obj = num2cell (obj); elseif (ischar (obj)) obj = {obj}; endif + # Various options + if isempty (spsh_opts) + spsh_opts.formulas_as_text = 0; + # other options to be implemented here + endif + + # Select interface to be used if (strcmp (xls.xtype, 'COM')) # Call oct2com2xls to do the work - [xls, rstatus] = oct2com2xls (obj, xls, wsh, topleft); + [xls, rstatus] = oct2com2xls (obj, xls, wsh, crange, spsh_opts); elseif (strcmp (xls.xtype, 'POI')) # Invoke Java and Apache POI - [xls, rstatus] = oct2jpoi2xls (obj, xls, wsh, topleft); + [xls, rstatus] = oct2jpoi2xls (obj, xls, wsh, crange, spsh_opts); elseif (strcmp (xls.xtype, 'JXL')) # Invoke Java and JExcelAPI - [xls, rstatus] = oct2jxla2xls (obj, xls, wsh, topleft); + [xls, rstatus] = oct2jxla2xls (obj, xls, wsh, crange, spsh_opts); # elseif (strcmp'xls.xtype, '<whatever>')) # <Other Excel interfaces> @@ -160,10 +182,15 @@ ## 2010-01-12 Fixed typearr sorting out (was only 1-dim & braces rather than parens)) ## Set cells corresponding to empty array cells empty (cf. Matlab) ## 2010-01-13 Removed an extraneous statement used for debugging -## FIXMEs added (array size vs. spreadsheet size in java based subfunctions); ## I plan look at it when octave v.3.4 is about to arrive. +## 2010-08-01 Added checks for input array size vs check on capacity +## " Changed topleft arg into range arg (just topleft still recognized) +## " Some code cleanup +## " Added option for formula input as text string +## 2010-08-01 Added range vs. array size vs. capacity checks +## 2010-08-03 Moved range checks and type array parsing to separate functions -function [ xls, status ] = oct2com2xls (obj, xls, wsh, top_left_cell='A1') +function [ xls, status ] = oct2com2xls (obj, xls, wsh, crange, spsh_opts) # define some constants not yet in __COM__.cc xlWorksheet = -4167; # xlChart= 4; @@ -175,8 +202,8 @@ if (nargin < 2) error ("oct2com2xls needs a minimum of 2 arguments."); endif if (nargin == 2) wsh = 1; endif if (~iscell (obj)) error ("Cell array expected as input argument"); endif - if (~strcmp (tolower (xls.filename(end-3:end)), '.xls')) - error ("oct2com2xls can only write to Excel .xls files") + if (~strmatch (tolower (xls.filename(end-4:end)), '.xls')) + error ("oct2com2xls can only write to Excel .xls or .xlsx files") endif if (isnumeric (wsh)) if (wsh < 1) error ("Illegal worksheet number: %i\n", wsh); endif @@ -188,6 +215,7 @@ rstatus = 1; return; endif + # Check xls file pointer struct test1 = ~isfield (xls, "xtype"); test1 = test1 || ~isfield (xls, "workbook"); test1 = test1 || ~strcmp (char (xls.xtype), 'COM'); @@ -196,26 +224,30 @@ if test1 error ("Invalid file pointer struct"); endif + + # Parse date ranges + [nr, nc] = size (obj); + [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); + if (nrows < nr || ncols < nc) + warning ("Array truncated to fit in range"); + obj = obj(1:nrows, 1:ncols); + endif - # Cleanup NaNs. Start with backing up strings, empty & boolean cells, - # then set text cells to 0 - obj2 = cell (size (obj)); - txtptr = cellfun ('isclass', obj, 'char'); - if (any (any (txtptr))) obj2(txtptr) = obj(txtptr); obj(txtptr) = 0; endif - eptr = cellfun ('isempty', obj); - if (any (any (eptr))) obj(eptr) = 0; endif - lptr = cellfun ("islogical" , obj); - if (any (any (lptr))) obj2(lptr) = obj(lptr); obj(lptr) = 0; endif + # Cleanup NaNs. Find where they are and mark as empty + ctype = [0 1 2 3 4]; # Numeric Boolean Text Formula Empty + typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); + # Make cells now indicated to be empty, empty + fptr = ~(4 * (ones (size (typearr))) .- typearr); + obj(fptr) = cellfun(@(x) [], obj(fptr), "Uniformoutput", false); - ptr = cellfun ("isnan", obj); - if (any (any (ptr))) obj{ptr} = []; endif + if (spsh_opts.formulas_as_text) + # find formulas (designated by a string starting with "=" and ending in ")") + fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), obj); + # ... and add leading "'" character + obj(fptr) = cellfun (@(x) ["'" x], obj(fptr), "Uniformoutput", false); + endif + clear fptr; - # Restore text, empty cells & booleans - if (any (any (txtptr))) obj(txtptr) = obj2(txtptr); endif - if (any (any (lptr))) obj(lptr) = obj2(lptr); endif - if (any (any (eptr))) obj(eptr) = {[]}; endif - clear obj2 txtptr eptr lptr ptr; - if (xls.changed < 2) # Existing file. Some involved investigation is needed to preserve # existing data that shouldn't be touched. @@ -311,7 +343,7 @@ # MG's original part. # Save object in Excel sheet, starting at cell top_left_cell if (~isempty(obj)) - r = sh.Range (top_left_cell); + r = sh.Range (topleft); r = r.Resize (size (obj, 1), size (obj, 2)); r.Value = obj; delete (r); @@ -344,7 +376,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls ( @var{arr}, @var{xlsi}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}) -## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{topleft}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options}) ## ## Add data in 1D/2D CELL array @var{arr} into a range with upper left ## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel @@ -372,22 +405,25 @@ ## 2010-03-08 Dumped formula evaluator for booleans. Not being able to ## write booleans was due to a __java__.oct deficiency (see ## http://sourceforge.net/mailarchive/forum.php?thread_name=4B59A333.5060302%40net.in.tum.de&forum_name=octave-dev ) +## 2010-07-27 Added formula writing support (based on patch by Benjamin Lindner) +## 2010-08-01 Improved try-catch for formulas to enter wrong formulas as text strings +## 2010-08-01 Added range vs. array size vs. capacity checks +## 2010-08-03 Moved range checks and type array parsingto separate functions -function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, topleftcell="A1") +function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, crange, spsh_opts) persistent ctype; if (isempty (ctype)) # Get cell types. Beware as they start at 0 not 1 - ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); - ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); - ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); - ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); - ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BOOLEAN'); - ctype(6) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_ERROR'); + ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); # 0 + ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BOOLEAN'); # 4 + ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); # 1 + ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); # 2 + ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); # 3 endif # scratch vars - rstatus = 0; changed = 1; + rstatus = 0; changed = 1; f_errs = 0; # Preliminary sanity checks if (isempty (obj)) @@ -399,9 +435,10 @@ endif if (nargin < 2) error ("oct2jpoi2xls needs a minimum of 2 arguments."); endif if (nargin == 2) wsh = 1; endif - if (~strmatch(tolower(xls.filename(end-4:end)), '.xls')) + if (~strmatch (tolower (xls.filename(end-4:end)), '.xls')) error ("oct2jpoi2xls can only write to Excel .xls or .xlsx files") endif + # Check if xls struct pointer seems valid test1 = ~isfield (xls, "xtype"); test1 = test1 || ~isfield (xls, "workbook"); @@ -411,7 +448,7 @@ if test1 error ("Invalid xls file struct"); endif # Check if requested worksheet exists in the file & if so, get pointer - nr_of_sheets = xls.workbook.getNumberOfSheets(); + nr_of_sheets = xls.workbook.getNumberOfSheets (); if (isnumeric (wsh)) if (wsh > nr_of_sheets) # Watch out as a sheet called Sheet%d can exist with a lower index... @@ -426,10 +463,10 @@ else sh = xls.workbook.getSheetAt (wsh - 1); # POI sheet count 0-based endif - printf ("(Writing to worksheet %s)\n", sh.getSheetName()); + printf ("(Writing to worksheet %s)\n", sh.getSheetName ()); else sh = xls.workbook.getSheet (wsh); - if (isempty(sh)) + if (isempty (sh)) # Sheet not found, just create it sh = xls.workbook.createSheet (wsh); xls.changed = 2; @@ -438,53 +475,54 @@ # Beware of strings variables interpreted as char arrays; change them to cell. if (ischar (obj)) obj = {obj}; endif - - [topleft, nrows, ncols, trow, lcol] = parse_sp_range (topleftcell); - [nrows, ncols] = size (obj); - - ## FIXME Check on max spreadsheet size vs. max data array size needed + # Parse date ranges + [nr, nc] = size (obj); + [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); + if (nrows < nr || ncols < nc) + warning ("Array truncated to fit in range"); + obj = obj(1:nrows, 1:ncols); + endif + # Prepare type array - typearr = ctype(4) * ones (nrows, ncols); # type "BLANK", provisionally - obj2 = cell (size (obj)); # Temporary storage for strings + typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); + if ~(spsh_opts.formulas_as_text) + # Remove leading '=' from formula strings + fptr = ~(2 * (ones (size (typearr))) .- typearr); + obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false); + endif - txtptr = cellfun ('isclass', obj, 'char'); # type "STRING" replaced by "NUMERIC" - obj2(txtptr) = obj(txtptr); obj(txtptr) = ctype(1); # Save strings in a safe place + # Create formula evaluator + frm_eval = xls.workbook.getCreationHelper ().createFormulaEvaluator (); - emptr = cellfun ("isempty", obj); - obj(emptr) = ctype(1); # Set empty cells to NUMERIC - - lptr = cellfun ("islogical" , obj); # Find logicals... - obj2(lptr) = obj(lptr); # .. and set them to BOOLEAN - - ptr = cellfun ("isnan", obj); # Find NaNs & set to BLANK - typearr(ptr) = ctype(4); typearr(~ptr) = ctype(1); # All other cells are now numeric - - obj(txtptr) = obj2(txtptr); # Copy strings back into place - obj(lptr) = obj2(lptr); - - typearr(txtptr) = ctype(2); # ...and clean up - typearr(emptr) = ctype(4); - typearr(lptr) = ctype(5); # BOOLEAN, temp NUMERIC - - # Create formula evaluator (needed to be able to write boolean values!) - # frm_eval = xls.workbook.getCreationHelper ().createFormulaEvaluator (); - for ii=1:nrows ll = ii + trow - 2; # Java POI's row count = 0-based row = sh.getRow (ll); if (isempty (row)) row = sh.createRow (ll); endif for jj=1:ncols kk = jj + lcol - 2; # POI's column count is also 0-based - if (typearr(ii, jj) == ctype(4)) - cell = row.createCell (kk, ctype(4)); + if (typearr(ii, jj) == ctype(5)) # Empty cells + cell = row.createCell (kk, ctype(5)); + elseif (typearr(ii, jj) == ctype(4)) # Formulas + # Try-catch needed as there's no guarantee for formula correctness + try + cell = row.createCell (kk, ctype(4)); + cell.setCellFormula (obj{ii,jj}); + catch + ++f_errs; + cell.setCellType (ctype (3)); # Enter formula as text + cell.setCellValue (obj{ii, jj}); + end_try_catch else cell = row.createCell (kk, typearr(ii,jj)); cell.setCellValue (obj{ii, jj}); endif endfor endfor - + + if (f_errs) + printf ("%d formula errors encountered - please check input array\n", f_errs); + endif xls.changed = 1; rstatus = 1; @@ -511,7 +549,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls ( @var{arr}, @var{xlsi}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}) -## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{topleft}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}) +## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options}) ## ## Add data in 1D/2D CELL array @var{arr} into a range with upper left ## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel @@ -537,17 +576,24 @@ ## 2009-12-11 ## 2010-01-12 Fixed skipping empty array values (now Excel-conformant => cell cleared) ## Added xls.changed = 1 statement to signal successful write +## 2010-07-27 Added formula writing support (based on POI patch by Benjamin Lindner) +## Added check for valid file pointer struct +## 2010-08-01 Improved try-catch for formulas to enter wrong formulas as text strings +## 2010-08-01 Added range vs. array size vs. capacity checks +## " Code cleanup +## " Changed topleft arg into range arg (topleft version still recognized) +## 2010-08-03 Moved range checks and cell type parsing to separate routines -function [ xls, rstatus ] = oct2jxla2xls (obj, xls, wsh, topleftcell="A1") +function [ xls, rstatus ] = oct2jxla2xls (obj, xls, wsh, crange, spsh_opts) persistent ctype; if (isempty (ctype)) ctype = [1, 2, 3, 4, 5]; - # Boolean, Number, String, NaN, Empty + # Number, Boolean, String, Formula, Empty endif # scratch vars - rstatus = 0; changed = 1; + rstatus = 0; changed = 1; f_errs = 0; # Preliminary sanity checks if (isempty (obj)) @@ -559,9 +605,17 @@ endif if (nargin < 2) error ("oct2java2xls needs a minimum of 2 arguments."); endif if (nargin == 2) wsh = 1; endif - if (~strmatch(tolower(xls.filename(end-4:end)), '.xls')) # FIXME for OOXML + if (~strmatch (tolower (xls.filename(end-4:end)), '.xls')) # No OOXML in JXL error ("oct2java2xls can only write to Excel .xls files") endif + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || ~strcmp (char (xls.xtype), 'JXL'); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if test1 + error ("Invalid file pointer struct"); + endif # Prepare workbook pointer if needed if (xls.changed < 2) @@ -575,7 +629,7 @@ endif # Check if requested worksheet exists in the file & if so, get pointer - nr_of_sheets = xls.workbook.getNumberOfSheets(); # 1 based !! + nr_of_sheets = xls.workbook.getNumberOfSheets (); # 1 based !! if (isnumeric (wsh)) if (wsh > nr_of_sheets) # Watch out as a sheet called Sheet%d can exist with a lower index... @@ -590,7 +644,7 @@ else sh = wb.getSheet (wsh - 1); # POI sheet count 0-based endif - shnames = char(wb.getSheetNames ()); + shnames = char (wb.getSheetNames ()); printf ("(Writing to worksheet %s)\n", shnames {nr_of_sheets, 1}); else sh = wb.getSheet (wsh); @@ -604,50 +658,52 @@ # Beware of strings variables interpreted as char arrays; change them to cell. if (ischar (obj)) obj = {obj}; endif - - [topleft, nrows, ncols, trow, lcol] = parse_sp_range (topleftcell); - [nrows, ncols] = size (obj); - ## FIXME check on spreadsheet size vs. data array size needed + # Parse date ranges + [nr, nc] = size (obj); + [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); + if (nrows < nr || ncols < nc) + warning ("Array truncated to fit in range"); + obj = obj(1:nrows, 1:ncols); + endif - # Prepare type array to speed up writing - typearr = 5 * ones (nrows, ncols); # type "EMPTY", provisionally - obj2 = cell (size (obj)); # Temporary storage for strings + # Prepare type array + typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); + if ~(spsh_opts.formulas_as_text) + # Remove leading '=' from formula strings + fptr = ~(4 * (ones (size (typearr))) .- typearr); + obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false); + endif + clear fptr - txtptr = cellfun ('isclass', obj, 'char'); # type "STRING" replaced by "NUMERIC" - obj2(txtptr) = obj(txtptr); obj(txtptr) = 3; # Save strings in a safe place - - emptr = cellfun ("isempty", obj); - obj(emptr) = 5; # Set empty cells to NUMERIC - - lptr = cellfun ("islogical" , obj); # Find logicals... - obj2(lptr) = obj(lptr); # .. and set them to BOOLEAN - - ptr = cellfun ("isnan", obj); # Find NaNs & set to BLANK - typearr(ptr) = 4; typearr(~ptr) = 2; # All other cells are now numeric - - obj(txtptr) = obj2(txtptr); # Copy strings back into place - obj(lptr) = obj2(lptr); - typearr(txtptr) = 3; # ...and clean up - typearr(emptr) = 5; - typearr(lptr) = 1; # BOOLEAN - # Write date to worksheet for ii=1:nrows ll = ii + trow - 2; # Java JExcelAPI's row count = 0-based for jj=1:ncols kk = jj + lcol - 2; # JExcelAPI's column count is also 0-based switch typearr(ii, jj) - case 1 # Boolean + case 1 # Numerical + tmp = java_new ('jxl.write.Number', kk, ll, obj{ii, jj}); + sh.addCell (tmp); + case 2 # Boolean tmp = java_new ('jxl.write.Boolean', kk, ll, obj{ii, jj}); sh.addCell (tmp); - case 2 # Numerical - tmp = java_new ('jxl.write.Number', kk, ll, obj{ii, jj}); - sh.addCell (tmp); case 3 # String tmp = java_new ('jxl.write.Label', kk, ll, obj{ii, jj}); sh.addCell (tmp); - case {4, 5} + case 4 # Formula + # First make sure formula functions are all uppercase + obj{ii, jj} = toupper (obj{ii, jj}); + # There's no guarantee for formula correctness, so.... + try # Actually JExcelAPI flags formula errors as warnings :-( + tmp = java_new ('jxl.write.Formula', kk, ll, obj{ii, jj}); + catch + ++f_errs; + # Formula error. Enter formula as text string instead + tmp = java_new ('jxl.write.Label', kk, ll, obj{ii, jj}); + end_try_catch + sh.addCell (tmp); + case 5 # Empty or NaN tmp = java_new ('jxl.write.Blank', kk, ll); sh.addCell (tmp); otherwise @@ -656,8 +712,10 @@ endfor endfor + if (f_errs) + printf ("%d formula errors encountered - please check input array\n", f_errs); + endif xls.changed = 1; rstatus = 1; endfunction - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-08-03 21:27:42
|
Revision: 7494 http://octave.svn.sourceforge.net/octave/?rev=7494&view=rev Author: prnienhuis Date: 2010-08-03 21:27:35 +0000 (Tue, 03 Aug 2010) Log Message: ----------- Support for reading back formulas as literal text strings. This works only for POI, JXL (.xls) and OTK (.ods) interfaces. Neither COM nor JOD support this :-) Also some more code cleanup Modified Paths: -------------- trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/xls2oct.m Modified: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m 2010-08-03 21:24:56 UTC (rev 7493) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2010-08-03 21:27:35 UTC (rev 7494) @@ -18,6 +18,7 @@ ## @deftypefn {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}, @var{range}) +## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}, @var{range}, @var{options}) ## ## Read data contained within range @var{range} from worksheet @var{wsh} ## in an OpenOffice.org spreadsheet file pointed to in struct @var{ods}. @@ -37,6 +38,13 @@ ## If no range is specified the occupied cell range will have to be ## determined behind the scenes first; this can take some time. ## +## Optional argument @var{options}, a structure, can be used to +## specify various read modes. Currently the only option field is +## "formulas_as_text"; if set to TRUE or 1, spreadsheet formulas +## (if at all present) are read as formula strings rather than the +## evaluated formula result values. This only works for the OTK (Open +## Document Toolkit) interface. +## ## If only the first argument is specified, ods2oct will try to read ## all contents from the first = leftmost (or the only) worksheet (as ## if a range of @'' (empty string) was specified). @@ -97,15 +105,22 @@ ## So I added a warning for users using odfdom 0.8. ## 2010-04-11 Removed support for odfdom-0.8 - it's painfully slow and unreliable ## 2010-05-31 Updated help text (delay i.c.o. empty range due to getusedrange call) -## 2010-05-31 Added support for jOpenDocument 1.2b3; improved this subfunc a lot +## 2010-08-03 Added support for reading back formulas (works only in OTK) ## -## (Latest update of subfunctions below: 2010-05-31) +## (Latest update of subfunctions below: 2010-08-03) -function [ rawarr, ods, rstatus ] = ods2oct (ods, wsh=1, datrange=[]) +function [ rawarr, ods, rstatus ] = ods2oct (ods, wsh=1, datrange=[], spsh_opts=[]) + persistent odf08; + + if isempty (spsh_opts) + spsh_opts.formulas_as_text = 0; + # Other options here + endif + if (strcmp (ods.xtype, 'OTK')) # Read ods file tru Java & ODF toolkit - [rawarr, ods, rstatus] = ods2jotk2oct (ods, wsh, datrange); + [rawarr, ods, rstatus] = ods2jotk2oct (ods, wsh, datrange, spsh_opts); elseif (strcmp (ods.xtype, 'JOD')) [rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, datrange); @@ -151,8 +166,9 @@ ## "" Tamed down memory usage for rawarr when desired data range is given ## "" Added call to getusedrange() for cases when no range was specified ## 2010-03-19 More code cleanup & fixes for bugs introduced 18/3/2010 8-() +## 2010-08-03 Added preliminary support for reading back formulas as text strings -function [ rawarr, ods, rstatus ] = ods2jotk2oct (ods, wsh=1, crange = []) +function [ rawarr, ods, rstatus ] = ods2jotk2oct (ods, wsh, crange, spsh_opts) # Parts after user gfterry in # http://www.oooforum.org/forum/viewtopic.phtml?t=69060 @@ -248,8 +264,22 @@ jj = lcol; while (jj <= rcol) tcell = row.getCellAt(jj-1); + form = 0; if (~isempty (tcell)) # If empty it's possibly in columns-repeated/spanned - if ~(index (char(tcell), 'text:p>Err:') || index (char(tcell), 'text:p>#DIV')) + if (spsh_opts.formulas_as_text) # Get spreadsheet formula rather than value + # Check for formula attribute + tmp = tcell.getTableFormulaAttribute (); + if isempty (tmp) + form = 0; + else + if (strcmp (tolower (tmp(1:3)), 'of:')) + tmp (1:end-3) = tmp(4:end); + endif + rawarr(ii-trow+2, jj-lcol+1) = tmp; + form = 1; + endif + endif + if ~(form || index (char(tcell), 'text:p>Err:') || index (char(tcell), 'text:p>#DIV')) # Get data from cell ctype = tcell.getOfficeValueTypeAttribute (); cvalue = tcell.getOfficeValueAttribute (); @@ -356,79 +386,25 @@ ## along with Octave; see the file COPYING. If not, see ## <http://www.gnu.org/licenses/>. -## ods2jod2oct - get data out of an ODS spreadsheet into octave using -## jOpenDocument. +## ods2oct - get data out of an ODS spreadsheet into octave. +## Watch out, no error checks, and spreadsheet formula error results +## are conveyed as 0 (zero). ## ## Author: Philip Nienhuis ## Created: 2009-12-13 -## Updates: -## 2010-05-31 First working updates for jopendocument v 1.2b3 -## Added getusedrange, lifted requirement of range argument -function [ rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, crange=[]) +function [ rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, crange) - persistent months; persistent ctype; + persistent months; months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; - ctype = {'FLOAT', 'STRING', 'BOOLEAN', 'DATE', 'TIME', 'EMPTY', 'CURRENCY', 'PERCENTAGE', '', ''}; - rstatus = 1 + if (isempty (crange)) error ("Empty cell range not allowed w. jOpenDocument."); endif - if (isnumeric (wsh)) - try - sh = ods.workbook.getSheet (wsh - 1); - iwsh = wsh; - catch - rstatus = 0; - error ("Sheet nr. %d out of range - only %d sheets present in file %s\n", \ - wsh, ods.workbook.getSheetCount (), ods.filename); - end_try_catch - else - sh = ods.workbook.getSheet (wsh); - if (isempty (sh)) - rstatus = 0; - error ("Sheet %s not present in file %s\n", wsh, ods.filename); - endif - if (isempty (crange)) - # In that case we need the sheet index for a call to getusedrange () - ii = 0; shcnt = ods.workbook.getSheetCount (); - while (ii < shcnt) - shname = char (ods.workbook.getSheet (ii).getName ()); - if (strcmp (shname, wsh)) - iwsh = ii + 1; - ii = shcnt; - else - ++ii; - endif - endwhile - endif - endif - - # Check jOpenDocument version - cl = sh.getCellAt (0, 0); - try - # 1.2b3 has public getValueType () - cl.getValueType () - ver = 3 - catch - # 1.2b2 has not - ver = 2 - end_try_catch - - if (isempty (crange)) - [toprow, brow, lcol, rcol] = getusedrange (ods, iwsh); - if (toprow == 0) - # Empty sheet - nrows = 0; - else - ncols = rcol - lcol + 1; - nrows = brow - toprow + 1; - endif - else - [dummy, nrows, ncols, toprow, lcol] = parse_sp_range (crange); - if (lcol > 1024 || toprow > 65536) error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); endif - brow = toprow + nrows - 1; - rcol = lcol + ncols - 1; - endif + if (isnumeric(wsh)) wsh = max (wsh - 1, 1); endif # Sheet COUNT starts at 0! + sh = ods.workbook.getSheet (wsh); + + [dummy, nrows, ncols, toprow, lcol] = parse_sp_range (crange); + if (lcol > 1024 || toprow > 65536) error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); endif # Truncate range silently if needed rcol = min (lcol + ncols - 1, 1024); ncols = min (ncols, 1024 - lcol + 1); @@ -436,123 +412,48 @@ # Placeholder for data rawarr = cell (nrows, ncols); - - # Get data from sheet - if (ver ==3) # jOpenDocument version 1.2b3 - - for ii=1:nrows - for jj = 1:ncols - cl = sh.getCellAt (jj+lcol-2, ii+toprow-2); - valtype = char (cl.getValueType ()); - if (~isempty (valtype)) - switch deblank (valtype) - case {'FLOAT', 'CURRENCY', 'PERCENTAGE'} - # Check for error values - txt = cl.getTextValue (); - if ~(strfind (txt, 'Err:') || strfind (txt, '#DIV/0')) - rawarr (ii, jj) = cl.getValue ().doubleValue (); - endif - case 'STRING' - rawarr (ii, jj) = cl.getTextValue (); - case 'BOOLEAN' - rawarr (ii, jj) = cl.getValue (); - case 'DATE' - cl = char (cl); - st = strfind (cl, 'office:date-value=') + 19; - en = strfind (cl(st:end), '">')(1) + st - 2; - cvalue = cl(st:en); - # Dates are returned as octave datenums, i.e. 0-0-0000 based - yr = str2num (cvalue(1:4)); - mo = str2num (cvalue(6:7)); - dy = str2num (cvalue(9:10)); - if (index (cvalue, 'T')) - hh = str2num (cvalue(12:13)); - mm = str2num (cvalue(15:16)); - ss = str2num (cvalue(18:19)); - rawarr(ii, jj) = datenum (yr, mo, dy, hh, mm, ss); - else - rawarr(ii, jj) = datenum (yr, mo, dy); - endif - case 'TIME' - cl = char (cl); - st = strfind (cl, 'office:time-value=') + 19; - en = strfind (cl(st:end), '">')(1) + st - 2; - cvalue = cl(st:en); - if (index (cvalue, 'PT')) - hh = str2num (cvalue(3:4)); - mm = str2num (cvalue(6:7)); - ss = str2num (cvalue(9:10)); - rawarr(ii, jj) = datenum (0, 0, 0, hh, mm, ss); - endif - otherwise - endswitch - endif - endfor - endfor - - elseif (ver ==2 ) # jOpenDocument version 1.2b2 - - for ii=1:nrows - for jj = 1:ncols - celladdress = calccelladdress (toprow, lcol, ii, jj); - try - val = sh.getCellAt (celladdress).getValue (); - catch - # No panic, probably a merged cell - val = {}; - end_try_catch - if (~isempty (val)) - if (ischar (val)) - # Text string + for ii=1:nrows + for jj = 1:ncols + celladdress = calccelladdress (toprow, lcol, ii, jj); + try + val = sh.getCellAt (celladdress).getValue (); + catch + # No panic, probably a merged cell + val = {}; + end_try_catch + if (~isempty (val)) + if (ischar (val)) + # Text string + rawarr(ii, jj) = val; + elseif (isnumeric (val)) + # Boolean + if (val) rawarr(ii, jj) = true; else; rawarr(ii, jj) = false; endif + else + try + val = sh.getCellAt (celladdress).getValue ().doubleValue (); rawarr(ii, jj) = val; - elseif (isnumeric (val)) - # Boolean - if (val) rawarr(ii, jj) = true; else; rawarr(ii, jj) = false; endif - else - try - val = sh.getCellAt (celladdress).getValue ().doubleValue (); - rawarr(ii, jj) = val; - catch - val = char (val); - if (isempty (val)) - # Probably empty Cell - else - # Maybe date / time value. Dirty hack to get values: - mo = strmatch (toupper (val(5:7)), months); - dd = str2num (val(9:10)); - yy = str2num (val(25:end)); - hh = str2num (val(12:13)); - mm = str2num (val(15:16)); - ss = str2num (val(18:19)); - rawarr(ii, jj) = datenum (yy, mo, dd, hh, mm,ss); - endif - end_try_catch - endif + catch + val = char (val); + if (isempty (val)) + # Probably empty Cell + else + # Maybe date / time value. Dirty hack to get values: + mo = strmatch (toupper (val(5:7)), months); + dd = str2num (val(9:10)); + yy = str2num (val(25:end)); + hh = str2num (val(12:13)); + mm = str2num (val(15:16)); + ss = str2num (val(18:19)); + rawarr(ii, jj) = datenum (yy, mo, dd, hh, mm,ss); + endif + end_try_catch endif - endfor + endif endfor + endfor + + ods.limits = [ lcol, lcol+ncols-1; toprow, toprow+nrows-1 ]; + + rstatus = ~isempty (rawarr); - endif - - # Crop rawarr from all empty outer rows & columns just like Excel does - # & keep track of limits - emptr = cellfun('isempty', rawarr); - if (all (all (emptr))) - rawarr = {}; - ods.limits= []; - else - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nrows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = ncols; - while (all (emptr(:, icolr))), icolr--; endwhile - # Crop textarray - rawarr = rawarr(irowt:irowb, icoll:icolr); - rstatus = 1; - ods.limits = [lcol+icoll-1, lcol+icolr-1; toprow+irowt-1, toprow+irowb-1]; - endif - endfunction Modified: trunk/octave-forge/main/io/inst/xls2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2oct.m 2010-08-03 21:24:56 UTC (rev 7493) +++ trunk/octave-forge/main/io/inst/xls2oct.m 2010-08-03 21:27:35 UTC (rev 7494) @@ -18,6 +18,7 @@ ## @deftypefn {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}, @var{wsh}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}, @var{wsh}, @var{range}) +## @deftypefnx {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}, @var{wsh}, @var{range}, @var{options}) ## ## Read data contained within range @var{range} from worksheet @var{wsh} ## in an Excel spreadsheet file pointed to in struct @var{xls}. @@ -35,6 +36,13 @@ ## determined behind the scenes first; this can take some time for the ## Java-based interfaces. ## +## Optional argument @var{options}, a structure, can be used to +## specify various read modes. Currently the only option field is +## "formulas_as_text"; if set to TRUE or 1, spreadsheet formulas +## (if at all present) are read as formula strings rather than the +## evaluated formula result values. This only works for the Java +## based interfaces (POI and JXL). +## ## If only the first argument is specified, xls2oct will try to read ## all contents from the first = leftmost (or the only) worksheet (as ## if a range of @'' (empty string) was specified). @@ -99,18 +107,24 @@ ## ADDRESS function still not working OK) ## 2010-03-14 Updated help text ## 2010-05-31 Updated help text (delay i.c.o. empty range due to getusedrange call) +## 2010-07-28 Added option to read formulas as text strings rather than evaluated value -function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh, datrange='') +function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh, datrange='', spsh_opts=[]) + if isempty (spsh_opts) + spsh_opts.formulas_as_text = 0; + # Other future options here + endif + if (strcmp (xls.xtype, 'COM')) # Call Excel tru COM server [rawarr, xls, rstatus] = xls2com2oct (xls, wsh, datrange); elseif (strcmp (xls.xtype, 'POI')) # Read xls file tru Java POI - [rawarr, xls, rstatus] = xls2jpoi2oct (xls, wsh, datrange); + [rawarr, xls, rstatus] = xls2jpoi2oct (xls, wsh, datrange, spsh_opts); elseif (strcmp (xls.xtype, 'JXL')) # Read xls file tru JExcelAPI - [rawarr, xls, rstatus] = xls2jxla2oct (xls, wsh, datrange); + [rawarr, xls, rstatus] = xls2jxla2oct (xls, wsh, datrange, spsh_opts); # elseif ---- <Other interfaces here> @@ -123,7 +137,7 @@ #==================================================================================== -## Copyright (C)2009 P.R. Nienhuis, <pr.nienhuis at hccnet.nl> +## Copyright (C) 2009 P.R. Nienhuis, <pr.nienhuis at hccnet.nl> ## ## based on mat2xls by Michael Goffioul (2007) <mic...@sw...> ## @@ -293,12 +307,14 @@ ## Updates: ## 2010-01-11 Fall back to cached values when formula evaluator fails ## 2010-03-14 Fixed max column nr for OOXML for empty given range +## 2010-07-28 Added option to read formulas as text strings rather than evaluated value +## 2010-08-01 Some bug fixes for formula reading (cvalue rather than scell) -function [ rawarr, xls, status ] = xls2jpoi2oct (xls, wsh, cellrange=[]) +function [ rawarr, xls, status ] = xls2jpoi2oct (xls, wsh, cellrange=[], spsh_opts) persistent ctype; if (isempty (ctype)) - # Get enumrated cell types. Beware as they start at 0 not 1 + # Get enumerated cell types. Beware as they start at 0 not 1 ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); @@ -337,6 +353,7 @@ lastrow = sh.getLastRowNum (); if (isempty (cellrange)) # Get used range by searching (slow...). Beware, it can be bit unreliable + ## FIXME - can be replaced by call to getusedrange.m # lcol = 65535; # Old xls value lcol = 1048576; # OOXML (xlsx) max. rcol = 0; @@ -375,43 +392,50 @@ scol = (irow.getFirstCellNum).intValue (); ecol = (irow.getLastCellNum).intValue () - 1; for jj = max (scol, lcol) : min (lcol+ncols-1, ecol) - cell = irow.getCell (jj); - if ~isempty (cell) + scell = irow.getCell (jj); + if ~isempty (scell) # Explore cell contents - type_of_cell = cell.getCellType (); + type_of_cell = scell.getCellType (); if (type_of_cell == ctype(3)) # Formula - try # Because not al Excel formulas have been implemented - cell = frm_eval.evaluate (cell); - type_of_cell = cell.getCellType(); - # Separate switch because form.eval. yields different type - switch type_of_cell - case ctype (1) # Numeric - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumberValue (); - case ctype(2) # String - rawarr (ii+1-firstrow, jj+1-lcol) = char (cell.getStringValue ()); - case ctype (5) # Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = cell.BooleanValue (); - otherwise - # Nothing to do here - endswitch - # Set cell type to blank to skip switch below - type_of_cell = ctype(4); - catch - # In case of formula errors we take the cached results - type_of_cell = cell.getCachedFormulaResultType (); - ++jerror; # We only need one warning even for multiple errors - end_try_catch + if ~(spsh_opts.formulas_as_text) + try # Because not al Excel formulas have been implemented + cvalue = frm_eval.evaluate (scell); + type_of_cell = cvalue.getCellType(); + # Separate switch because form.eval. yields different type + switch type_of_cell + case ctype (1) # Numeric + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getNumberValue (); + case ctype(2) # String + rawarr (ii+1-firstrow, jj+1-lcol) = char (scell.getStringValue ()); + case ctype (5) # Boolean + rawarr (ii+1-firstrow, jj+1-lcol) = scell.BooleanValue (); + otherwise + # Nothing to do here + endswitch + # Set cell type to blank to skip switch below + type_of_cell = ctype(4); + catch + # In case of formula errors we take the cached results + type_of_cell = scell.getCachedFormulaResultType (); + ++jerror; # We only need one warning even for multiple errors + end_try_catch + endif endif # Preparations done, get data values into data array switch type_of_cell case ctype(1) # 0 Numeric - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getNumericCellValue (); + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getNumericCellValue (); case ctype(2) # 1 String - rawarr (ii+1-firstrow, jj+1-lcol) = char (cell.getRichStringCellValue ()); + rawarr (ii+1-firstrow, jj+1-lcol) = char (scell.getRichStringCellValue ()); + case ctype(3) + if (spsh_opts.formulas_as_text) + tmp = char (scell.getCellFormula ()); + rawarr (ii+1-firstrow, jj+1-lcol) = ['=' tmp]; + endif case ctype(4) # 3 Blank # Blank; ignore until further notice case ctype(5) # 4 Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getBooleanCellValue (); + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getBooleanCellValue (); otherwise # 5 Error # Ignore endswitch @@ -481,9 +505,13 @@ ## Author: Philip Nienhuis ## Created: 2009-12-04 -## Last updated 2009-12-11 +## Updates: +## 2009-12-11 ??? some bug fix +## 2010-07-28 Added option to read formulas as text strings rather than evaluated value +## Added check for proper xls structure +## 2010-07-29 Added check for too latge requested data rectangle -function [ rawarr, xls, status ] = xls2jxla2oct (xls, wsh, cellrange=[]) +function [ rawarr, xls, status ] = xls2jxla2oct (xls, wsh, cellrange=[], spsh_opts) persistent ctype; if (isempty (ctype)) @@ -542,47 +570,59 @@ # Translate range to HSSF POI row & column numbers [dummy, nrows, ncols, trow, lcol] = parse_sp_range (cellrange); firstrow = max (trow-1, firstrow); - lastrow = firstrow + nrows - 1; lcol = lcol - 1; # POI rows & column # 0-based + # Check for too large requested range against actually present range + lastrow = min (firstrow + nrows - 1, sh.getRows () - 1); + nrows = min (nrows, sh.getRows () - firstrow); + ncols = min (ncols, sh.getColumns () - lcol); endif # Read contents into rawarr rawarr = cell (nrows, ncols); # create placeholder for jj = lcol : lcol+ncols-1 for ii = firstrow:lastrow - cell = sh.getCell (jj, ii); - type_of_cell = char (cell.getType ()); - switch type_of_cell - case ctype {1, 1} - # Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {2, 1} - # Boolean formula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {3, 1} - # Date - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {4, 1} - # Date Formula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {5, 1} - # Empty. Nothing to do here - case ctype {6, 1} - # Error. Nothing to do here - case ctype {7, 1} - # Formula Error. Nothing to do here - case ctype {8, 1} - # Number - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {9, 1} - # String - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getString (); - case ctype {10, 1} - # NumericalFormula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getValue (); - case ctype {11, 1} - # String Formula - rawarr (ii+1-firstrow, jj+1-lcol) = cell.getString (); + scell = sh.getCell (jj, ii); + switch char (scell.getType ()) + case ctype {1, 1} # Boolean + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + case ctype {2, 1} # Boolean formula + if (spsh_opts.formulas_as_text) + tmp = scell.getFormula (); + rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + else + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + endif + case ctype {3, 1} # Date + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + case ctype {4, 1} # Date formula + if (spsh_opts.formulas_as_text) + tmp = scell.getFormula (); + rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + else + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + endif + case { ctype {5, 1}, ctype {6, 1}, ctype {7, 1} } + # Empty, Error or Formula error. Nothing to do here + case ctype {8, 1} # Number + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + case ctype {9, 1} # String + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getString (); + case ctype {10, 1} # Numerical formula + if (spsh_opts.formulas_as_text) + tmp = scell.getFormula (); + rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + else + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + endif + case ctype {11, 1} # String formula + if (spsh_opts.formulas_as_text) + tmp = scell.getFormula (); + rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + else + rawarr (ii+1-firstrow, jj+1-lcol) = scell.getString (); + endif + otherwise + # Do nothing endswitch endfor endfor This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-08-03 21:29:12
|
Revision: 7495 http://octave.svn.sourceforge.net/octave/?rev=7495&view=rev Author: prnienhuis Date: 2010-08-03 21:29:06 +0000 (Tue, 03 Aug 2010) Log Message: ----------- Support function files to be invoked by the spreadsheet scripts, not directly by users. Added Paths: ----------- trunk/octave-forge/main/io/inst/spsh_chkrange.m trunk/octave-forge/main/io/inst/spsh_prstype.m Added: trunk/octave-forge/main/io/inst/spsh_chkrange.m =================================================================== --- trunk/octave-forge/main/io/inst/spsh_chkrange.m (rev 0) +++ trunk/octave-forge/main/io/inst/spsh_chkrange.m 2010-08-03 21:29:06 UTC (rev 7495) @@ -0,0 +1,82 @@ +## Copyright (C) 2010 Philip Nienhuis +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [ @var{topleftaddr}, @var{nrows}, @var{ncols}, @var{toprow}, @var{leftcol} ] = spsh_chkrange ( @var{range}, @var{rowsize}, @var{colsize}, @var{intf-type}, @var{filename}) +## Get and check various cell and range address parameters for spreadsheet input. +## +## spsh_chkrange should not be invoked directly but rather through oct2xls or oct2ods. +## +## Example: +## +## @example +## [tl, nrw, ncl, trw, lcl] = spsh_chkrange (crange, nr, nc, xtype, filename); +## @end example +## +## @end deftypefn + +## Author: Philip Nienhuis, <prn...@us...> +## Created: 2010-08-02 +## Updates: +## + +function [ topleft, nrows, ncols, trow, lcol ] = spsh_chkrange (crange, nr, nc, xtype, filename) + + # Define max row & column capacity from interface type & file suffix + switch xtype + case {'COM', 'POI'} + if (strmatch (tolower (filename(end-3:end)), '.xls')) + # BIFF5 & BIFF8 + ROW_CAP = 65536; COL_CAP = 256; + else + # OOXML (COM needs Excel 2007+ for this) + ROW_CAP = 1048576; COL_CAP = 16384; + endif + case 'JXL' + # JExcelAPI can only process BIFF5 & BIFF8 + ROW_CAP = 65536; COL_CAP = 256; + case {'OTK', 'JOD'} + # ODS + ROW_CAP = 65536; COL_CAP = 1024; + otherwise + error (sprintf ("Unknown interface type - %s\n", spptr.xtype)); + endswitch + + if (isempty (deblank (crange))) + trow = 1; + lcol = 1; + nrows = nr; + ncols = nc; + topleft= 'A1'; + elseif (isempty (strfind (deblank (crange), ':'))) + # Only top left cell specified + [topleft, dummy1, dummy2, trow, lcol] = parse_sp_range (crange); + nrows = nr; + ncols = nc; + else + [topleft, nrows, ncols, trow, lcol] = parse_sp_range (crange); + endif + if (trow > ROW_CAP || lcol > COL_CAP) + error ("Topleft cell (%s) beyond spreadsheet limits."); + endif + # Check spreadsheet capacity beyond requested topleft cell + nrows = min (nrows, ROW_CAP - trow + 1); + ncols = min (ncols, COL_CAP - lcol + 1); + # Check array size and requested range + nrows = min (nrows, nr); + ncols = min (ncols, nc); + +endfunction Added: trunk/octave-forge/main/io/inst/spsh_prstype.m =================================================================== --- trunk/octave-forge/main/io/inst/spsh_prstype.m (rev 0) +++ trunk/octave-forge/main/io/inst/spsh_prstype.m 2010-08-03 21:29:06 UTC (rev 7495) @@ -0,0 +1,75 @@ +## Copyright (C) 2010 Philip Nienhuis +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} [ @var{type-array} ] = spsh_prstype ( @var{iarray}, @var{rowsize}, @var{colsize}, @var{celltypes}, @var{options}) +## Return a square array with codes for cell types in square input cell array @var{iarray}. +## Codes are contained in input vector in order of Numeric, Boolean, Text, Formula and Empty, resp. +## +## spsh_prstype should not be invoked directly but rather through oct2xls or oct2ods. +## +## Example: +## +## @example +## typarr = spsh_chkrange (cellarray, nr, nc, ctypes, options); +## @end example +## +## @end deftypefn + +## Author: Philip Nienhuis, <prn...@us...> +## Created: 2010-08-02 +## Updates: +## + +function [ typearr ] = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts) + + # ctype index: + # 1 = numeric + # 2 = boolean + # 3 = text + # 4 = formula + # 5 = error / NaN / empty + + typearr = ctype(5) * ones (nrows, ncols); # type "EMPTY", provisionally + obj2 = cell (size (obj)); # Temporary storage for strings + + txtptr = cellfun ('isclass', obj, 'char'); # type "STRING" replaced by "NUMERIC" + obj2(txtptr) = obj(txtptr); obj(txtptr) = ctype(3); # Save strings in a safe place + + emptr = cellfun ("isempty", obj); + obj(emptr) = ctype(5); # Set empty cells to NUMERIC + + lptr = cellfun ("islogical" , obj); # Find logicals... + obj2(lptr) = obj(lptr); # .. and set them to BOOLEAN + + ptr = cellfun ("isnan", obj); # Find NaNs & set to BLANK + typearr(ptr) = ctype(5); typearr(~ptr) = ctype(1); # All other cells are now numeric + + obj(txtptr) = obj2(txtptr); # Copy strings back into place + obj(lptr) = obj2(lptr); # Same for logicals + obj(emptr) = []; # And empty cells + + typearr(txtptr) = ctype(3); # ...and clean up + typearr(emptr) = ctype(5); # EMPTY + typearr(lptr) = ctype(2); # BOOLEAN + + if ~(spsh_opts.formulas_as_text) + # Find formulas (designated by a string starting with "=" and ending in ")") + fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), obj); + typearr(fptr) = ctype(4); # FORMULA + endif + +endfunction This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-08-16 19:20:03
|
Revision: 7542 http://octave.svn.sourceforge.net/octave/?rev=7542&view=rev Author: prnienhuis Date: 2010-08-16 19:19:57 +0000 (Mon, 16 Aug 2010) Log Message: ----------- Restored these, accidentally deleted Added Paths: ----------- trunk/octave-forge/main/io/inst/csvread.m trunk/octave-forge/main/io/inst/csvwrite.m trunk/octave-forge/main/io/inst/dlmwrite.m Added: trunk/octave-forge/main/io/inst/csvread.m =================================================================== --- trunk/octave-forge/main/io/inst/csvread.m (rev 0) +++ trunk/octave-forge/main/io/inst/csvread.m 2010-08-16 19:19:57 UTC (rev 7542) @@ -0,0 +1,27 @@ +## Copyright (C) 2001, 2008 Paul Kienzle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc. + +## -*- texinfo -*- +## @deftypefn {Function File} {x} = csvread (@var{filename}) +## Read the matrix @var{x} from a file. +## +## This function is equivalent to dlmread (@var{filename}, "," , ...) +## +## @seealso{dlmread, dlmwrite, csvwrite, csv2cell} +## @end deftypefn + +function m = csvread(f,varargin) + m = dlmread(f,',',varargin{:}); Added: trunk/octave-forge/main/io/inst/csvwrite.m =================================================================== --- trunk/octave-forge/main/io/inst/csvwrite.m (rev 0) +++ trunk/octave-forge/main/io/inst/csvwrite.m 2010-08-16 19:19:57 UTC (rev 7542) @@ -0,0 +1,27 @@ +## Copyright (C) 2001, 2008 Paul Kienzle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc. + +## -*- texinfo -*- +## @deftypefn {Function File} {x} = csvwrite (@var{filename}, @var{x}) +## Write the matrix @var{x} to a file. +## +## This function is equivalent to dlmwrite(@var{filename},@var{x},",",...) +## +## @seealso{dlmread, dlmwrite, csvread, csv2cell} +## @end deftypefn + +function m = csvwrite(f,m,varargin) + dlmwrite(f,m,',',varargin{:}); Added: trunk/octave-forge/main/io/inst/dlmwrite.m =================================================================== --- trunk/octave-forge/main/io/inst/dlmwrite.m (rev 0) +++ trunk/octave-forge/main/io/inst/dlmwrite.m 2010-08-16 19:19:57 UTC (rev 7542) @@ -0,0 +1,197 @@ +## Copyright (C) 2002, 2008 Paul Kienzle +## +## This program is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} dlmwrite (@var{file}, @var{a}) +## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, @var{delim}, @var{r}, @var{c}) +## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, "attrib1", @var{value1}, "attrib2", @var{value2}, @dots{}) +## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, "-append", @dots{}) +## +## Write the matrix @var{a} to the text @var{file} using delimiters. +## +## @table @var +## @item delim +## the delimiter to use to separate values on a row +## +## @item r +## the number of delimiter-only lines to add to the start of the file +## +## @item c +## the number of delimiters to prepend to each line of data. +## +## @item "-append" +## append to the end of the @var{file}. +## +## @item "append", state +## Either @samp{"on"} or @samp{"off"}. See @samp{"-append"} above. +## +## @item "delimiter", d +## See @var{delim} above. +## +## @item "newline", os +## The character(s) to use to separate each row. Three special cases +## exist for this option. @samp{"unix"} is changed into '\n', +## @samp{"pc"} is changed into '\r\n', and @samp{"mac"} is changed +## into '\r'. Other values for this option are kept as is. +## +## @item "roffset", r +## See @var{r} above. +## +## @item "coffset", c +## See @var{c} above. +## +## @item "precision", p +## The precision to use when writing the file. It can either be a +## format string (as used by fprintf) or a number of significant digits. +## @end table +## +## @example +## @var{A} = reshape(1:16,4,4); +## dlmwrite(@code{"file.csv"}, @var{A}) +## @end example +## +## @example +## dlmwrite (@code{"file.tex"}, @var{a}, "delimiter", "&", "newline", "\\n") +## @end example +## +## @seealso{dlmread, csvread, csvwrite} +## @end deftypefn + +## Author: Paul Kienzle <pki...@us...> +## +## This program was originally granted to the public domain +## +## 2002-03-08 Paul Kienzle <pki...@us...> +## * Initial revision +## 2005-11-27 Bill Denney <bi...@gi...> +## * Significant modifications of the input arguements for additional +## functionality. + +function dlmwrite (file, a, varargin) + + if (nargin < 2 || ! ischar (file)) + ptint_usage (); + endif + + ## set defaults + delim = ","; + r = 0; + c = 0; + newline = "\n"; + precision = "%.16g"; + opentype = "wt"; + + ## process the input arguements + i = 0; + while (i < length (varargin)) + i = i + 1; + if (strcmpi (varargin{i}, "delimiter") || strcmpi(varargin{i}, "delim")) + i = i + 1; + delim = varargin{i}; + elseif (strcmpi (varargin{i}, "newline")) + i = i + 1; + newline = varargin{i}; + if (strcmpi (newline, "unix")) + newline = "\n"; + elseif (strcmpi (newline, "pc")) + newline = "\r\n"; + elseif (strcmpi (newline, "mac")) + newline = "\r"; + endif + elseif (strcmpi (varargin{i}, "roffset")) + i = i + 1; + r = varargin{i}; + elseif (strcmpi (varargin{i}, "coffset")) + i = i + 1; + c = varargin{i}; + elseif (strcmpi (varargin{i}, "precision")) + i = i + 1; + precision = varargin{i}; + if (! strcmpi (class (precision), "char")) + precision = sprintf ("%.%gg", precision); + endif + elseif (strcmpi (varargin{i}, "-append")) + opentype = "at"; + elseif (strcmpi (varargin{i}, "append")) + i = i + 1; + if (strcmpi (varargin{i}, "on")) + opentype = "at"; + elseif (strcmpi (varargin{i}, "off")) + opentype = "wt"; + else + error ("dlmwrite: append must be \"on\" or \"off\"."); + endif + else + if (i == 1) + delim = varargin{i}; + elseif (i == 2) + r = varargin{i}; + elseif (i == 3) + c = varargin{i}; + else + print_usage(); + endif + endif + endwhile + + [fid, msg] = fopen (file, opentype); + if (fid < 0) + error (msg); + else + if (r > 0) + fprintf (fid, "%s", + repmat ([repmat(delim, 1, c + columns(a)-1), newline], 1, r)); + endif + if (iscomplex (a)) + cprecision = regexprep (precision, '^%([-\d.])','%+$1'); + template = [precision, cprecision, "i", ... + repmat([delim, precision, cprecision, "i"], 1, ... + columns(a) - 1), newline ]; + else + template = [precision, repmat([delim, precision], 1, columns(a)-1),... + newline]; + endif + if (c > 0) + template = [repmat(delim, 1, c), template]; + endif + if (iscomplex (a)) + a = a.'; + b = zeros (2*rows(a), columns (a)); + b(1: 2 : end, :) = real (a); + b(2: 2 : end, :) = imag (a); + fprintf (fid, template, b); + else + fprintf (fid, template, a.'); + endif + fclose (fid); + endif +endfunction + +%!test +%! f = tmpnam(); +%! dlmwrite(f,[1,2;3,4],'precision','%5.2f','newline','unix','roffset',1,'coffset',1); +%! fid = fopen(f,"rt"); +%! f1 = char(fread(fid,Inf,'char')'); +%! fclose(fid); +%! dlmwrite(f,[5,6],'precision','%5.2f','newline','unix','coffset',1,'delimiter',',','-append'); +%! dlmwrite(f,[5,6],'precision','%5.2f','delim','\t','-append'); +%! fid = fopen(f,"rt"); +%! f2 = char(fread(fid,Inf,'char')'); +%! fclose(fid); +%! unlink(f); +%! +%! assert(f1,",,\n, 1.00, 2.00\n, 3.00, 4.00\n"); +%! assert(f2,",,\n, 1.00, 2.00\n, 3.00, 4.00\n, 5.00, 6.00\n 5.00\t 6.00\n"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-08-18 21:35:35
|
Revision: 7555 http://octave.svn.sourceforge.net/octave/?rev=7555&view=rev Author: prnienhuis Date: 2010-08-18 21:35:28 +0000 (Wed, 18 Aug 2010) Log Message: ----------- Improved logic for opening files to avoid unneeded error message clutter in the terminal Modified Paths: -------------- trunk/octave-forge/main/io/inst/xlsread.m trunk/octave-forge/main/io/inst/xlswrite.m Modified: trunk/octave-forge/main/io/inst/xlsread.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsread.m 2010-08-18 21:33:58 UTC (rev 7554) +++ trunk/octave-forge/main/io/inst/xlsread.m 2010-08-18 21:35:28 UTC (rev 7555) @@ -122,6 +122,8 @@ ## 2009-12-29 bug fixes ## 2010-01-12 added unwind_protect to get rid of stray Excel invocations i.c.o. COM errors ## 2010-05-31 Updated help text (delays i.c.o. empty range due to getusedrange call) +## 2010-08-18 Added check for existence of xls after call to xlsopen to +## avoid unneeded error message clutter function [ numarr, txtarr, rawarr, lims ] = xlsread (fn, wsh, datrange, reqintf=[]) @@ -151,13 +153,17 @@ reqintf= "JXL"; printf ("BASIC (BIFF5) support request translated to JXL. \n"); endif + + if (nargout < 1) printf ("Warning: no output spreadsheet file pointer specified as argument.\n"); endif # Checks done. Get raw data into cell array "rawarr". xlsopen finds out # what interface to use. If none found, suggest csv unwind_protect # Needed to catch COM errors & able to close stray Excel invocations # Get pointer array to Excel file + xls_ok = 0; xls = xlsopen (fn, 0, reqintf); + xls_ok = 1; if (strcmp (xls.xtype, 'COM') || strcmp (xls.xtype, 'POI') || strcmp (xls.xtype, 'JXL')) @@ -184,7 +190,7 @@ unwind_protect_cleanup # Close Excel file - xls = xlsclose (xls); + if (xls_ok) xls = xlsclose (xls); endif end_unwind_protect Modified: trunk/octave-forge/main/io/inst/xlswrite.m =================================================================== --- trunk/octave-forge/main/io/inst/xlswrite.m 2010-08-18 21:33:58 UTC (rev 7554) +++ trunk/octave-forge/main/io/inst/xlswrite.m 2010-08-18 21:35:28 UTC (rev 7555) @@ -93,6 +93,8 @@ ## 2010-01-04 (Adapted range capacity checks to OOXML) ## 2010-01-12 (Bug fix; added unwind_protect to xlsopen...xlsclose calls) ## 2010-01-15 Fixed typos in texinfo +## 2010-08-18 Added check for existence of xls after call to xlsopen to +## avoid unneeded error message clutter function [ rstatus ] = xlswrite (filename, arr, arg3, arg4, arg5) @@ -152,12 +154,14 @@ endif unwind_protect # Needed to besure Excel can be closed i.c.o. errors + xls_ok = 0; xls = xlsopen (filename, 1, reqintf); + xls_ok = 1; [xls, rstatus] = oct2xls (arr(1:nr, 1:nc), xls, wsh, topleft); unwind_protect_cleanup - xls = xlsclose (xls); + if (xls_ok) xls = xlsclose (xls); endif end_unwind_protect This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-09-07 19:30:31
|
Revision: 7679 http://octave.svn.sourceforge.net/octave/?rev=7679&view=rev Author: prnienhuis Date: 2010-09-07 19:30:23 +0000 (Tue, 07 Sep 2010) Log Message: ----------- These functions are in core octave Removed Paths: ------------- trunk/octave-forge/main/io/inst/csvread.m trunk/octave-forge/main/io/inst/csvwrite.m trunk/octave-forge/main/io/inst/dlmwrite.m Deleted: trunk/octave-forge/main/io/inst/csvread.m =================================================================== --- trunk/octave-forge/main/io/inst/csvread.m 2010-09-07 19:27:31 UTC (rev 7678) +++ trunk/octave-forge/main/io/inst/csvread.m 2010-09-07 19:30:23 UTC (rev 7679) @@ -1,27 +0,0 @@ -## Copyright (C) 2001, 2008 Paul Kienzle -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc. - -## -*- texinfo -*- -## @deftypefn {Function File} {x} = csvread (@var{filename}) -## Read the matrix @var{x} from a file. -## -## This function is equivalent to dlmread (@var{filename}, "," , ...) -## -## @seealso{dlmread, dlmwrite, csvwrite, csv2cell} -## @end deftypefn - -function m = csvread(f,varargin) - m = dlmread(f,',',varargin{:}); Deleted: trunk/octave-forge/main/io/inst/csvwrite.m =================================================================== --- trunk/octave-forge/main/io/inst/csvwrite.m 2010-09-07 19:27:31 UTC (rev 7678) +++ trunk/octave-forge/main/io/inst/csvwrite.m 2010-09-07 19:30:23 UTC (rev 7679) @@ -1,27 +0,0 @@ -## Copyright (C) 2001, 2008 Paul Kienzle -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc. - -## -*- texinfo -*- -## @deftypefn {Function File} {x} = csvwrite (@var{filename}, @var{x}) -## Write the matrix @var{x} to a file. -## -## This function is equivalent to dlmwrite(@var{filename},@var{x},",",...) -## -## @seealso{dlmread, dlmwrite, csvread, csv2cell} -## @end deftypefn - -function m = csvwrite(f,m,varargin) - dlmwrite(f,m,',',varargin{:}); Deleted: trunk/octave-forge/main/io/inst/dlmwrite.m =================================================================== --- trunk/octave-forge/main/io/inst/dlmwrite.m 2010-09-07 19:27:31 UTC (rev 7678) +++ trunk/octave-forge/main/io/inst/dlmwrite.m 2010-09-07 19:30:23 UTC (rev 7679) @@ -1,197 +0,0 @@ -## Copyright (C) 2002, 2008 Paul Kienzle -## -## This program is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} dlmwrite (@var{file}, @var{a}) -## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, @var{delim}, @var{r}, @var{c}) -## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, "attrib1", @var{value1}, "attrib2", @var{value2}, @dots{}) -## @deftypefnx {Function File} {} dmlwrite (@var{file}, @var{a}, "-append", @dots{}) -## -## Write the matrix @var{a} to the text @var{file} using delimiters. -## -## @table @var -## @item delim -## the delimiter to use to separate values on a row -## -## @item r -## the number of delimiter-only lines to add to the start of the file -## -## @item c -## the number of delimiters to prepend to each line of data. -## -## @item "-append" -## append to the end of the @var{file}. -## -## @item "append", state -## Either @samp{"on"} or @samp{"off"}. See @samp{"-append"} above. -## -## @item "delimiter", d -## See @var{delim} above. -## -## @item "newline", os -## The character(s) to use to separate each row. Three special cases -## exist for this option. @samp{"unix"} is changed into '\n', -## @samp{"pc"} is changed into '\r\n', and @samp{"mac"} is changed -## into '\r'. Other values for this option are kept as is. -## -## @item "roffset", r -## See @var{r} above. -## -## @item "coffset", c -## See @var{c} above. -## -## @item "precision", p -## The precision to use when writing the file. It can either be a -## format string (as used by fprintf) or a number of significant digits. -## @end table -## -## @example -## @var{A} = reshape(1:16,4,4); -## dlmwrite(@code{"file.csv"}, @var{A}) -## @end example -## -## @example -## dlmwrite (@code{"file.tex"}, @var{a}, "delimiter", "&", "newline", "\\n") -## @end example -## -## @seealso{dlmread, csvread, csvwrite} -## @end deftypefn - -## Author: Paul Kienzle <pki...@us...> -## -## This program was originally granted to the public domain -## -## 2002-03-08 Paul Kienzle <pki...@us...> -## * Initial revision -## 2005-11-27 Bill Denney <bi...@gi...> -## * Significant modifications of the input arguements for additional -## functionality. - -function dlmwrite (file, a, varargin) - - if (nargin < 2 || ! ischar (file)) - ptint_usage (); - endif - - ## set defaults - delim = ","; - r = 0; - c = 0; - newline = "\n"; - precision = "%.16g"; - opentype = "wt"; - - ## process the input arguements - i = 0; - while (i < length (varargin)) - i = i + 1; - if (strcmpi (varargin{i}, "delimiter") || strcmpi(varargin{i}, "delim")) - i = i + 1; - delim = varargin{i}; - elseif (strcmpi (varargin{i}, "newline")) - i = i + 1; - newline = varargin{i}; - if (strcmpi (newline, "unix")) - newline = "\n"; - elseif (strcmpi (newline, "pc")) - newline = "\r\n"; - elseif (strcmpi (newline, "mac")) - newline = "\r"; - endif - elseif (strcmpi (varargin{i}, "roffset")) - i = i + 1; - r = varargin{i}; - elseif (strcmpi (varargin{i}, "coffset")) - i = i + 1; - c = varargin{i}; - elseif (strcmpi (varargin{i}, "precision")) - i = i + 1; - precision = varargin{i}; - if (! strcmpi (class (precision), "char")) - precision = sprintf ("%.%gg", precision); - endif - elseif (strcmpi (varargin{i}, "-append")) - opentype = "at"; - elseif (strcmpi (varargin{i}, "append")) - i = i + 1; - if (strcmpi (varargin{i}, "on")) - opentype = "at"; - elseif (strcmpi (varargin{i}, "off")) - opentype = "wt"; - else - error ("dlmwrite: append must be \"on\" or \"off\"."); - endif - else - if (i == 1) - delim = varargin{i}; - elseif (i == 2) - r = varargin{i}; - elseif (i == 3) - c = varargin{i}; - else - print_usage(); - endif - endif - endwhile - - [fid, msg] = fopen (file, opentype); - if (fid < 0) - error (msg); - else - if (r > 0) - fprintf (fid, "%s", - repmat ([repmat(delim, 1, c + columns(a)-1), newline], 1, r)); - endif - if (iscomplex (a)) - cprecision = regexprep (precision, '^%([-\d.])','%+$1'); - template = [precision, cprecision, "i", ... - repmat([delim, precision, cprecision, "i"], 1, ... - columns(a) - 1), newline ]; - else - template = [precision, repmat([delim, precision], 1, columns(a)-1),... - newline]; - endif - if (c > 0) - template = [repmat(delim, 1, c), template]; - endif - if (iscomplex (a)) - a = a.'; - b = zeros (2*rows(a), columns (a)); - b(1: 2 : end, :) = real (a); - b(2: 2 : end, :) = imag (a); - fprintf (fid, template, b); - else - fprintf (fid, template, a.'); - endif - fclose (fid); - endif -endfunction - -%!test -%! f = tmpnam(); -%! dlmwrite(f,[1,2;3,4],'precision','%5.2f','newline','unix','roffset',1,'coffset',1); -%! fid = fopen(f,"rt"); -%! f1 = char(fread(fid,Inf,'char')'); -%! fclose(fid); -%! dlmwrite(f,[5,6],'precision','%5.2f','newline','unix','coffset',1,'delimiter',',','-append'); -%! dlmwrite(f,[5,6],'precision','%5.2f','delim','\t','-append'); -%! fid = fopen(f,"rt"); -%! f2 = char(fread(fid,Inf,'char')'); -%! fclose(fid); -%! unlink(f); -%! -%! assert(f1,",,\n, 1.00, 2.00\n, 3.00, 4.00\n"); -%! assert(f2,",,\n, 1.00, 2.00\n, 3.00, 4.00\n, 5.00, 6.00\n 5.00\t 6.00\n"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-11-14 16:53:37
|
Revision: 7915 http://octave.svn.sourceforge.net/octave/?rev=7915&view=rev Author: prnienhuis Date: 2010-11-14 16:53:26 +0000 (Sun, 14 Nov 2010) Log Message: ----------- Many bug fixes; more rigid input & output arg checks; better tracking of changes to files; also tested w Apache POI 3.7 Modified Paths: -------------- trunk/octave-forge/main/io/inst/oct2xls.m trunk/octave-forge/main/io/inst/xls2oct.m trunk/octave-forge/main/io/inst/xlsclose.m trunk/octave-forge/main/io/inst/xlsopen.m trunk/octave-forge/main/io/inst/xlsread.m trunk/octave-forge/main/io/inst/xlswrite.m Modified: trunk/octave-forge/main/io/inst/oct2xls.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2xls.m 2010-11-14 16:51:22 UTC (rev 7914) +++ trunk/octave-forge/main/io/inst/oct2xls.m 2010-11-14 16:53:26 UTC (rev 7915) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ ## ## @var{wsh} can be a number or string (max. 31 chars). ## In case of a yet non-existing Excel file, the first worksheet will be -## used & named according to @var{wsh} - the extra worksheets that Excel +## used & named according to @var{wsh} - extra empty worksheets that Excel ## creates by default are deleted. ## In case of existing files, some checks are made for existing worksheet ## names or numbers, or whether @var{wsh} refers to an existing sheet with @@ -98,11 +98,14 @@ ## 2010-08-16 Added check on presence of output argument. Made wsh = 1 default ## 2010-08-17 Corrected texinfo ("topleft" => "range") ## 2010-08-25 Improved help text (section on java memory usage) +## 2010-11-12 Moved ptr struct check into main func. More input validity checks +## 2010-11-13 Added check for 2-D input array -## Last script file update (incl. subfunctions): 2010-08-11 +## Last script file update (incl. subfunctions): 2011-11-12 function [ xls, rstatus ] = oct2xls (obj, xls, wsh=1, crange=[], spsh_opts=[]) + if (nargin < 2) error ("oct2xls needs a minimum of 2 arguments."); endif # Make sure input array is a cell array if (isempty (obj)) warning ("Request to write empty matrix - ignored."); @@ -116,43 +119,54 @@ elseif (~iscell (obj)) error ("oct2xls: input array neither cell nor numeric array"); endif - + if (ndims (c_arr) > 2), error ("Only 2-dimensional arrays can be written to spreadsheet"); endif + # Check xls file pointer struct + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if (test1) + error ("Invalid xls file pointer struct"); + endif + # Check worksheet ptr + if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 3"); endif + # Check range + if (~(isempty (crange) || ischar (crange))), error ("Character string (range) expected for arg # 4"); endif # Various options - if isempty (spsh_opts) + if (isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; # other options to be implemented here + elseif (isstruct (spsh_opts)) + if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif + # other options to be implemented here + else + error ("Structure expected for arg # 5"); endif - + + if (nargout < 1) printf ("Warning: no output spreadsheet file pointer specified.\n"); endif + # Select interface to be used if (strcmp (xls.xtype, 'COM')) # Call oct2com2xls to do the work [xls, rstatus] = oct2com2xls (obj, xls, wsh, crange, spsh_opts); - elseif (strcmp (xls.xtype, 'POI')) # Invoke Java and Apache POI [xls, rstatus] = oct2jpoi2xls (obj, xls, wsh, crange, spsh_opts); - elseif (strcmp (xls.xtype, 'JXL')) # Invoke Java and JExcelAPI [xls, rstatus] = oct2jxla2xls (obj, xls, wsh, crange, spsh_opts); - # elseif (strcmp'xls.xtype, '<whatever>')) # <Other Excel interfaces> - else error (sprintf ("oct2xls: unknown Excel .xls interface - %s.", xls.xtype)); - endif endfunction #=================================================================================== -## Copyright (C) 2007 by Michael Goffioul <michael.goffioul at swing.be> +## Copyright (C) 2009,2010 by Philip Nienhuis <prn...@us...> ## -## Adapted by P.R. Nienhuis <prnienhuis at users.sf.net> (2009) -## for more flexible writing into Excel worksheets through COM. -## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or @@ -189,7 +203,7 @@ ## ## @end deftypefn -## Author: Philip Nienhuis +## Author: Philip Nienhuis (originally based on mat2xls by Michael Goffioul) ## Rewritten: 2009-09-26 ## Updates: ## 2009-12-11 @@ -203,18 +217,18 @@ ## " Added option for formula input as text string ## 2010-08-01 Added range vs. array size vs. capacity checks ## 2010-08-03 Moved range checks and type array parsing to separate functions +## 2010-10-20 Bug fix removing new empty sheets in new workbook that haven't been +## created in the first place duetoExcelsetting (thanks Ian Journeaux) +## " Changed range use in COM transfer call +## 2010-10-21 Improved file change tracking (var xls.changed) +## 2010-10-24 Fixed bug introduced in above fix: for loops have no stride param, +## " replaced by while loop +## " Added check for "live" ActiveX server +## 2010-11-12 Moved ptr struct check into main func function [ xls, status ] = oct2com2xls (obj, xls, wsh, crange, spsh_opts) - # define some constants not yet in __COM__.cc - xlWorksheet = -4167; # xlChart= 4; - - # scratch vars - status = 0; - # Preliminary sanity checks - if (nargin < 2) error ("oct2com2xls needs a minimum of 2 arguments."); endif - if (nargin == 2) wsh = 1; endif if (~strmatch (tolower (xls.filename(end-4:end)), '.xls')) error ("oct2com2xls can only write to Excel .xls or .xlsx files") endif @@ -223,19 +237,23 @@ elseif (size (wsh, 2) > 31) error ("Illegal worksheet name - too long") endif - # Check xls file pointer struct - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'COM'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid file pointer struct"); - endif + # Check to see if ActiveX is still alive + try + wb_cnt = xls.workbook.Worksheets.count; + catch + error ("ActiveX invocation in file ptr struct seems non-functional"); + end_try_catch + # define some constants not yet in __COM__.cc + xlWorksheet = -4167; # xlChart= 4; + # scratch vars + status = 0; + # Parse date ranges [nr, nc] = size (obj); [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); + lowerright = calccelladdress (trow + nrows - 1, lcol + ncols - 1); + crange = [topleft ':' lowerright]; if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); obj = obj(1:nrows, 1:ncols); @@ -246,7 +264,7 @@ typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); # Make cells now indicated to be empty, empty fptr = ~(4 * (ones (size (typearr))) .- typearr); - obj(fptr) = cellfun(@(x) [], obj(fptr), "Uniformoutput", false); + obj(fptr) = cellfun (@(x) [], obj(fptr), "Uniformoutput", false); if (spsh_opts.formulas_as_text) # find formulas (designated by a string starting with "=" and ending in ")") @@ -256,8 +274,9 @@ endif clear fptr; - if (xls.changed < 2) - # Existing file. Some involved investigation is needed to preserve + if (xls.changed < 3) + # Existing file OR a new file with data added in a previous oct2xls call. + # Some involved investigation is needed to preserve # existing data that shouldn't be touched. # # See if desired *sheet* name exists. @@ -300,7 +319,7 @@ if (old_sh) # Requested sheet exists. Check if it is a *work*sheet if ~(xls.workbook.Sheets(old_sh).Type == xlWorksheet) - # Error as you can't write data to this + # Error as you can't write data to Chart sheet error (sprintf ("Existing sheet '%s' is not type worksheet.", wsh)); else # Simply point to the relevant sheet @@ -308,7 +327,11 @@ endif else # Add a new worksheet. Earlier it was checked whether this is safe - sh = xls.workbook.Worksheets.Add (); + try + sh = xls.workbook.Worksheets.Add (); + catch + error (sprintf ("Cannot add new worksheet to file %s\n", xls.filename)); + end_try_catch if (~isnumeric (wsh)) sh.Name = wsh; else @@ -328,44 +351,52 @@ # ....then move the last one before the new sheet. xls.workbook.Worksheets (ws_cnt).Move (before = xls.workbook.Worksheets(ws_cnt - 1)); endif - xls.changed = 1; else - # The easy case: a new Excel file. - # Workbook was created in xlsopen. Write to first worksheet: - sh = xls.workbook.Worksheets (1); + # The easy case: a new Excel file. Workbook was created in xlsopen. + # Delete empty non-used sheets, last one first xls.app.Application.DisplayAlerts = 0; - xls.workbook.Worksheets(3).Delete(); xls.workbook.Worksheets(2).Delete(); + ii = xls.workbook.Sheets.count; + while (ii > 1) + xls.workbook.Worksheets(ii).Delete(); + --ii; + endwhile xls.app.Application.DisplayAlerts = 1; + # Write to first worksheet: + sh = xls.workbook.Worksheets (1); # Rename the sheet - if (isnumeric(wsh)) - sh.Name = sprintf("Sheet%i", wsh); + if (isnumeric (wsh)) + sh.Name = sprintf ("Sheet%i", wsh); else sh.Name = wsh; endif - xls.changed = 2; + xls.changed = 2; # 3 => 2 endif - + # MG's original part. # Save object in Excel sheet, starting at cell top_left_cell if (~isempty(obj)) - r = sh.Range (topleft); - r = r.Resize (size (obj, 1), size (obj, 2)); - r.Value = obj; + r = sh.Range (crange); + try + r.Value = obj; + catch + error (sprintf ("Cannot add data to worksheet %s in file %s\n", sh.Name, xls.filename)); + end_try_catch delete (r); endif # If we get here, all went OK status = 1; + xls.changed = max (xls.changed, 1); # If it was 2, preserve it. endfunction #==================================================================================== -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -417,9 +448,17 @@ ## 2010-08-01 Improved try-catch for formulas to enter wrong formulas as text strings ## 2010-08-01 Added range vs. array size vs. capacity checks ## 2010-08-03 Moved range checks and type array parsingto separate functions +## 2010-10-21 Improved logic for tracking file changes +## 2010-10-27 File change tracking again refined, internal var 'changed' dropped +## 2010-11-12 Moved ptr struct check into main func function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, crange, spsh_opts) + # Preliminary sanity checks + if (~strmatch (tolower (xls.filename(end-4:end)), '.xls')) + error ("oct2jpoi2xls can only write to Excel .xls or .xlsx files") + endif + persistent ctype; if (isempty (ctype)) # Get cell types. Beware as they start at 0 not 1 @@ -429,25 +468,9 @@ ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); # 2 ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); # 3 endif - # scratch vars - rstatus = 0; changed = 1; f_errs = 0; + rstatus = 0; f_errs = 0; - # Preliminary sanity checks - if (nargin < 2) error ("oct2jpoi2xls needs a minimum of 2 arguments."); endif - if (nargin == 2) wsh = 1; endif - if (~strmatch (tolower (xls.filename(end-4:end)), '.xls')) - error ("oct2jpoi2xls can only write to Excel .xls or .xlsx files") - endif - - # Check if xls struct pointer seems valid - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'POI'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 error ("Invalid xls file struct"); endif - # Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = xls.workbook.getNumberOfSheets (); if (isnumeric (wsh)) @@ -461,6 +484,7 @@ endwhile if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif sh = xls.workbook.createSheet (strng); + xls.changed = min (xls.changed, 2); # Keep 2 for new files else sh = xls.workbook.getSheetAt (wsh - 1); # POI sheet count 0-based endif @@ -470,7 +494,7 @@ if (isempty (sh)) # Sheet not found, just create it sh = xls.workbook.createSheet (wsh); - xls.changed = 2; + xls.changed = min (xls.changed, 2); # Keep 2 or 3 f. new files endif endif @@ -486,6 +510,7 @@ typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); if ~(spsh_opts.formulas_as_text) # Remove leading '=' from formula strings + # FIXME should be easier using typearr<4> info fptr = ~(2 * (ones (size (typearr))) .- typearr); obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false); endif @@ -521,14 +546,14 @@ if (f_errs) printf ("%d formula errors encountered - please check input array\n", f_errs); endif - xls.changed = 1; + xls.changed = max (xls.changed, 1); # Preserve a "2" rstatus = 1; endfunction #==================================================================================== -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -582,44 +607,38 @@ ## " Changed topleft arg into range arg (topleft version still recognized) ## 2010-08-03 Moved range checks and cell type parsing to separate routines ## 2010-08-11 Moved addcell() into try-catch as it is addCell which throws fatal errors +## 2010-10-20 Improved logic for tracking file changes (xls.changed 2 or 3); dropped +## " internal variable 'changed' +## 2010-10-27 File change tracking again refined +## 2010-11-12 Moved ptr struct check into main func function [ xls, rstatus ] = oct2jxla2xls (obj, xls, wsh, crange, spsh_opts) + # Preliminary sanity checks + if (~strmatch (tolower (xls.filename(end-4:end-1)), '.xls')) # No OOXML in JXL + error ("JExcelAPI can only write to Excel .xls files") + endif + persistent ctype; if (isempty (ctype)) ctype = [1, 2, 3, 4, 5]; # Number, Boolean, String, Formula, Empty endif - # scratch vars - rstatus = 0; changed = 1; f_errs = 0; - - # Preliminary sanity checks - if (nargin < 2) error ("oct2java2xls needs a minimum of 2 arguments."); endif - if (nargin == 2) wsh = 1; endif - if (~strmatch (tolower (xls.filename(end-4:end)), '.xls')) # No OOXML in JXL - error ("oct2java2xls can only write to Excel .xls files") - endif - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'JXL'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid file pointer struct"); - endif + rstatus = 0; f_errs = 0; # Prepare workbook pointer if needed - if (xls.changed < 2) - # Create writable copy of workbook. If 2 a writable wb was made in xlsopen + if (xls.changed == 0) # Only for 1st call of octxls after xlsopen + # Create writable copy of workbook. If >2 a writable wb was made in xlsopen xlsout = java_new ('java.io.File', xls.filename); wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsout, xls.workbook); - xls.changed = 1; # For in case we come from reading the file + # Catch JExcelAPI bug/"feature": when switching to write mode, the file on disk + # is affected and the memory file MUST be written to disk to save earlier data + xls.changed = 1; xls.workbook = wb; else wb = xls.workbook; endif - # Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = xls.workbook.getNumberOfSheets (); # 1 based !! if (isnumeric (wsh)) @@ -633,8 +652,9 @@ endwhile if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif sh = wb.createSheet (strng, nr_of_sheets); ++nr_of_sheets; + xls.changed = min (xls.changed, 2); # Keep a 2 in case of new file else - sh = wb.getSheet (wsh - 1); # POI sheet count 0-based + sh = wb.getSheet (wsh - 1); # POI sheet count 0-based endif shnames = char (wb.getSheetNames ()); printf ("(Writing to worksheet %s)\n", shnames {nr_of_sheets, 1}); @@ -644,13 +664,10 @@ # Sheet not found, just create it sh = wb.createSheet (wsh, nr_of_sheets); ++nr_of_sheets; - xls.changed = 2; + xls.changed = min (xls.changed, 2); # Keep a 2 for new file endif endif - # Beware of strings variables interpreted as char arrays; change them to cell. - if (ischar (obj)) obj = {obj}; endif - # Parse date ranges [nr, nc] = size (obj); [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); @@ -689,7 +706,7 @@ # There's no guarantee for formula correctness, so.... try # Actually JExcelAPI flags formula errors as warnings :-( tmp = java_new ('jxl.write.Formula', kk, ll, obj{ii, jj}); - # ... while errors are actualy detected in addCell(), so + # ... while errors are actually detected in addCell(), so # that should be within the try-catch sh.addCell (tmp); catch @@ -710,7 +727,7 @@ if (f_errs) printf ("%d formula errors encountered - please check input array\n", f_errs); endif - xls.changed = 1; + xls.changed = max (xls.changed, 1); # Preserve 2 for new files rstatus = 1; endfunction Modified: trunk/octave-forge/main/io/inst/xls2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/xls2oct.m 2010-11-14 16:51:22 UTC (rev 7914) +++ trunk/octave-forge/main/io/inst/xls2oct.m 2010-11-14 16:53:26 UTC (rev 7915) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -64,7 +64,6 @@ ## ## If one of the Java interfaces is used, field @var{xls}.limits contains ## the outermost column and row numbers of the actually read cell range. -## This doesn't work with native Excel / COM. ## ## Erroneous data and empty cells turn up empty in @var{rawarr}. ## Date/time values in Excel are returned as numerical values. @@ -106,21 +105,44 @@ ## Created: 2010-10-16 ## Updates: ## 2009-01-03 (added OOXML support & cleaned up code. Excel -## ADDRESS function still not working OK) +## ADDRESS function still not implemented in Apache POI) ## 2010-03-14 Updated help text ## 2010-05-31 Updated help text (delay i.c.o. empty range due to getusedrange call) ## 2010-07-28 Added option to read formulas as text strings rather than evaluated value ## 2010-08-25 Small typo in help text +## 2010-10-20 Added option fornot stripping output arrays +## 2010-11-07 More rigorous input checks. +## 2010-11-12 Moved pointer check into main func +## 2010-11-13 Catch empty sheets when no range was specified ## -## Latest subfunc update: 2010-10-08 (xls2com2oct) +## Latest subfunc update: 2010-11-14 (poi) -function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh, datrange='', spsh_opts=[]) +function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh=1, datrange='', spsh_opts=[]) + # Check if xls struct pointer seems valid + if (~isstruct (xls)), error ("File ptr struct expected for arg @ 1"); endif + test1 = ~isfield (xls, "xtype"); + test1 = test1 || ~isfield (xls, "workbook"); + test1 = test1 || isempty (xls.workbook); + test1 = test1 || isempty (xls.app); + if test1 + error ("Invalid xls file struct"); + endif + # Check worksheet ptr + if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 2"); endif + # Check range + if (~(isempty (datrange) || ischar (datrange))), error ("Character string (range) expected for arg # 3"); endif # Check & setup options struct if (nargin < 4 || isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; spsh_opts.strip_array = 1; # Future options: + elseif (isstruct (spsh_opts)) + if (~isfield (spsh_opts', formulas_as_text')), spsh_opts.formulas_as_text = 0; endif + if (~isfield (spsh_opts', strip_array')), spsh_opts.strip_array = 1; endif + % Future options: + else + error ("Structure expected for arg # 4"); endif # Select the proper interfaces @@ -167,7 +189,7 @@ #==================================================================================== -## Copyright (C) 2009 P.R. Nienhuis, <pr.nienhuis at hccnet.nl> +## Copyright (C) 2009,2010 P.R. Nienhuis, <pr.nienhuis at hccnet.nl> ## ## based on mat2xls by Michael Goffioul (2007) <mic...@sw...> ## @@ -211,6 +233,10 @@ ## 2010-10-07 Implemented limits (only reliable for empty input ranges) ## 2010-10-08 Resulting data array now cropped (also in case of specified range) ## 2010-10-10 More code cleanup (shuffled xls tests & wsh ptr code before range checks) +## 2010-10-20 Slight change to Excel range setup +## 2010-10-24 Added check for "live" ActiveX server +## 2010-11-12 Moved ptr struct check into main func +## 2010-11-13 Catch empty sheets when no range was specified function [rawarr, xls, rstatus ] = xls2com2oct (xls, wsh, crange) @@ -222,20 +248,14 @@ warning ("Worksheet name too long - truncated") wsh = wsh(1:31); endif - - # Check the file handle struct - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'COM'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid file pointer struct"); - endif - - app = xls.app; wb = xls.workbook; + # Check to see if ActiveX is still alive + try + wb_cnt = wb.Worksheets.count; + catch + error ("ActiveX invocation in file ptr struct seems non-functional"); + end_try_catch # Check & get handle to requested worksheet wb_cnt = wb.Worksheets.count; @@ -244,6 +264,7 @@ if (wsh < 1 || wsh > wb_cnt) errstr = sprintf ("Worksheet number: %d out of range 1-%d", wsh, wb_cnt); error (errstr) + rstatus = 1; return else old_sh = wsh; @@ -269,8 +290,17 @@ allcells = sh.UsedRange; # Get actually used range indices [trow, brow, lcol, rcol] = getusedrange (xls, old_sh); - nrows = brow - trow + 1; ncols = rcol - lcol + 1; - topleft = calccelladdress (trow, lcol); + if (trow == 0 && brow == 0) + # Empty sheet + rawarr = {}; + printf ("Worksheet '%s' contains no data\n", sh.Name); + return; + else + nrows = brow - trow + 1; ncols = rcol - lcol + 1; + topleft = calccelladdress (trow, lcol); + lowerright = calccelladdress (brow, rcol); + crange = [topleft ':' lowerright]; + endif else # Extract top_left_cell from range [topleft, nrows, ncols, trow, lcol] = parse_sp_range (crange); @@ -280,10 +310,9 @@ if (nrows >= 1) # Get object from Excel sheet, starting at cell top_left_cell - r = sh.Range (topleft); - r = r.Resize (nrows, ncols); - rawarr = r.Value; - delete (r); + rr = sh.Range (crange); + rawarr = rr.Value; + delete (rr); # Take care of actual singe cell range if (isnumeric (rawarr) || ischar (rawarr)) @@ -304,7 +333,7 @@ #================================================================================== -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -350,6 +379,10 @@ ## 2010-08-01 Some bug fixes for formula reading (cvalue rather than scell) ## 2010-10-10 Code cleanup: -getusedrange called; - fixed typo in formula evaluation msg; ## " moved cropping output array to calling function. +## 2010-11-12 Moved ptr struct check into main func +## 2010-11-13 Catch empty sheets when no range was specified +## 2010-11-14 Fixed sheet # index (was offset by -1) in call to getusedrange() in case +#3 of text sheet name arg function [ rawarr, xls, status ] = xls2jpoi2oct (xls, wsh, cellrange=[], spsh_opts) @@ -365,19 +398,8 @@ endif status = 0; jerror = 0; + wb = xls.workbook; - # Check if xls struct pointer seems valid - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'POI'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid xls file struct"); - else - wb = xls.workbook; - endif - # Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = wb.getNumberOfSheets (); if (isnumeric (wsh)) @@ -393,33 +415,23 @@ firstrow = sh.getFirstRowNum (); # 0-based lastrow = sh.getLastRowNum (); # 0-based if (isempty (cellrange)) -# # Get used range by searching (slow...). Beware, it can be bit unreliable -# ## FIXME - can be replaced by call to getusedrange.m -# lcol = 65535; # Old xls value -# lcol = 1048576; # OOXML (xlsx) max. -# rcol = 0; -# for ii=firstrow:lastrow -# irow = sh.getRow (ii); -# if (~isempty (irow)) -# scol = (irow.getFirstCellNum).intValue (); -# lcol = min (lcol, scol); -# ecol = (irow.getLastCellNum).intValue () - 1; -# rcol = max (rcol, ecol); -# # Keep track of lowermost non-empty row as getLastRowNum() is unreliable -# if ~(irow.getCell(scol).getCellType () == ctype(4) && irow.getCell(ecol).getCellType () == ctype(4)) -# botrow = ii; -# endif -# endif -# endfor if (ischar (wsh)) # get numeric sheet index - ii = wb.getSheetIndex (sh); + ii = wb.getSheetIndex (sh) + 1; else ii = wsh; endif [ firstrow, lastrow, lcol, rcol ] = getusedrange (xls, ii); - nrows = lastrow - firstrow + 1; - ncols = rcol - lcol + 1; + if (firstrow == 0 && lastrow == 0) + # Empty sheet + rawarr = {}; + printf ("Worksheet '%s' contains no data\n", sh.getSheetName ()); + rstatus = 1; + return; + else + nrows = lastrow - firstrow + 1; + ncols = rcol - lcol + 1; + endif else # Translate range to HSSF POI row & column numbers [topleft, nrows, ncols, firstrow, lcol] = parse_sp_range (cellrange); @@ -450,11 +462,11 @@ # Separate switch because form.eval. yields different type switch type_of_cell case ctype (1) # Numeric - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getNumberValue (); + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getNumberValue (); case ctype(2) # String - rawarr (ii+1-firstrow, jj+1-lcol) = char (scell.getStringValue ()); + rawarr {ii+1-firstrow, jj+1-lcol} = char (scell.getStringValue ()); case ctype (5) # Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = scell.BooleanValue (); + rawarr {ii+1-firstrow, jj+1-lcol} = scell.BooleanValue (); otherwise # Nothing to do here endswitch @@ -470,18 +482,18 @@ # Preparations done, get data values into data array switch type_of_cell case ctype(1) # 0 Numeric - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getNumericCellValue (); + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getNumericCellValue (); case ctype(2) # 1 String - rawarr (ii+1-firstrow, jj+1-lcol) = char (scell.getRichStringCellValue ()); + rawarr {ii+1-firstrow, jj+1-lcol} = char (scell.getRichStringCellValue ()); case ctype(3) if (spsh_opts.formulas_as_text) tmp = char (scell.getCellFormula ()); - rawarr (ii+1-firstrow, jj+1-lcol) = ['=' tmp]; + rawarr {ii+1-firstrow, jj+1-lcol} = ['=' tmp]; endif case ctype(4) # 3 Blank # Blank; ignore until further notice case ctype(5) # 4 Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getBooleanCellValue (); + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getBooleanCellValue (); otherwise # 5 Error # Ignore endswitch @@ -492,20 +504,7 @@ if (jerror > 0) warning (sprintf ("xls2oct: %d cached values instead of formula evaluations.\n", jerror)); endif -# # Crop rawarr from empty outer rows & columns -# emptr = cellfun('isempty', rawarr); -# irowt = 1; -# while (all (emptr(irowt, :))), irowt++; endwhile -# irowb = nrows; -# while (all (emptr(irowb, :))), irowb--; endwhile -# icoll = 1; -# while (all (emptr(:, icoll))), icoll++; endwhile -# icolr = ncols; -# while (all (emptr(:, icolr))), icolr--; endwhile -# # Crop cell array -# rawarr = rawarr(irowt:irowb, icoll:icolr); status = 1; - xls.limits = [lcol, rcol; firstrow, lastrow]; endfunction @@ -558,6 +557,8 @@ ## 2010-07-29 Added check for too latge requested data rectangle ## 2010-10-10 Code cleanup: -getusedrange(); moved cropping result array to ## " calling function +## 2010-11-12 Moved ptr struct check into main func +## 2010-11-13 Catch empty sheets when no range was specified function [ rawarr, xls, status ] = xls2jxla2oct (xls, wsh, cellrange=[], spsh_opts) @@ -565,33 +566,22 @@ if (isempty (ctype)) ctype = cell (11, 1); # Get enumerated cell types. Beware as they start at 0 not 1 - ctype(1,1) = (java_get ('jxl.CellType', 'BOOLEAN')).toString (); - ctype(2,1) = (java_get ('jxl.CellType', 'BOOLEAN_FORMULA')).toString (); - ctype(3,1) = (java_get ('jxl.CellType', 'DATE')).toString (); - ctype(4,1) = (java_get ('jxl.CellType', 'DATE_FORMULA')).toString (); - ctype(5,1) = (java_get ('jxl.CellType', 'EMPTY')).toString (); - ctype(6,1) = (java_get ('jxl.CellType', 'ERROR')).toString (); - ctype(7,1) = (java_get ('jxl.CellType', 'FORMULA_ERROR')).toString (); - ctype(8,1) = (java_get ('jxl.CellType', 'NUMBER')).toString (); - ctype(9,1) = (java_get ('jxl.CellType', 'LABEL')).toString (); - ctype(10,1) = (java_get ('jxl.CellType', 'NUMBER_FORMULA')).toString (); - ctype(11,1) = (java_get ('jxl.CellType', 'STRING_FORMULA')).toString (); + ctype( 1) = (java_get ('jxl.CellType', 'BOOLEAN')).toString (); + ctype( 2) = (java_get ('jxl.CellType', 'BOOLEAN_FORMULA')).toString (); + ctype( 3) = (java_get ('jxl.CellType', 'DATE')).toString (); + ctype( 4) = (java_get ('jxl.CellType', 'DATE_FORMULA')).toString (); + ctype( 5) = (java_get ('jxl.CellType', 'EMPTY')).toString (); + ctype( 6) = (java_get ('jxl.CellType', 'ERROR')).toString (); + ctype( 7) = (java_get ('jxl.CellType', 'FORMULA_ERROR')).toString (); + ctype( 8) = (java_get ('jxl.CellType', 'NUMBER')).toString (); + ctype( 9) = (java_get ('jxl.CellType', 'LABEL')).toString (); + ctype(10) = (java_get ('jxl.CellType', 'NUMBER_FORMULA')).toString (); + ctype(11) = (java_get ('jxl.CellType', 'STRING_FORMULA')).toString (); endif - status = 0; + status = 0; + wb = xls.workbook; - # Check if xls struct pointer seems valid - test1 = ~isfield (xls, "xtype"); - test1 = test1 || ~isfield (xls, "workbook"); - test1 = test1 || ~strcmp (char (xls.xtype), 'JXL'); - test1 = test1 || isempty (xls.workbook); - test1 = test1 || isempty (xls.app); - if test1 - error ("Invalid xls file struct"); - else - wb = xls.workbook; - endif - # Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = wb.getNumberOfSheets (); shnames = char (wb.getSheetNames ()); @@ -604,10 +594,6 @@ if (isempty (sh)), error (sprintf ("Worksheet %s not found in file %s", wsh, xls.filename)); endif end - # Check ranges -# firstrow = 0; -# lcol = 0; - if (isempty (cellrange)) # Get numeric sheet pointer (1-based) ii = 1; @@ -621,8 +607,16 @@ endwhile # Get data rectangle row & column numbers (1-based) [firstrow, lastrow, lcol, rcol] = getusedrange (xls, wsh); - nrows = lastrow - firstrow + 1; - ncols = rcol - lcol + 1; + if (firstrow == 0 && lastrow == 0) + # Empty sheet + rawarr = {}; + printf ("Worksheet '%s' contains no data\n", shnames {wsh}); + rstatus = 1; + return; + else + nrows = lastrow - firstrow + 1; + ncols = rcol - lcol + 1; + endif else # Translate range to row & column numbers (1-based) [dummy, nrows, ncols, firstrow, lcol] = parse_sp_range (cellrange); @@ -639,43 +633,85 @@ for ii = firstrow:lastrow scell = sh.getCell (jj-1, ii-1); switch char (scell.getType ()) - case ctype {1, 1} # Boolean - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); - case ctype {2, 1} # Boolean formula + case ctype {1} # Boolean + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); + case ctype {2} # Boolean formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); - rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); endif - case ctype {3, 1} # Date - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); - case ctype {4, 1} # Date formula + case ctype {3} # Date + try + % Older JXL.JAR, returns float + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); + catch + % Newer JXL.JAR, returns date string w. epoch = 1-1-1900 :-( + tmp = strsplit (' ', char (scell.getDate ())); + yy = str2num (tmp{6}); + mo = find (ismember (months, upper (tmp{2})) == 1); + dd = str2num (tmp{3}); + hh = str2num (tmp{4}(1:2)); + mi = str2num (tmp{4}(4:5)); + ss = str2num (tmp{4}(7:8)); + if (~scell.isTime ()) + yy = mo = dd = 0; + endif + rawarr {ii+1-firstrow, jj+1-lcol} = datenum (yy, mo, dd, hh, mi, ss); + end_try_catch + case ctype {4} # Date formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); - rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + unwind_protect + % Older JXL.JAR, returns float + tmp = scell.getValue (); + % if we get here, we got a float (old JXL). + % Check if it is time + if (~scell.isTime ()) + % Reset rawarr <> so it can be processed below as date string + rawarr {ii+1-firstrow, jj+1-lcol} = []; + else + rawarr {ii+1-firstrow, jj+1-lcol} = tmp; + end + unwind_protect_cleanup + if (isempty (rawarr {ii+1-firstrow, jj+1-lcol})) + % Newer JXL.JAR, returns date string w. epoch = 1-1-1900 :-( + tmp = strsplit (' ', char (scell.getDate ())); + yy = str2num (tmp{6}); + mo = find (ismember (months, upper (tmp{2})) == 1); + dd = str2num (tmp{3}); + hh = str2num (tmp{4}(1:2)); + mi = str2num (tmp{4}(4:5)); + ss = str2num (tmp{4}(7:8)); + if (scell.isTime ()) + yy = 0; mo = 0; dd = 0; + end + rawarr {ii+1-firstrow, jj+1-lcol} = datenum (yy, mo, dd, hh, mi, ss); + endif + end_unwind_protect endif - case { ctype {5, 1}, ctype {6, 1}, ctype {7, 1} } + case { ctype {5}, ctype {6}, ctype {7} } # Empty, Error or Formula error. Nothing to do here - case ctype {8, 1} # Number - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); - case ctype {9, 1} # String - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getString (); - case ctype {10, 1} # Numerical formula + case ctype {8} # Number + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); + case ctype {9} # String + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getString (); + case ctype {10} # Numerical formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); - rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getValue (); + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); endif - case ctype {11, 1} # String formula + case ctype {11} # String formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); - rawarr (ii+1-firstrow, jj+1-lcol) = ["=" tmp]; + rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else - rawarr (ii+1-firstrow, jj+1-lcol) = scell.getString (); + rawarr {ii+1-firstrow, jj+1-lcol} = scell.getString (); endif otherwise # Do nothing @@ -683,20 +719,7 @@ endfor endfor -# # Crop rawarr from empty outer rows & columns -# emptr = cellfun('isempty', rawarr); -# irowt = 1; -# while (all (emptr(irowt, :))), irowt++; endwhile -# irowb = nrows; -# while (all (emptr(irowb, :))), irowb--; endwhile -# icoll = 1; -# while (all (emptr(:, icoll))), icoll++; endwhile -# icolr = ncols; -# while (all (emptr(:, icolr))), icolr--; endwhile -# # Crop cell array -# rawarr = rawarr(irowt:irowb, icoll:icolr); status = 1; - xls.limits = [lcol, rcol; firstrow, lastrow]; endfunction Modified: trunk/octave-forge/main/io/inst/xlsclose.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsclose.m 2010-11-14 16:51:22 UTC (rev 7914) +++ trunk/octave-forge/main/io/inst/xlsclose.m 2010-11-14 16:53:26 UTC (rev 7915) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -16,15 +16,28 @@ ## -*- texinfo -*- ## @deftypefn {Function File} [@var{xls}] = xlsclose (@var{xls}) +## @deftypefnx {Function File} [@var{xls}] = xlsclose (@var{xls}, @var{filename}) ## Close the Excel spreadsheet pointed to in struct @var{xls}, if needed -## write the file to disk. An empty pointer struct will be returned. -## xlsclose will determine if the file must be written to disk based -## on information contained in @var{xls}. +## write the file to disk. Based on information contained in @var{xls}, +## xlsclose will determine if the file should be written to disk. ## -## You need MS-Excel (95 - 2003), and/or the Java package > 1.2.6 plus Apache -## POI > 3.5 installed on your computer + proper javaclasspath set, to make -## this function work at all. +## If no errors occured during writing, the xls file pointer struct will be +## reset and -if COM interface was used- ActiveX/Excel will be closed. +## However if errors occurred, the file pinter will be ontouched so you can +## clean up before a next try with xlsclose(). +## Be warned that until xlsopen is called again with the same @var{xls} pointer +## struct and @var{_keepxls_} omitted or set to false, hidden Excel or Java +## applications with associated (possibly large) memory chunks are kept alive +## taking up resources. ## +## @var{filename} can be used to write changed spreadsheet files to +## an other file than opened with xlsopen(); unfortunately this doesn't work +## with JXL (JExcelAPI) interface. +## +## You need MS-Excel (95 - 2010), and/or the Java package > 1.2.6 plus Apache +## POI > 3.5 and/or JExcelAPI installed on your computer + proper +## javaclasspath set, to make this function work at all. +## ## @var{xls} must be a valid pointer struct made by xlsopen() in the same ## octave session. ## @@ -41,15 +54,44 @@ ## ## @end deftypefn - ## Author: Philip Nienhuis ## Created: 2009-11-29 ## Updates: ## 2010-01-03 (checked OOXML support) ## 2010-08-25 See also: xlsopen (instead of xlsclose) +## 2010-10-20 Improved tracking of file changes and need to write it to disk +## 2010-10-27 Various changes to catch errors when writing to disk; +## " Added input arg "keepxls" for use with xlswrite.m to save the +## " untouched file ptr struct in case of errors rather than wipe it +## 2010-11-12 Replaced 'keepxls' by new filename arg; catch write errors and +## always keep file pointer in case of write errors -function [ xls ] = xlsclose (xls) +function [ xls ] = xlsclose (xls, filename=[]) + if (~isempty (filename)) + if (ischar (filename)) + if (xls.changed == 0) + warning ("File %s wasn't changed, new filename ignored.", filename); + else + if (strcmp (xls.xtype, 'JXL')) + warning ("JXL doesn't support changing filename, new filename ignored."); + elseif ~(strcmp (xls.xtype, 'COM') || strmatch ('.xls', filename)) + # Excel / ActiveX will write any filename extension + error ('No .xls or .xlsx filename extension specified'); + else + ### For multi-user environments, uncomment below AND relevant stanza in xlsopen + # In case of COM, be sure to first close the open workbook + #if (strcmp (xls.xtype, \xC7OM')) + # xls.app.Application.DisplayAlerts = 0; + # xls.workbook.close(); + # xls.app.Application.DisplayAlerts = 0; + #endif + xls.filename = filename; + endif + endif + endif + endif + if (strcmp (xls.xtype, 'COM')) # If file has been changed, write it out to disk. # @@ -62,45 +104,72 @@ # 51 = .xlsx - xlOpenXMLWorkbook (without macro's in 2007) # 52 = .xlsm - xlOpenXMLWorkbookMacroEnabled (with or without macro's in 2007) # 56 = .xls - xlExcel8 (97-2003 format in Excel 2007) + # (see Excel Help, VB reference, Enumerations, xlFileType) + + # xls.changed = 0: no changes: just close; + # 1: existing file with changes: save, close. + # 2: new file with data added: save, close + # 3: new file, no added added (empty): close & delete on disk - unwind_protect - xls.app.Application.DisplayAlerts = 0; - if (xls.changed > 0) + xls.app.Application.DisplayAlerts = 0; + try + if (xls.changed > 0 && xls.changed < 3) if (xls.changed == 2) # Probably a newly created, or renamed, Excel file printf ("Saving file %s ...\n", xls.filename); xls.workbook.SaveAs (canonicalize_file_name (xls.filename)); elseif (xls.changed == 1) - # Just updated exiting Excel file + # Just updated existing Excel file xls.workbook.Save (); endif + xls.changed = 0; xls.workbook.Close (canonicalize_file_name (xls.filename)); endif - unwind_protect_cleanup xls.app.Quit (); delete (xls.workbook); # This statement actually closes the workbook delete (xls.app); # This statement actually closes down Excel - end_unwind_protect + catch + xls.app.Application.DisplayAlerts = 1; + end_try_catch elseif (strcmp (xls.xtype, 'POI')) - if (xls.changed > 0) - if (xls.changed == 2) printf ("Saving file %s...\n", xls.filename); endif - xlsout = java_new ("java.io.FileOutputStream", xls.filename); - xls.workbook.write (xlsout); - xlsout.close (); + if (xls.changed > 0 && xls.changed < 3) + try + xlsout = java_new ("java.io.FileOutputStream", xls.filename); + if (xls.changed == 2) printf ("Saving file %s...\n", xls.filename); endif + xls.workbook.write (xlsout); + xlsout.close (); + xls.changed = 0; + catch +# xlsout.close (); + end_try_catch endif elseif (strcmp (xls.xtype, 'JXL')) - if (xls.changed > 0) - if (xls.changed == 2) printf ("Saving file %s...\n", xls.filename); endif - (xls.workbook).write (); + if (xls.changed > 0 && xls.changed < 3) + try + if (xls.changed == 2) printf ("Saving file %s...\n", xls.filename); endif + xls.workbook.write (); + xls.workbook.close (); + if (xls.changed == 3) + # Upon entering write mode, JExcelAPI always makes a disk file + # Incomplete new files (no data added) had better be deleted. + xls.workbook.close (); + delete (xls.filename); + endif + xls.changed = 0; + catch + end_try_catch endif - (xls.workbook).close (); - + # elseif <other interfaces here> endif - xls = []; + if (xls.changed) + warning (sprintf ("File %s could not be saved. Read-only or in use elsewhere?\nFile pointer preserved.", xls.filename)); + else + xls = []; + endif endfunction Modified: trunk/octave-forge/main/io/inst/xlsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/xlsopen.m 2010-11-14 16:51:22 UTC (rev 7914) +++ trunk/octave-forge/main/io/inst/xlsopen.m 2010-11-14 16:53:26 UTC (rev 7915) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -33,10 +33,11 @@ ## following jars in your javaclasspath: poi-ooxml-schemas-3.5.jar, ## xbean.jar and dom4j-1.6.1.jar (or later versions). ## -## @var{filename} should be a valid .xls or xlsx Excel file name; but if you use the -## COM interface you can specify any extension that your installed Excel version -## can read AND write. If @var{filename} does not contain any directory path, -## the file is saved in the current directory. +## @var{filename} should be a valid .xls or xlsx Excel file name (including +## extension); but if you use the COM interface you can specify any extension +## that your installed Excel version can read AND write, using the Java +## interfaces only .xls or .xlsx are allowed. If @var{filename} does not +## contain any directory path, the file is saved in the current directory. ## ## If @var{readwrite} is set to 0 (default value) or omitted, the Excel file ## is opened for reading. If @var{readwrite} is set to True or 1, an Excel @@ -76,154 +77,211 @@ ## should be [] ## 2010-08-25 Improved help text ## 2010-09-27 Improved POI help message for unrecognized .xls format to hint for BIFF5/JXL +## 2010-10-20 Improved code for tracking changes to new/existing files +## " Lots of code cleanup, improved error checking and catching +## " Implemented fallback to JXL if POI can't read a file. +## 2010-10-30 More fine-grained file existence/writable checks +## 2010-11-01 Added <COM>.Application.DisplayAlerts=0 in COM section to avoid Excel pop-ups +## 2010-11-05 Option for multiple requested interface types (cell array) +## " Bug fix: JXL fallback from POI for BIFF5 is only useful for reading +## 2010-11-05 Slight change to reporting to screen +## 2010-11-08 Tested with POI 3.7 (OK) +## 2010-11-10 Texinfo header updated ## -## 2010-09-27 Latest subfunction update +## 2010-11-05 Latest subfunction update function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[]) persistent xlsinterfaces; persistent chkintf; + # xlsinterfaces.<intf> = [] (not yet checked), 0 (found to be unsupported) or 1 (OK) if (isempty (chkintf)) xlsinterfaces = struct ( "COM", [], "POI", [], "JXL", [] ); chkintf = 1; endif - - if (nargout < 1) usage ("XLS = xlsopen (Xlfile, [Rw]). But no return argument specified!"); endif + if (nargout < 1) + usage ("XLS = xlsopen (Xlfile [, Rw] [, reqintf]). But no return argument specified!"); + endif + if (~(islogical (xwrite) || isnumeric (xwrite))) + usage ("Numerical or logical value expected for arg # 2") + endif if (~isempty (reqinterface)) - # Try to invoke requested interface for this call. Check if it - # is supported anyway by emptying the corresponding var. - if (strcmp (tolower (reqinterface), tolower ('COM'))) - printf ("Excel/COM interface requested... "); - xlsinterfaces.COM = []; xlsinterfaces.POI = 0; xlsinterfaces.JXL = 0; - elseif (strcmp (tolower (reqinterface), tolower ('POI'))) - printf ("Java/Apache POI interface requested... "); - xlsinterfaces.COM = 0; xlsinterfaces.POI = []; xlsinterfaces.JXL = 0; - elseif (strcmp (tolower (reqinterface), tolower ('JXL'))) - printf ("Java/JExcelAPI interface requested... "); - xlsinterfaces.COM = 0; xlsinterfaces.POI = 0; xlsinterfaces.JXL = []; - else - usage (sprintf ("Unknown .xls interface \"%s\" requested. Only COM, POI or JXL supported", reqinterface)); - endif + if ~(ischar (reqinterface) || iscell(reqinterface)), usage ("Arg # 3 not recognized"); endif + # Turn arg3 into cell array if needed + if (~iscell (reqinterface)), reqinterface = {reqinterface}; endif + xlsinterfaces.COM = 0; xlsinterfaces.POI = 0; xlsinterfaces.JXL = 0; + for ii=1:numel (reqinterface) + reqintf = toupper (reqinterface {ii}); + # Try to invoke requested interface(s) for this call. Check if it + # is supported anyway by emptying the corresponding var. + if (strcmp (reqintf, 'COM')) + xlsinterfaces.COM = []; + elseif (strcmp (reqintf, 'POI')) + xlsinterfaces.POI = []; + elseif (strcmp (reqintf, 'JXL')) + xlsinterfaces.JXL = []; + else + usage (sprintf ("Unknown .xls interface \"%s\" requested. Only COM, POI or JXL supported", reqinterface{})); + endif + endfor + printf ("Checking interface(s):\n"); xlsinterfaces = getxlsinterfaces (xlsinterfaces); - - # Well, is the requested interface supported on the system? - if (~xlsinterfaces.(toupper (reqinterface))) - # No it aint - error (" ...but that's not supported!"); - endif + # Well, is/are the requested interface(s) supported on the system? + # FIXME check for multiple interfaces + for ii=1:numel (reqinterface) + if (~xlsinterfaces.(toupper (reqinterface{ii}))) + # No it aint + error ("%s is not supported!", reqinterface{ii}); + endif + endfor endif # Var xwrite is really used to avoid creating files when wanting to read, or # not finding not-yet-existing files when wanting to write. - if (xwrite) xwrite = 1; endif # Be sure it's either 0 or 1 initially - - # Check if Excel file exists - fid = fopen (filename, 'rb'); - if (fid < 0) - if (~xwrite) - err_str = sprintf ("File %s not found\n", filename); - error (err_str) - else - printf ("Creating file %s\n", filename); - xwrite = 2; + # Check if Excel file exists. Adapt file open mode for readwrite argument + if (xwrite), fmode = 'r+b'; else fmode = 'rb'; endif + fid = fopen (filename, fmode); + if (fid < 0) # File doesn't exist... + if (~xwrite) # ...which obviously is fatal for reading... + error ( sprintf ("File %s not found\n", filename)); + else # ...but for writing, we need more info: + fid = fopen (filename, 'rb'); # Check if it exists at all... + if (fid < 0) # File didn't exist yet. Simply create it + printf ("Creating file %s\n", filename); + xwrite = 3; + else # File exists, but is not writable => Error + fclose (fid); # Do not forget to close the handle neatly + error (sprintf ("Write mode requested but file %s is not writable\n", filename)) + endif endif else - # close file anyway to avoid COM or Java errors + # Close file anyway to avoid COM or Java errors fclose (fid); endif # Check for the various Excel interfaces. No problem if they've already # been checked, getxlsinterfaces (far below) just returns immediately then. - xlsinterfaces = getxlsinterfaces (xlsinterfaces); # Supported interfaces determined; Excel file type check moved to seperate interfaces. chk1 = strcmp (tolower (filename(end-3:end)), '.xls'); chk2 = strcmp (tolower (filename(end-4:end-1)), '.xls'); + # Initialize file ptr struct xls = struct ("xtype", 'NONE', "app", [], "filename", [], "workbook", [], "changed", 0, "limits", []); - + + # Keep track of which interface is selected + xlssupport = 0; + # Interface preference order is defined below: currently COM -> POI -> JXL - - if (xlsinterfaces.COM) + if (xlsinterfaces.COM && ~xlssupport) # Excel functioning has been tested above & file exists, so we just invoke it - xls.xtype = 'COM'; app = actxserver ("Excel.Application"); - xls.app = app; - if (xwrite < 2) - # Open workbook - wb = app.Workbooks.Open (canonicalize_file_name (filename)); - elseif (xwrite == 2) - # Create a new workbook - wb = app.Workbooks.Add (); - endif - xls.workbook = wb; - xls.filename = filename; + try # Because Excel itself can still crash on file formats etc. + app.Application.DisplayAlerts = 0; + if (xwrite < 2) + # Open workbook + wb = app.Workbooks.Open (canonicalize_file_name (filename)); + elseif (xwrite > 2) + # Create a new workbook + wb = app.Workbooks.Add (); + ### Uncommenting the below statement can be useful in multi-user environments. + ### Be sure to uncomment correspondig stanza in xlsclose to avoid zombie Excels + # wb.SaveAs (canonicalize_file_name (filename)) + endif + xls.app = app; + xls.xtype = 'COM'; + xls.workbook = wb; + xls.filename = filename; + xlssupport += 1; + catch + warning ( sprintf ("ActiveX error trying to open or create file %s\n", filename)); + app.Application.DisplayAlerts = 1; + app.Quit (); + delete (app); + end_try_catch + endif - elseif (xlsinterfaces.POI) + if (xlsinterfaces.POI && ~xlssupport) if ~(chk1 || chk2) error ("Unsupported file format for xls2oct / Apache POI.") endif - xls.xtype = 'POI'; # Get handle to workbook - if (xwrite == 2) - if (chk1) - wb = java_new ('org.apache.poi.hssf.usermodel.HSSFWorkbook'); - elseif (chk2) - wb = java_new ('org.apache.poi.xssf.usermodel.XSSFWorkbook'); + try + if (xwrite > 2) + if (chk1) + wb = java_new ('org.apache.poi.hssf.usermodel.HSSFWorkbook'); + elseif (chk2) + wb = java_new ('org.apache.poi.xssf.usermodel.XSSFWorkbook'); + else + # Nothing; we let the user encounter the full java error text + endif + xls.app = 'new_POI'; else - # Nothing; we let the user encounter the full java error text - endif - xls.app = 'new_POI'; - else - try xlsin = java_new ('java.io.FileInputStream', filename); wb = java_invoke ('org.apache.poi.ss.usermodel.WorkbookFactory', 'create', xlsin); xls.app = xlsin; - catch - error ("File format not supported. Hint: perhaps it's (Excel 95) - try JXL"); - end_try_catch - endif - xls.workbook = wb; - xls.filename = filename; + endif + xls.xtype = 'POI'; + xls.workbook = wb; + xls.filename = filename; + xlssupport += 2; + catch + clear xlsin; + if (xlsinterfaces.JXL) + printf ('Couldn''t open file %s using POI; trying Excel''95 format with JXL...\n', filename); + endif + end_try_catch + endif - elseif (xlsinterfaces.JXL) + if (xlsinterfaces.JXL && ~xlssupport) if (~chk1) error ("Currently xls2oct / JXL can only read reliably from .xls files") endif - xls.xtype = 'JXL'; - xlsin = java_new ('java.io.File', filename); - if (xwrite == 2) - # Get handle to new xls-file - wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsin); + try + xlsin = java_new ('java.io.File', filename); + if (xwrite > 2) + # Get handle to new xls-file + wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsin); + else + # Open existing file + wb = java_invoke ('jxl.Workbook', 'getWorkbook', xlsin); + endif + xls.xtype = 'JXL'; + xls.app = xlsin; + xls.workbook = wb; + xls.filename = filename; + xlssupport += 4; + catch + clear xlsin; + if (xlsinterfaces.POI) + printf ('... No luck with JXL, unsupported file format.\n', filename); + endif + end_try_catch + endif + + # if + # ---- other interfaces + # endif + + if (~xlssupport) + if (isempty (reqinterface)) + warning ("No support for Excel .xls I/O"); else - # Open existing file - wb = java_invoke ('jxl.Workbook', 'getWorkbook', xlsin); + warning ("File type not supported by %s %s %s %s", reqinterface{:}); endif - xls.app = xlsin; - xls.workbook = wb; - xls.filename = filename; - - # elseif ---- other interfaces - + xls = []; else - warning ("No support for Excel .xls I/O"); - xls = []; - endif - - if (~isempty (xls)) - # From here on xwrite is tracked via xls struct in the various lower + # From here on xwrite is tracked via xls.changed in the various lower # level r/w routines and it is only used to determine if an informative # message is to be given when saving a newly created xls file. - xls.changed = xwrite; # Until something was written to existing files we keep status "unchanged". - # xls.changed = 0 (existing/only read from), 1 (existing/data added), 2 (new). - + # xls.changed = 0 (existing/only read from), 1 (existing/data added), 2 (new, + # data added) or 3 (pristine, no data added). if (xls.changed == 1) xls.changed = 0; endif - endif # Rounding up. If none of the xlsinterfaces is supported we're out of luck. @@ -236,7 +294,7 @@ endfunction -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -277,18 +335,20 @@ ## 2009-12-27 Make sure proper dimensions are checked in parsed javaclasspath ## 2010-09-11 Rearranged code and clarified messages about missing classes ## 2010-09-27 More code cleanup +## 2010-10-20 Added check for minimum Java version (should be >= 6 / 1.6) +## 2010-11-05 Slight change to reporting to screen function [xlsinterfaces] = getxlsinterfaces (xlsinterfaces) + persistent tmp1 = []; persistent jcp; # Java class path + if (isempty (xlsinterfaces.COM) && isempty (xlsinterfaces.POI) && isempty (xlsinterfaces.JXL)) - chk1 = 1; - printf ("Supported interfaces: "); - else - chk1= 0; + printf ("Looking for supported interfaces:\n"); endif # Check if MS-Excel COM ActiveX server runs if (isempty (xlsinterfaces.COM)) + printf ("Excel/COM... "); xlsinterfaces.COM = 0; try app = actxserver ("Excel.application"); @@ -296,84 +356,97 @@ xlsinterfaces.COM = 1; # Close Excel. Yep this is inefficient when we need only one r/w action, # but it quickly pays off when we need to do more with the same file - # (+, MS-Excel code is in OS cache after this call anyway so no big deal) + # (+, MS-Excel code is in OS cache anyway after this call so no big deal) app.Quit(); delete(app); - printf ("Excel (COM) OK. "); - chk1 = 1; + printf ("OK.\n"); catch # COM non-existent + printf ("not working.\n"); end_try_catch endif - try - tmp1 = javaclasspath; - # If we get here, at least Java works. Now check for proper entries - # in class path. Under *nix the classpath must first be split up - if (isunix) tmp1 = strsplit (char (tmp1), ":"); endif - catch - # No Java support found - xlsinterfaces.POI = 0; - xlsinterfaces.JXL = 0; - if ~(isempty (xlsinterfaces.POI) && isempty (xlsinterfaces.JXL)) - # Some Java-based interface requested but Java support is absent - error ('No Java support found.'); - else - # No specific Java-based interface requested. Just return - return; - endif - end_try_catch + if (isempty (tmp1)) + # Check Java support. First try javaclasspath + try + jcp = javaclasspath; + # If we get here, at least Java works. Now check for proper version (>= 1.6) + jver = char (java_invoke ('java.lang.System', 'getProperty', 'java.version')); + cjver = strsplit (jver, '.'); + if (sscanf (cjver{2}, '%d') < 6) + warning ("Java version too old - you need at least Java 6 (v. 1.6.x.x)\n"); + return + endif + # Now check for proper entries in class path. Under *nix the classpath + # must first be split up + if (isunix) jcp = strsplit (char (jcp), ":"); endif + tmp1 = 1; + catch + # No Java support found + xlsinterfaces.POI = 0; + xlsinter... [truncated message content] |
From: <prn...@us...> - 2010-11-14 16:55:25
|
Revision: 7916 http://octave.svn.sourceforge.net/octave/?rev=7916&view=rev Author: prnienhuis Date: 2010-11-14 16:55:15 +0000 (Sun, 14 Nov 2010) Log Message: ----------- Various bug fixes; better tracking of changes to files; tested w jOpenDocument 1.2 final (which still has limitations / bugs) Modified Paths: -------------- trunk/octave-forge/main/io/inst/oct2ods.m trunk/octave-forge/main/io/inst/ods2oct.m trunk/octave-forge/main/io/inst/odsclose.m trunk/octave-forge/main/io/inst/odsopen.m trunk/octave-forge/main/io/inst/odsread.m trunk/octave-forge/main/io/inst/odswrite.m Modified: trunk/octave-forge/main/io/inst/oct2ods.m =================================================================== --- trunk/octave-forge/main/io/inst/oct2ods.m 2010-11-14 16:53:26 UTC (rev 7915) +++ trunk/octave-forge/main/io/inst/oct2ods.m 2010-11-14 16:55:15 UTC (rev 7916) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <pr.nienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <pr.nienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -104,11 +104,16 @@ ## 2010-08-23 Added check on validity of ods file ptr ## " Experimental support for odfdom 0.8.6 (in separate subfunc, to be integrated later) ## 2010-08-25 Improved help text (java memory, ranges) +## 2010-10-27 Improved file change tracking tru ods.changed +## 2010-11-12 Better input argument checks +## 2010-11-13 Reset ods.limits when read was successful +## 2010-11-13 Added check for 2-D input array ## -## Last update of subfunctions below: 2010-08-23 +## Last update of subfunctions below: 2011-11-12 function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange=[], spsh_opts=[]) + if (nargin < 2) error ("oct2xls needs a minimum of 2 arguments."); endif # Check if input array is cell if (isempty (c_arr)) warning ("Request to write empty matrix - ignored."); @@ -122,21 +127,31 @@ elseif (~iscell (c_arr)) error ("oct2ods: input array neither cell nor numeric array"); endif - - # Check ods file ptr - odschk = 1; - odschk = odschk && isstruct(ods); - odschk = odschk && (~isempty (ods.filename)); - odschk = odschk && (ods.xtype == 'OTK' || ods.xtype == 'JOD'); - if (~odschk) error ("Arg # 2 is an invalid ods file ptr\n"); endif - - # Check and if needed initialize spsh_opts - if isempty (spsh_opts) + if (ndims (c_arr) > 2), error ("Only 2-dimensional arrays can be written to spreadsheet"); endif + # Check ods file pointer struct + test1 = ~isfield (ods, "xtype"); + test1 = test1 || ~isfield (ods, "workbook"); + test1 = test1 || isempty (ods.workbook); + test1 = test1 || isempty (ods.app); + if test1 + error ("Invalid ods file pointer struct"); + endif + # Check worksheet ptr + if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 3"); endif + # Check range + if (~(isempty (crange) || ischar (crange))), error ("Character string (range) expected for arg # 4"); endif + # Various options + if (isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; - # Other options here + # other options to be implemented here + elseif (isstruct (spsh_opts)) + if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif + # other options to be implemented here + else + error ("Structure expected for arg # 5"); endif - if (nargout < 1) printf ("Warning: no output spreadsheet file pointer specified as argument.\n"); endif + if (nargout < 1) printf ("Warning: no output spreadsheet file pointer specified.\n"); endif if (strcmp (ods.xtype, 'OTK')) # Write ods file tru Java & ODF toolkit. @@ -148,18 +163,17 @@ otherwise error ("Unsupported odfdom version"); endswitch - elseif (strcmp (ods.xtype, 'JOD')) # Write ods file tru Java & jOpenDocument. API still leaves lots to be wished... [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh, crange); - -# elseif ---- < Other interfaces here > - +# elseif + # ---- < Other interfaces here > else error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); - endif + if (rstatus), ods.limits = []; endif + endfunction @@ -191,23 +205,25 @@ ## writing to an existing sheet. In that case one should beware of ## table-number-columns-repeated, table-number-rows-repeated, ## covered (merged) cells, incomplete tables and rows, etc. -## ODF toolkit does nothing to hide this from the user; you may -## sort it out all by yourself. +## ODF toolkit v. 0.7.5 does nothing to hide this from the user; +## you may sort it out all by yourself. ## Author: Philip Nienhuis <prn...@us...> ## Created: 2010-01-07 ## Updates: ## 2010-01-14 (finally seems to work OK) ## 2010-03-08 Some comment lines adapted -## 2010-03-25 Try-catch added f unpatched-for-booleans java-1.2.6 / 1.2.7 package +## 2010-03-25 Try-catch added f. unpatched-for-booleans java-1.2.6 / 1.2.7 package ## 2010-04-11 Changed all references to "cell" to "scell" to avoid reserved keyword -## Small bugfix for cases with empty left columns (wrong cell reference) +## " Small bugfix for cases with empty left columns (wrong cell reference) ## 2010-04-13 Fixed bug with stray cell copies beyond added data rectangle ## 2010-07-29 Added formula input support (based on xls patch by Benjamin Lindner) ## 2010-08-01 Added try-catch around formula input ## " Changed range arg to also allow just topleft cell ## 2010-08-03 Moved range checks and type array parsing to separate functions -## 2010-08-13 Fixed empty Sheet1 in case of new spreadsheets fix input text sheet name +## 2010-08-13 Fixed empty Sheet1 in case of new spreadsheets, fix input text sheet name +## 2010-10-27 Improved file change tracking tru ods.changed +## 2010-11-12 Improved file change tracking tru ods.changed function [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh, crange, spsh_opts) @@ -217,7 +233,7 @@ ctype = [1, 2, 3, 4, 5, 6, 7]; endif - rstatus = 0; changed = 0; f_errs = 0; + rstatus = 0; f_errs = 0; # Get some basic spreadsheet data from the pointer using ODFtoolkit odfcont = ods.workbook; @@ -248,7 +264,7 @@ endwhile if (ischar (wsh) && nr_of_sheets < 256) newsh = 1; endif else # Sheet index specified - if ((ods.changed == 2) || (wsh > nr_of_sheets && wsh < 256)) # Max nr of sheets = 256 + if ((ods.changed > 2) || (wsh > nr_of_sheets && wsh < 256)) # Max nr of sheets = 256 # Create a new sheet newsh = 1; elseif (wsh <=nr_of_sheets && wsh > 0) @@ -279,13 +295,12 @@ # Prepare worksheet for writing. If needed create new sheet if (newsh) - if (ods.changed == 2) + if (ods.changed > 2) # New spreadsheet. Prepare to use the default 1x1 first sheet. sh = sheets.item(0); else # Other sheets exist, create a new sheet. First the basics sh = java_new ('org.odftoolkit.odfdom.doc.table.OdfTable', odfcont); - changed = 1; # Append sheet to spreadsheet ( contentRoot) offsprdsh.appendChild (sh); # Rebuild sheets nodes @@ -303,7 +318,7 @@ wsh = sheets.getLength () - 1; endif # Fixup wsh pointer in case of new spreadsheet - if (ods.changed == 2) wsh = 0; endif + if (ods.changed > 2) wsh = 0; endif # Add table-column entry for style etc col = sh.addTableColumn (); @@ -349,7 +364,7 @@ # Only now add drow as otherwise for each cell an empty table-column is # inserted above the rows (odftoolkit bug?) sh.appendRow (drow); - if (ods.changed == 2) + if (ods.changed > 2) # In case of a completely new spreadsheet, delete the first initial 1-cell row # But check if it *is* a row... try @@ -363,6 +378,7 @@ nrow = drow.cloneNode (1); # Deep copy sh.appendRow (nrow); endfor + ods.changed = min (ods.changed, 2); # Keep 2 for new spshsht, 1 for existing + changed else # Existing sheet. We must be prepared for all situations, incomplete rows, @@ -393,7 +409,6 @@ # Apparently a nr-rows-repeated top table-row must be split, as the # first data row seems to be projected in it (1st while condition above!) row.removeAttribute ('table:number-rows-repeated'); - changed = 1; row.getCellAt (0).removeAttribute ('table:number-columns-repeated'); nrow = row.cloneNode (1); drow = nrow; # Future upper data array row @@ -421,7 +436,6 @@ sh.appendRow (row); drow.appendCell (dcell); sh.appendRow (drow); - changed = 1; endif endif @@ -438,13 +452,11 @@ scell.setTableNumberColumnsRepeatedAttribute (lcol + 1); row.appendCell (scell); sh.appendRow (row); - changed = 1; else # If needed expand nr-rows-repeated repcnt = row.getTableNumberRowsRepeatedAttribute (); if (repcnt > 1) row.removeAttribute ('table:number-rows-repeated'); - changed = 1; # Insert new table-rows above row until our new data space is complete. # Keep handle of upper new table-row as that's where data are added 1st drow = row.cloneNode (1); @@ -475,7 +487,6 @@ if (csplit > 0) # Apparently a nr-columns-repeated cell must be split scell.removeAttribute ('table:number-columns-repeated'); - changed = 1; ncell = scell.cloneNode (1); if (repcnt > 1) scell.setTableNumberColumnsRepeatedAttribute (repcnt - csplit); @@ -494,7 +505,6 @@ scell = dcell.cloneNode (1); dcell.setTableNumberColumnsRepeatedAttribute (-csplit); row.appendCell (dcell); - changed = 1; row.appendCell (scell); endif endif @@ -508,13 +518,11 @@ # Apparently end of row encountered. Add cell scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); scell = row.appendCell (scell); - changed = 1; else # If needed expand nr-cols-repeated repcnt = scell.getTableNumberColumnsRepeatedAttribute (); if (repcnt > 1) scell.removeAttribute ('table:number-columns-repeated'); - changed = 1; for kk=2:repcnt ncell = scell.cloneNode (1); row.insertBefore (ncell, scell.getNextSibling ()); @@ -525,7 +533,6 @@ while (scell.hasChildNodes ()) tmp = scell.getFirstChild (); scell.removeChild (tmp); - changed = 1; endwhile scell.removeAttribute ('table:formula'); endif @@ -594,7 +601,6 @@ otherwise # Nothing endswitch - changed = 1; scell = scell.getNextSibling (); @@ -607,10 +613,8 @@ if (f_errs) printf ("%d formula errors encountered - please check input array\n", f_errs); endif - if (changed) - ods.changed = 1; - rstatus = 1; - endif + ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) + rstatus = 1; endfunction @@ -651,6 +655,8 @@ ## 2010-06-05 odfdom 0.8.5 is there, next try.... ## 2010-06-## odfdom 0.8.5 dropped, too buggy ## 2010-08-22 odfdom 0.8.6 is there... seems to work with just one bug, easily worked around +## 2010-10-27 Improved file change tracking tru ods.changed +## 2010-11-12 Improved file change tracking tru ods.changed function [ ods, rstatus ] = oct3jotk2ods (c_arr, ods, wsh, crange, spsh_opts) @@ -718,8 +724,13 @@ # Prepare spreadsheet for writing (size, etc.). If needed create new sheet if (newsh) - # Create a new sheet using DOM API. This part works OK. - sh = sheets.get (nr_of_sheets - 1).newTable (spsh, nrows, ncols); + if (ods.changed > 2) + # New spreadsheet, use default first sheet + sh = sheets.get (0); + else + # Create a new sheet using DOM API. This part works OK. + sh = sheets.get (nr_of_sheets - 1).newTable (spsh, nrows, ncols); + endif changed = 1; if (isnumeric (wsh)) # Give sheet a name @@ -793,7 +804,7 @@ endfor if (changed) - ods.changed = 1; + ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) rstatus = 1; endif @@ -840,21 +851,11 @@ ## " Code cleanup ## 2010-08-13 Fixed bug of ignoring text sheet name in case of new spreadsheet ## 2010-08-15 Fixed bug with invalid first sheet in new spreadsheets +## 2010-10-27 Improved file change tracking tru ods.changed +## 2010-11-12 Improved file change tracking tru ods.changed function [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh, crange) - # Check jOpenDocument version - sh = ods.workbook.getSheet (0); - cl = sh.getCellAt (0, 0); - try - # Versions 1.2b3+ have public getValueType () - cl.getValueType (); - ver = 3; - catch - # 1.2b2 has not - ver = 2; - end_try_catch - rstatus = 0; sh = []; changed = 0; # Get worksheet. Use first one if none given @@ -871,9 +872,9 @@ if (isempty (sh)) # Sheet number wsh didn't exist yet wsh = sprintf ("Sheet%d", wsh+1); - elseif (ods.changed == 2) + elseif (ods.changed > 2) sh.setName ('Sheet1'); - ods.changed = 0; + changed = 1; endif endif endif @@ -882,16 +883,17 @@ sh = ods.workbook.getSheet (wsh); if (isempty (sh)) # Still doesn't exist. Create sheet - if (ver == 3) - if (ods.changed == 2) + if (ods.odfvsn == 3) + if (ods.changed > 2) # 1st "new" -unnamed- sheet has already been made when creating the spreadsheet sh = ods.workbook.getSheet (0); sh.setName (wsh); - ods.changed = 0; + changed = 1; else # For existing spreadsheets printf ("Adding sheet '%s'\n", wsh); sh = ods.workbook.addSheet (sh_cnt, wsh); + changed = 1; endif else error ("jOpenDocument v. 1.2b2 does not support adding sheets - upgrade to v. 1.2b3\n"); @@ -950,6 +952,7 @@ val = c_arr {ii, jj}; if ((isnumeric (val) && ~isnan (val)) || ischar (val) || islogical (val)) try + sh.getCellAt (jj + lcol - 1, ii + trow - 1).clearValue(); jcell = sh.getCellAt (jj + lcol - 1, ii + trow - 1).setValue (val); changed = 1; catch @@ -961,7 +964,7 @@ endfor if (changed) - ods.changed = 1; + ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) rstatus = 1; endif Modified: trunk/octave-forge/main/io/inst/ods2oct.m =================================================================== --- trunk/octave-forge/main/io/inst/ods2oct.m 2010-11-14 16:53:26 UTC (rev 7915) +++ trunk/octave-forge/main/io/inst/ods2oct.m 2010-11-14 16:55:15 UTC (rev 7916) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <pr.nienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <pr.nienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -110,26 +110,39 @@ ## 2010-08-25 Improved helptext (moved some text around) ## 2010-08-27 Added ods3jotk2oct - internal function for odfdom-0.8.6.jar ## " Extended check on spsh_opts (must be a struct) +## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to here ## -## (Latest update of subfunctions below: 2010-08-27) +## (Latest update of subfunctions below: 2010-11-13) function [ rawarr, ods, rstatus ] = ods2oct (ods, wsh=1, datrange=[], spsh_opts=[]) - # Check ods file ptr - odschk = 1; - odschk = odschk && isstruct(ods); - odschk = odschk && (~isempty (ods.filename)); - odschk = odschk && (ods.xtype == 'OTK' || ods.xtype == 'JOD'); - if (~odschk) error ("Arg # 1 is an invalid ods file ptr\n"); endif - - if isempty (spsh_opts) + # Check if ods struct pointer seems valid + if (~isstruct (ods)), error ("File ptr struct expected for arg @ 1"); endif + test1 = ~isfield (ods, "xtype"); + test1 = test1 || ~isfield (ods, "workbook"); + test1 = test1 || isempty (ods.workbook); + test1 = test1 || isempty (ods.app); + if (test1) + error ("Arg #1 is an invalid ods file struct"); + endif + # Check worksheet ptr + if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 2"); endif + # Check range + if (~(isempty (datrange) || ischar (datrange))), error ("Character string (range) expected for arg # 3"); endif + # Check & setup options struct + if (nargin < 4 || isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; + spsh_opts.strip_array = 1; # Other options here - # elseif (~isstruct (spsh_opts)) error ("struct expected for OPTIONS argument (# 4)"); + else + if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif + if (~isfield (spsh_opts, 'strip_array')), spsh_opts.strip_array = 1; endif + % Future options: endif - + + # Select the proper interfaces if (strcmp (ods.xtype, 'OTK')) # Read ods file tru Java & ODF toolkit switch ods.odfvsn @@ -140,15 +153,36 @@ otherwise error ("Unsupported odfdom version or invalid ods file pointer."); endswitch - elseif (strcmp (ods.xtype, 'JOD')) + # Read ods file tru Java & jOpenDocument. JOD doesn't know about formulas :-( [rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, datrange); - -# elseif ---- < Other interfaces here > - +# elseif + # ---- < Other interfaces here > else error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); + endif + # Optionally strip empty outer rows and columns & keep track of original data location + if (spsh_opts.strip_array) + emptr = cellfun ('isempty', rawarr); + if (all (all (emptr))) + rawarr = {}; + ods.limits= []; + else + nrows = size (rawarr, 1); ncols = size (rawarr, 2); + irowt = 1; + while (all (emptr(irowt, :))), irowt++; endwhile + irowb = nrows; + while (all (emptr(irowb, :))), irowb--; endwhile + icoll = 1; + while (all (emptr(:, icoll))), icoll++; endwhile + icolr = ncols; + while (all (emptr(:, icolr))), icolr--; endwhile + + # Crop outer rows and columns and update limits + rawarr = rawarr(irowt:irowb, icoll:icolr); + ods.limits = ods.limits + [icoll-1, icolr-ncols; irowt-1, irowb-nrows]; + endif endif endfunction @@ -156,7 +190,7 @@ #===================================================================== -## Copyright (C) 2009 Philip Nienhuis <prnienhuis _at- users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis _at- users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -186,6 +220,7 @@ ## "" Added call to getusedrange() for cases when no range was specified ## 2010-03-19 More code cleanup & fixes for bugs introduced 18/3/2010 8-() ## 2010-08-03 Added preliminary support for reading back formulas as text strings +## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to caller function [ rawarr, ods, rstatus ] = ods2jotk2oct (ods, wsh, crange, spsh_opts) @@ -363,26 +398,8 @@ ++ii; endwhile - # Crop rawarr from all empty outer rows & columns - # & keep track of limits - emptr = cellfun ('isempty', rawarr); - if (all (all (emptr))) - rawarr = {}; - ods.limits= []; - else - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nrows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = ncols; - while (all (emptr(:, icolr))), icolr--; endwhile - # Crop textarray - rawarr = rawarr(irowt:irowb, icoll:icolr); - rstatus = 1; - ods.limits = [lcol+icoll-1, lcol+icolr-1; trow+irowt-1, trow+irowb-1]; - endif + # Keep track of data rectangle limits + ods.limits = [lcol, rcol; trow, brow]; endfunction @@ -410,7 +427,8 @@ ## Author: Philip Nienhuis <Philip@DESKPRN> ## Created: 2010-08-24. First workable version Aug 27, 2010 ## Updates: -## +## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to caller +## 2010-11-13 Added workaround for reading text cells in files made by jOpenDocument 1.2bx function [ rawarr, ods, rstatus ] = ods3jotk2oct (ods, wsh, crange, spsh_opts) @@ -467,6 +485,7 @@ rcol = min (lcol + ncols - 1, 1024); ncols = min (ncols, 1024 - lcol + 1); nrows = min (nrows, 65536 - trow + 1); + brow = trow + nrows - 1; endif # Create storage for data content @@ -478,13 +497,19 @@ for jj=lcol:ncols+lcol-1; ocell = row.getCellByIndex (jj-1); if ~isempty (ocell) - otype = ocell.getValueType (); + otype = deblank (tolower (ocell.getValueType ())); if (spsh_opts.formulas_as_text) if ~isempty (ocell.getFormula ()) otype = 'formula'; endif endif - switch deblank (tolower (otype)) + # Provisions for catching jOpenDocument 1.2b bug where text cells + # haven't been assigned an <office:value-type='string'> attribute + if (~isempty (ocell)) + if (findstr ('<text:', char (ocell.getOdfElement ()))), otype = 'string'; endif + endif + # At last, read the data + switch otype case {'float', 'currency', 'percentage'} rawarr(ii-trow+1, jj-lcol+1) = ocell.getDoubleValue (); case 'date' @@ -534,39 +559,21 @@ case 'formula' rawarr(ii-trow+1, jj-lcol+1) = ocell.getFormula (); otherwise - # Nothing + # Nothing. endswitch endif endfor endfor - # Crop rawarr from all empty outer rows & columns just like Excel does - # & keep track of limits - emptr = cellfun ('isempty', rawarr); - if (all (all (emptr))) - rawarr = {}; - ods.limits= []; - else - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nrows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = ncols; - while (all (emptr(:, icolr))), icolr--; endwhile - # Crop textarray - rawarr = rawarr(irowt:irowb, icoll:icolr); - rstatus = 1; - ods.limits = [lcol+icoll-1, lcol+icolr-1; trow+irowt-1, trow+irowb-1]; - endif + # Keep track of data rectangle limits + ods.limits = [lcol, rcol; trow, brow]; endfunction #=========================================================================== -## Copyright (C) 2009 Philip Nienhuis <pr.nienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <pr.nienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -591,6 +598,8 @@ ## Last updates: ## 2010-08-12 Added separate stanzas for jOpenDocument v 1.2b3 and up. This version ## allows better cell type parsing and is therefore more reliable +## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to here +## 2010-11-13 Added workaround for reading text cells in files made by jOpenDocument 1.2bx function [ rawarr, ods, rstatus] = ods2jod2oct (ods, wsh, crange) @@ -600,10 +609,8 @@ # Check jOpenDocument version sh = ods.workbook.getSheet (0); cl = sh.getCellAt (0, 0); - try + if (ods.odfvsn == 3) # 1.2b3+ has public getValueType () - cl.getValueType (); - ver = 3; persistent ctype; if (isempty (ctype)) BOOLEAN = char (java_get ('org.jopendocument.dom.ODValueType', 'BOOLEAN')); @@ -614,10 +621,10 @@ STRING = char (java_get ('org.jopendocument.dom.ODValueType', 'STRING')); TIME = char (java_get ('org.jopendocument.dom.ODValueType', 'TIME')); endif - catch - # 1.2b2 has not - ver = 2; - end_try_catch +# else +# # 1.2b2 has not +# ver = 2; + endif if (isnumeric (wsh)) wsh = wsh - 1; endif # Sheet INDEX starts at 0 # Check if sheet exists. If wsh = numeric, nonexistent sheets throw errors. @@ -630,13 +637,14 @@ if (isempty (sh)) error ("No sheet called '%s' present in file %s\n", wsh, ods.filename); endif - + # Either parse (given cell range) or prepare (unknown range) help variables if (isempty (crange)) - if (ver < 3) + if (ods.odfvsn < 3) error ("No empty read range allowed in jOpenDocument version 1.2b2") else - [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh+1); + if (isnumeric (wsh)) wsh = wsh + 1; endif + [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); nrows = brow - trow + 1; # Number of rows to be read ncols = rcol - lcol + 1; # Number of columns to be read endif @@ -650,11 +658,54 @@ rcol = min (lcol + ncols - 1, 1024); ncols = min (ncols, 1024 - lcol + 1); nrows = min (nrows, 65536 - trow + 1); + brow= trow + nrows - 1; endif # Create storage for data content rawarr = cell (nrows, ncols); - if (ver == 2) + if (ods.odfvsn >= 3) + # Version 1.2b3+ + for ii=1:nrows + for jj = 1:ncols + try + scell = sh.getCellAt (lcol+jj-2, trow+ii-2); + sctype = char (scell.getValueType ()); + # Workaround for sheets written by jOpenDocument 1.2bx (no value-type attrb): + if (~isempty (scell)) + if (findstr ('<text:', char (scell))), sctype = STRING; endif + endif + switch sctype + case { FLOAT, CURRENCY, PERCENTAGE } + rawarr{ii, jj} = scell.getValue ().doubleValue (); + case BOOLEAN + rawarr {ii, jj} = scell.getValue () == 1; + case STRING + rawarr{ii, jj} = scell.getValue(); + case DATE + tmp = strsplit (char (scell.getValue ()), ' '); + yy = str2num (tmp{6}); + mo = find (ismember (months, toupper (tmp{2})) == 1); + dd = str2num (tmp{3}); + hh = str2num (tmp{4}(1:2)); + mi = str2num (tmp{4}(4:5)); + ss = str2num (tmp{4}(7:8)); + rawarr{ii, jj} = datenum (yy, mo, dd, hh, mi, ss); + case TIME + tmp = strsplit (char (scell.getValue ().getTime ()), ' '); + hh = str2num (tmp{4}(1:2)) / 24.0; + mi = str2num (tmp{4}(4:5)) / 1440.0; + ss = str2num (tmp{4}(7:8)) / 86600.0; + rawarr {ii, jj} = hh + mi + ss; + otherwise + # Nothing + endswitch + catch + # Probably a merged cell, just skip + # printf ("Error in row %d, col %d (addr. %s)\n", ii, jj, calccelladdress (lcol+jj-2, trow+ii-2)); + end_try_catch + endfor + endfor + else # ods,odfvsn == 3 # 1.2b2 for ii=1:nrows for jj = 1:ncols @@ -696,65 +747,11 @@ endfor endfor - else - # Version 1.2b3+ - for ii=1:nrows - for jj = 1:ncols - try - scell = sh.getCellAt (lcol+jj-2, trow+ii-2); - switch char (scell.getValueType ()) - case { FLOAT, CURRENCY, PERCENTAGE } - rawarr{ii, jj} = scell.getValue ().doubleValue (); - case BOOLEAN - rawarr {ii, jj} = scell.getValue () == 1; - case STRING - rawarr{ii, jj} = scell.getValue(); - case DATE - tmp = strsplit (char (scell.getValue ()), ' '); - yy = str2num (tmp{6}); - mo = find (ismember (months, toupper (tmp{2})) == 1); - dd = str2num (tmp{3}); - hh = str2num (tmp{4}(1:2)); - mi = str2num (tmp{4}(4:5)); - ss = str2num (tmp{4}(7:8)); - rawarr{ii, jj} = datenum (yy, mo, dd, hh, mi, ss); - case TIME - tmp = strsplit (char (scell.getValue ().getTime ()), ' '); - hh = str2num (tmp{4}(1:2)) / 24.0; - mi = str2num (tmp{4}(4:5)) / 1440.0; - ss = str2num (tmp{4}(7:8)) / 86600.0; - rawarr {ii, jj} = hh + mi + ss; - otherwise - # Nothing - endswitch - catch - # Probably a merged cell, just skip - end_try_catch - endfor - endfor endif + + # Keep track of data rectangle limits + ods.limits = [lcol, rcol; trow, brow]; - # Crop rawarr from all empty outer rows & columns just like Excel does - # & keep track of limits - emptr = cellfun ('isempty', rawarr); - if (all (all (emptr))) - rawarr = {}; - ods.limits= []; - else - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nrows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = ncols; - while (all (emptr(:, icolr))), icolr--; endwhile - # Crop textarray - rawarr = rawarr(irowt:irowb, icoll:icolr); - rstatus = 1; - ods.limits = [lcol+icoll-1, lcol+icolr-1; trow+irowt-1, trow+irowb-1]; - endif - rstatus = ~isempty (rawarr); endfunction Modified: trunk/octave-forge/main/io/inst/odsclose.m =================================================================== --- trunk/octave-forge/main/io/inst/odsclose.m 2010-11-14 16:53:26 UTC (rev 7915) +++ trunk/octave-forge/main/io/inst/odsclose.m 2010-11-14 16:55:15 UTC (rev 7916) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -16,10 +16,14 @@ ## -*- texinfo -*- ## @deftypefn {Function File} [@var{ods}] = odsclose (@var{ods}) +## @deftypefnx {Function File} [@var{ods}] = odsclose (@var{ods}, @var{filename}) ## Close the OpenOffice_org Calc spreadsheet pointed to in struct -## @var{ods}, if needed write the file to disk. An empty pointer struct -## will be returned. odsclose will determine if the file must be written -## to disk based on information contained in @var{ods}. +## @var{ods}, if needed write the file to disk. +## odsclose will determine if the file must be written to disk based on +## information contained in @var{ods}. +## An empty pointer struct will be returned if no errors occurred. +## Optional argument @var{filename} can be used to write changed spreadsheet +## files to an other file than opened by odsopen(). ## ## You need the Java package > 1.2.6 plus odfdom.jar + xercesImpl.jar ## and/or jopendocument-<version>.jar installed on your computer + @@ -45,32 +49,64 @@ ## 2010-01-08 (OTK ODS write support) ## 2010-04-13 Improved help text a little bit ## 2010-08-25 Swapped in texinfo help text +## 2010-10-17 Fixed typo in error message about unknown interface +## 2010-10-27 Improved file change tracking tru ods.changed +## 2010-11-12 Keep ods file pointer when write errors occur. +## " Added optional filename arg to change filename to be written to -function [ ods ] = odsclose (ods) +function [ ods ] = odsclose (ods, filename=[]) # If needed warn that dangling spreadsheet pointers may be left if (nargout < 1) warning ("return argument missing - ods invocation not reset."); endif + if (~isempty (filename)) + if (ischar (filename)) + if (ods.changed == 0 || ods.changed > 2) + warning ("File %s wasn't changed, new filename ignored.", ods.filename); + else + if (strfind (tolower (filename), '.sxc') || strfind (tolower (filename), '.ods')) + ods.filename = filename; + else + error ('No .sxc or .ods filename extension specified'); + endif + endif + endif + endif + if (strcmp (ods.xtype, 'OTK')) # Java & ODF toolkit - if (ods.changed), ods.app.save (ods.filename); endif - ods.app.close (); + try + if (ods.changed && ods.changed < 3) + ods.app.save (ods.filename); + ods.changed = 0; + endif + ods.app.close (); + catch + end_try_catch elseif (strcmp (ods.xtype, 'JOD')) # Java & jOpenDocument - if (ods.changed) - ofile = java_new ('java.io.File', ods.filename); - ods.workbook.saveAs (ofile); - endif + try + if (ods.changed && ods.changed < 3) + ofile = java_new ('java.io.File', ods.filename); + ods.workbook.saveAs (ofile); + ods.changed = 0; + endif + catch + end_try_catch # elseif ---- < Other interfaces here > else - error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); + error (sprintf ("ods2close: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); endif - # Reset file pointer - ods = []; + if (ods.changed && ods.changed < 3) + error ( sprintf ("Could not save file %s - read-only or in use elsewhere?\nFile pointer preserved", ods.filename)); + else + # Reset file pointer + ods = []; + endif endfunction Modified: trunk/octave-forge/main/io/inst/odsopen.m =================================================================== --- trunk/octave-forge/main/io/inst/odsopen.m 2010-11-14 16:53:26 UTC (rev 7915) +++ trunk/octave-forge/main/io/inst/odsopen.m 2010-11-14 16:55:15 UTC (rev 7916) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -29,13 +29,13 @@ ## referred to as OTK and JOD, resp., and are preferred in that order by default ## (depending on their presence). ## -## @var{filename} must be a valid .ods OpenOffice.org file name. If @var{filename} -## does not contain any directory path, the file is saved in the current -## directory. +## @var{filename} must be a valid .ods OpenOffice.org file name including +## .ods suffix. If @var{filename} does not contain any directory path, +## the file is saved in the current directory. ## -## @var{readwrite} must be set to 1 if writing to spreadsheet is desired -## immediately after calling odsopen(). It merely serves proper handling -## of file errors (e.g., "file not found" or "new file created"). +## @var{readwrite} must be set to true ornumerical 1 if writing to spreadsheet +## is desired immediately after calling odsopen(). It merely serves proper +## handling of file errors (e.g., "file not found" or "new file created"). ## ## Optional input argument @var{reqintf} can be used to override the ODS ## interface automatically selected by odsopen. Currently implemented interfaces @@ -73,6 +73,9 @@ ## " Moved JOD version check to this func from subfunc getodsinterfaces() ## " Full support for odfdom 0.8.6 (in subfunc) ## 2010-08-27 Improved help text +## 2010-10-27 Improved tracking of file changes tru ods.changed +## 2010-11-12 Small changes to help text +## " Added try-catch to file open sections to create fallback to other intf ## ## Latest change on subfunction below: 2010-09-27 @@ -86,6 +89,10 @@ if (nargout < 1) usage ("ODS = odsopen (ODSfile, [Rw]). But no return argument specified!"); endif + ## FIXME: if ever another interface is implemented the below stanzas + ## should be remodeled after xlsopen() to allow for multiple + ## user-desired interface requests (for just 2 interfaces there's + ## no need yet) if (~isempty (reqinterface)) # Try to invoke requested interface for this call. Check if it # is supported anyway by emptying the corresponding var. @@ -112,15 +119,22 @@ if (rw) rw = 1; endif # Be sure it's either 0 or 1 initially - # Check if ODS file exists - fid = fopen (filename, 'rb'); + # Check if ODS file exists. Set open mode based on rw argument + if (rw), fmode = 'r+b'; else fmode = 'rb'; endif + fid = fopen (filename, fmode); if (fid < 0) - if (~rw) + if (~rw) # Read mode requested but file doesn't exist err_str = sprintf ("File %s not found\n", filename); error (err_str) - else - printf ("Creating file %s\n", filename); - rw = 2; + else # For writing we need more info: + fid = fopen (filename, 'rb'); # Check if it can be opened for reading + if (fid < 0) # Not found => create it + printf ("Creating file %s\n", filename); + rw = 3; + else # Found but not writable = error + fclose (fid); # Do not forget to close the handle neatly + error (sprintf ("Write mode requested but file %s is not writable\n", filename)) + endif endif else # close file anyway to avoid Java errors @@ -135,67 +149,95 @@ # Supported interfaces determined; now check ODS file type. chk1 = strcmp (tolower (filename(end-3:end)), '.ods'); - if (~chk1) - error ("Currently ods2oct can only read reliably from .ods files") - endif + # Only jOpenDocument (JOD) can read from .sxc files, but only if odfvsn = 2 + chk2 = strcmp (tolower (filename(end-3:end)), '.sxc'); +# if (~chk1) +# error ("Currently ods2oct can only read reliably from .ods files") +# endif ods = struct ("xtype", [], "app", [], "filename", [], "workbook", [], "changed", 0, "limits", [], "odfvsn", []); # Preferred interface = OTK (ODS toolkit & xerces), so it comes first. + # Keep track of which interface is selected. Can be used for fallback to other intf + odssupport = 0; - if (odsinterfaces.OTK) + if (odsinterfaces.OTK && ~odssupport) # Parts after user gfterry in # http://www.oooforum.org/forum/viewtopic.phtml?t=69060 odftk = 'org.odftoolkit.odfdom.doc'; - if (rw == 2) - # New spreadsheet - wb = java_invoke ([odftk '.OdfSpreadsheetDocument'], 'newSpreadsheetDocument'); - ods.changed = 2; - else - # Existing spreadsheet - wb = java_invoke ([odftk '.OdfDocument'], 'loadDocument', filename); - endif - ods.workbook = wb.getContentDom (); # Reads the entire spreadsheet - ods.xtype = 'OTK'; - ods.app = wb; - ods.filename = filename; - ods.odfvsn = odsinterfaces.odfvsn; + try + if (rw > 2) + # New spreadsheet + wb = java_invoke ([odftk '.OdfSpreadsheetDocument'], 'newSpreadsheetDocument'); + else + # Existing spreadsheet + wb = java_invoke ([odftk '.OdfDocument'], 'loadDocument', filename); + endif + ods.workbook = wb.getContentDom (); # Reads the entire spreadsheet + ods.xtype = 'OTK'; + ods.app = wb; + ods.filename = filename; + ods.odfvsn = odsinterfaces.odfvsn; + odssupport += 1; + catch + if (xlsinterfaces.JOD && ~rw && chk2) + printf ('Couldn''t open file %s using OTK; trying .sxc format with JOD...\n', filename); + else + error ('Couldn''t open file %s using OTK', filename); + endif + end_try_catch + endif - elseif (odsinterfaces.JOD) + if (odsinterfaces.JOD && ~odssupport) file = java_new ('java.io.File', filename); jopendoc = 'org.jopendocument.dom.spreadsheet.SpreadSheet'; - if (rw ==2) - # Create an empty 2 x 2 default TableModel template - tmodel= java_new ('javax.swing.table.DefaultTableModel', 2, 2); - wb = java_invoke (jopendoc, 'createEmpty', tmodel); - ods.changed = 2; - else - wb = java_invoke (jopendoc, 'createFromFile', file); - endif - ods.workbook = wb; - ods.filename = filename; - ods.xtype = 'JOD'; - ods.app = 'file'; - # Check jOpenDocument version - sh = ods.workbook.getSheet (0); - cl = sh.getCellAt (0, 0); try - # 1.2b3 has public getValueType () - cl.getValueType (); - ods.odfvsn = 3; + if (rw > 2) + # Create an empty 2 x 2 default TableModel template + tmodel= java_new ('javax.swing.table.DefaultTableModel', 2, 2); + wb = java_invoke (jopendoc, 'createEmpty', tmodel); + else + wb = java_invoke (jopendoc, 'createFromFile', file); + endif + ods.workbook = wb; + ods.filename = filename; + ods.xtype = 'JOD'; + ods.app = 'file'; + # Check jOpenDocument version. This can only work here when a + # workbook has been opened + sh = ods.workbook.getSheet (0); + cl = sh.getCellAt (0, 0); + try + # 1.2b3 has public getValueType () + cl.getValueType (); + ods.odfvsn = 3; + catch + # 1.2b2 has not + ods.odfvsn = 2; + printf ("NOTE: jOpenDocument v. 1.2b2 has limited functionality. Try upgrading to 1.2b3+\n"); + end_try_catch + odssupport += 2; catch - # 1.2b2 has not - ods.odfvsn = 2; - printf ("NOTE: jOpenDocument v. 1.2b2 has limited functionality. Try upgrading to 1.2b3+\n"); + error ('Couldn''t open file %s using JOD', filename); end_try_catch + endif -# elseif +# if # <other interfaces here> - else + if (~odssupport) warning ("No support for OpenOffice.org .ods I/O"); ods = []; + else + # From here on rw is tracked via ods.changed in the various lower + # level r/w routines and it is only used to determine if an informative + # message is to be given when saving a newly created ods file. + ods.changed = rw; + # Until something was written to existing files we keep status "unchanged". + # ods.changed = 0 (existing/only read from), 1 (existing/data added), 2 (new, + # data added) or 3 (pristine, no data added). + if (ods.changed == 1) ods.changed = 0; endif endif if (~isempty (reqinterface)) @@ -206,7 +248,7 @@ endfunction -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -257,6 +299,7 @@ ## 2010-09-11 Somewhat clarified messages about missing java classes ## " Rearranged code a bit; fixed typos in OTK detection code (odfdvsn -> odfvsn) ## 2010-09-27 More code cleanup +## 2010-11-12 Warning added about waning support for odfdom v. 0.7.5 function [odsinterfaces] = getodsinterfaces (odsinterfaces) @@ -273,6 +316,8 @@ # If we get here, at least Java works. Now check for proper entries # in class path. Under *nix the classpath must first be split up if (isunix) tmp1 = strsplit (char(tmp1), ":"); endif + ## FIXME implement more rigid Java version check a la xlsopen. + ## ods / Java stuff is less critical than xls / Java, however catch # No Java support odsinterfaces.OTK = 0; @@ -309,7 +354,10 @@ end_try_catch if ~(strcmp (odfvsn, '0.7.5') || strcmp (odfvsn, '0.8.6')) warning ("\nodfdom version %s is not supported - use v. 0.7.5 or 0.8.6.\n", odfvsn); - else + else + if (strcmp (odfvsn, '0.7.5')) + warning ("odfdom v. 0.7.5 support won't be maintained - please upgrade to 0.8.6 or higher."); + endif odsinterfaces.OTK = 1; printf (" Java/ODFtoolkit (OTK) OK. "); chk1 = 1; Modified: trunk/octave-forge/main/io/inst/odsread.m =================================================================== --- trunk/octave-forge/main/io/inst/odsread.m 2010-11-14 16:53:26 UTC (rev 7915) +++ trunk/octave-forge/main/io/inst/odsread.m 2010-11-14 16:55:15 UTC (rev 7916) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -33,7 +33,8 @@ ##a struct containing the data origins of the various returned arrays. ## ## If @var{filename} does not contain any directory, the file is -## assumed to be in the current directory. +## assumed to be in the current directory. @var{filename} should include +## the filename extension (.ods). ## ## @var{wsh} is either numerical or text, in the latter case it is ## case-sensitive and it should conform to OpenOffice.org Calc sheet @@ -110,9 +111,18 @@ ## 2010-01-05 (....) ## 2010-03-04 Slight adaptations in texinfo ## 2010-05-31 Updated help text (delays i.c.o. empty range due to getusedrange call) +## 2010-11-10 Updated help text (filename extension req'd) +## 2010-11-13 Added some input validity checks function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[]) + if (nargin < 1 || isempty (findstr ('.ods', tolower (filename)))) + usage ("odsread: at least a filename incl. suffix is needed"); + endif + if (nargout < 1) + usage ("odsread: no output argument(s) specified"); + endif + ods = odsopen (filename, 0, reqintf); [rawarr, ods, rstatus] = ods2oct (ods, wsh, datrange); Modified: trunk/octave-forge/main/io/inst/odswrite.m =================================================================== --- trunk/octave-forge/main/io/inst/odswrite.m 2010-11-14 16:53:26 UTC (rev 7915) +++ trunk/octave-forge/main/io/inst/odswrite.m 2010-11-14 16:55:15 UTC (rev 7916) @@ -1,4 +1,4 @@ -## Copyright (C) 2009 Philip Nienhuis <pr.nienhuis at users.sf.net> +## Copyright (C) 2009,2010 Philip Nienhuis <pr.nienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -24,9 +24,9 @@ ## ## @var{rstatus} returns 1 if write succeeded, 0 otherwise. ## -## @var{filename} must be a valid .ods OpenOffice.org file name. If -## @var{filename} does not contain any directory path, the file is saved -## in the current directory. +## @var{filename} must be a valid .ods OpenOffice.org file name (including +## file name extension). If @var{filename} does not contain any directory +## path, the file is saved in the current directory. ## ## @var{arr} can be any array type save complex. Mixed numeric/text arrays ## can only be cell arrays. @@ -86,13 +86,16 @@ ## 2010-01-14 Finalized write support tru ODS toolkit ## 2010-01-15 Added texinfo help ## 2010-08-25 Removed text about 31 char limit for sheet names (invalid) +## 2010-11-13 Added note about required file extension in help text +## 2010-11-13 Added some input arg checks function [ rstatus ] = odswrite (filename, data, wsh=1, range=[], reqintf=[]) - if (isnumeric (data)) - data = num2cell (data); - elseif (ischar (data)) - data = {data}; + # Input validity checks + if (nargin < 2) + usage ("Insufficient arguments - see 'help odswrite'"); + elseif (~ischar (filename) || isempty (findstr ('.ods', tolower (filename)))) + error ("First argument must be a filename (incl. .ods suffix)"); endif ods = odsopen (filename, 1, reqintf); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <prn...@us...> - 2010-11-14 18:08:14
|
Revision: 7917 http://octave.svn.sourceforge.net/octave/?rev=7917&view=rev Author: prnienhuis Date: 2010-11-14 16:58:07 +0000 (Sun, 14 Nov 2010) Log Message: ----------- Initial versions. I think some improvements to the code are useful but the author hasn't replied yet :-) Added Paths: ----------- trunk/octave-forge/main/io/inst/savevtk.m trunk/octave-forge/main/io/inst/savevtkvector.m Added: trunk/octave-forge/main/io/inst/savevtk.m =================================================================== --- trunk/octave-forge/main/io/inst/savevtk.m (rev 0) +++ trunk/octave-forge/main/io/inst/savevtk.m 2010-11-14 16:58:07 UTC (rev 7917) @@ -0,0 +1,57 @@ +## Copyright (C) 2010 Kurnia Wano, Levente Torok +##. +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +##. +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +##. +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## +## -*- texinfo -*- +## +## @deftypefn {Function File} savevtk ( @var{X}, @var{Y}, @var{Z}, @var{filename} ) +## savevtk Save a 3-D scalar array in VTK format. +## savevtk(array, filename) saves a 3-D array of any size to +## filename in VTK format. +##. +## -*- texinfo -*- +## +## +## Author: Kurnia Wano, Levente Torok <Tor...@gm...> +## Created: 2010-08-02 +## Updates: 2010-11-03 +## + +function savevtk(array, filename) + [nx, ny, nz] = size(array); + fid = fopen(filename, 'wt'); + fprintf(fid, '# vtk DataFile Version 2.0\n'); + fprintf(fid, 'Comment goes here\n'); + fprintf(fid, 'ASCII\n'); + fprintf(fid, '\n'); + fprintf(fid, 'DATASET STRUCTURED_POINTS\n'); + fprintf(fid, 'DIMENSIONS %d %d %d\n', nx, ny, nz); + fprintf(fid, '\n'); + fprintf(fid, 'ORIGIN 0.000 0.000 0.000\n'); + fprintf(fid, 'SPACING 1.000 1.000 1.000\n'); + fprintf(fid, '\n'); + fprintf(fid, 'POINT_DATA %d\n', nx*ny*nz); + fprintf(fid, 'SCALARS scalars double\n'); + fprintf(fid, 'LOOKUP_TABLE default\n'); + fprintf(fid, '\n'); + for a=1:nz + for b=1:ny + for c=1:nx + fprintf(fid, '%d ', array(c,b,a)); + end + fprintf(fid, '\n'); + end + end + fclose(fid); +return Added: trunk/octave-forge/main/io/inst/savevtkvector.m =================================================================== --- trunk/octave-forge/main/io/inst/savevtkvector.m (rev 0) +++ trunk/octave-forge/main/io/inst/savevtkvector.m 2010-11-14 16:58:07 UTC (rev 7917) @@ -0,0 +1,64 @@ +## Copyright (C) 2010 Kurnia Wano, Levente Torok +##. +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +##. +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +##. +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## + +## -*- texinfo -*- +## +## @deftypefn {Function File} savevtkvector ( @var{X}, @var{Y}, @var{Z}, @var{filename} ) +## savevtkvector Save a 3-D vector array in VTK format +## savevtkvector(X,Y,Z,filename) saves a 3-D vector of any size to +## filename in VTK format. X, Y and Z should be arrays of the same +## size, each storing speeds in the a single Cartesian directions. +## +## @end deftypefn +## +## +## Author: Kurnia Wano, Levente Torok <Tor...@gm...> +## Created: 2010-08-02 +## Updates: 2010-11-03 +## + +function savevtkvector(X, Y, Z, filename) + + if ((size(X) ~= size(Y)) | (size(X) ~= size(Z))) + error('Error: velocity arrays of unequal size\n'); + return; + end + [ny,nx,nz]=size(datax); + xx=1:size(datax,2); + yy=1:size(datax,1); + zz=1:size(datax,3); + datax=datax(:)’; + datay=datay(:)’; + dataz=dataz(:)’; + %% Header + fid=fopen(fullfile(outputd,filename),’w'); + fprintf(fid,’%s\n’,'# vtk DataFile Version 3.0′); + fprintf(fid,’%s\n’,’3D LFF extrapolation’); + fprintf(fid,’%s\n’,'ASCII’); + fprintf(fid,’%s\n’,'DATASET RECTILINEAR_GRID’); + fprintf(fid,’%s %1.0i %1.0i %1.0i\n’,'DIMENSIONS’,nx,ny,nz); + fprintf(fid,’%s %1.0i %s\n’,'X_COORDINATES’,nx,’float’); + fprintf(fid,’%1.0i ‘,xx); + fprintf(fid,’\n%s %1.0i %s\n’,'Y_COORDINATES’,ny,’float’); + fprintf(fid,’%1.0i ‘,yy); + fprintf(fid,’\n%s %1.0i %s\n’,'Z_COORDINATES’,nz,’float’); + fprintf(fid,’%1.0i ‘,zz); + %% Data + fprintf(fid,’\n%s %1.0i’,'POINT_DATA’,nx*ny*nz); + fprintf(fid,’\n%s\n’,'VECTORS BFIELD float’); + fprintf(fid,’%6.2f %6.2f %6.2f\n’,[datax;datay;dataz]); + fclose(fid); +return This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |