185 lines
6.9 KiB
Python
Executable File
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 ) )
|