debian-python-odf/contrib/odscell/odscell

185 lines
6.9 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2010 Kartikaya Gupta, https://staktrace.com/
#
# This is free software. You may redistribute it under the terms
# of the Apache license and the GNU General Public License Version
# 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Contributor(s):
#
from odf import opendocument
from odf.element import Text
from odf.table import *
from odf.text import P
from optparse import OptionParser
import sys,csv,re
def getSheet( file, sheetIndex ):
doc = opendocument.load( file )
try:
spreadsheet = doc.spreadsheet
except NameError:
sys.stderr.write("Error: file is not a spreadsheet\n")
return (None, None)
sheets = spreadsheet.getElementsByType( Table )
if sheetIndex > len( sheets ):
sys.stderr.write( "Error: spreadsheet has only %d sheets; requested invalid sheet %d\n" % (len( sheets ), sheetIndex + 1) )
return (None, None)
sheet = sheets[sheetIndex]
return (doc, sheet)
def displayCells( file, sheetIndex, rowIndex, colIndex, rowCount, colCount ):
(doc, sheet) = getSheet( file, sheetIndex )
if (doc == None or sheet == None):
return 1
rows = sheet.getElementsByType( TableRow )
if rowIndex + rowCount > len( rows ):
sys.stderr.write( "Error: sheet has only %d rows; requested invalid row %d\n" % (len( rows ), rowIndex + rowCount) )
return 1
csv_writer = csv.writer( sys.stdout )
for i in range( rowIndex, rowIndex + rowCount ):
row = rows[ i ]
cells = row.getElementsByType( TableCell )
if colIndex + colCount > len( cells ):
sys.stderr.write( "Error: row has only %d cells; requested invalid column %d\n" % (len( cells ), colIndex + colCount) )
return 1
for j in range( colIndex, colIndex + colCount ):
cells[ j ] = unicode( cells[ j ] )
csv_writer.writerow( cells[ colIndex : colIndex + colCount ] )
return 0
def updateCells( file, sheetIndex, rowIndex, colIndex, rowCount, colCount ):
(doc, sheet) = getSheet( file, sheetIndex )
if (doc == None or sheet == None):
return 1
data = sys.stdin.readlines()
if rowCount < 0:
rowCount = len( data )
elif len( data ) < rowCount:
sys.stderr.write( "Error: not enough rows in input\n" )
return 1
# add table rows as necessary
rows = sheet.getElementsByType( TableRow )
if rowIndex + rowCount > len( rows ):
for i in range( rowIndex + rowCount - len( rows ) ):
sheet.addElement( TableRow() )
rows = sheet.getElementsByType( TableRow )
csv_reader = csv.reader( data )
for i in range( rowIndex, rowIndex + rowCount ):
row = rows[ i ]
dataRow = csv_reader.next()
rowColCount = colCount
if rowColCount < 0:
rowColCount = len( dataRow )
elif len( dataRow ) < rowColCount:
sys.stderr.write( "Error: not enough columns in input on row %d\n" % (rowIndex - i + 1) )
return 1
cells = row.getElementsByType( TableCell )
if colIndex > len( cells ):
for j in range( len( cells ), colIndex ):
row.addElement( TableCell() )
cells = row.getElementsByType( TableCell )
for j in range( colIndex, colIndex + rowColCount ):
if j < len( cells ):
row.insertBefore( TableCell(), cells[ j ].nextSibling );
row.removeChild( cells[ j ] )
else:
row.addElement( TableCell() )
cells = row.getElementsByType( TableCell )
value = dataRow[ j - colIndex ]
if re.match( r'^[-]?\d+(\.\d+)?$', value.strip() ):
cells[ j ].setAttribute( 'valuetype', 'float' )
cells[ j ].setAttribute( 'value', value )
else:
cells[ j ].setAttribute( 'valuetype', 'string' )
cells[ j ].addElement( P( text = dataRow[ j - colIndex ] ) )
doc.save( file )
return 0
def parseCell( cell ):
cellmatch = re.match( r'^([A-Z]+)([0-9]+)$', cell )
if cellmatch == None:
sys.stderr.write( "Error: the cell specified was not in the required format of <column><row> (e.g. A1)" )
exit( 1 )
cellcol = cellmatch.group( 1 )
colIndex = 0
for i in range( len( cellcol ) ):
colIndex = (colIndex * 26) + (ord( cellcol[i] ) - ord( 'A' ) + 1)
colIndex = colIndex - 1
rowIndex = int( cellmatch.group( 2 ) ) - 1
return (colIndex, rowIndex)
def getCount( value, write, label ):
if value == None:
if write:
return -1
else:
return 1
value = int( value )
if value <= 0:
sys.stderr.write( "Error: illegal value specified for %s\n" % label )
exit( 1 )
return value
if __name__ == "__main__":
usage = "%prog file.ods cell"
parser = OptionParser( usage=usage, version="%prog 0.1" )
parser.add_option( '-r', '--rows', action='store', dest='rows', help=
'''Specify the height of the block of cells, in rows. Must be greater than zero. Defaults to 1 when
the -w option is not present. Defaults to the number of input rows when the -w option is present.''', default=None )
parser.add_option( '-c', '--cols', action='store', dest='cols', help=
'''Specify the width of the block of cells, in columns. Must be greater than zero. Defaults to 1 when
the -w option is not present. Defaults to the number of input columns when the -w option is present.''', default=None )
parser.add_option( '-s', '--sheet', action='store', dest='sheet', help='The sheet in the ODS file to read/modify. Must be greater than zero; defaults to 1.', default=1 )
parser.add_option( '-w', '--write', action='store_true', dest='write', help=
'''If specified, the spreadsheet will be modified with data from standard input. If not specified,
the cells from the spreadsheet will be written to standard output.''' )
(options, args) = parser.parse_args()
if len( args ) != 2:
parser.print_help()
exit( 1 )
file = args[0]
(colIndex, rowIndex) = parseCell( args[1] )
rowCount = getCount( options.rows, options.write, 'rows' )
colCount = getCount( options.cols, options.write, 'cols' )
sheet = int( options.sheet ) - 1
if sheet < 0:
sys.stderr.write( "Error: illegal value specified for sheet\n" )
exit( 1 )
if options.write:
exit( updateCells( file, sheet, rowIndex, colIndex, rowCount, colCount ) )
else:
exit( displayCells( file, sheet, rowIndex, colIndex, rowCount, colCount ) )