userfield.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # Copyright (C) 2006-2009 Søren Roug, European Environment Agency
  4. #
  5. # This is free software. You may redistribute it under the terms
  6. # of the Apache license and the GNU General Public License Version
  7. # 2 or at your option any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public
  15. # License along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. #
  18. # Contributor(s): Michael Howitz, gocept gmbh & co. kg
  19. #
  20. # $Id: userfield.py 447 2008-07-10 20:01:30Z roug $
  21. """Class to show and manipulate user fields in odf documents."""
  22. import sys
  23. import zipfile
  24. from odf.text import UserFieldDecl
  25. from odf.namespaces import OFFICENS
  26. from odf.opendocument import load
  27. import io, sys
  28. if sys.version_info[0]==3:
  29. unicode=str
  30. OUTENCODING = "utf-8"
  31. # OpenDocument v.1.0 section 6.7.1
  32. VALUE_TYPES = {
  33. u'float': (OFFICENS, u'value'),
  34. u'percentage': (OFFICENS, u'value'),
  35. u'currency': (OFFICENS, u'value'),
  36. u'date': (OFFICENS, u'date-value'),
  37. u'time': (OFFICENS, u'time-value'),
  38. u'boolean': (OFFICENS, u'boolean-value'),
  39. u'string': (OFFICENS, u'string-value'),
  40. }
  41. class UserFields(object):
  42. """List, view and manipulate user fields."""
  43. # these attributes can be a filename or a file like object
  44. src_file = None
  45. dest_file = None
  46. def __init__(self, src=None, dest=None):
  47. """Constructor
  48. @param src open file in binary mode: source document,
  49. or filename as a unicode string, or None for stdin.
  50. @param dest opendile in binary mode: destination document,
  51. or filename as a unicode string, or None for stdout.
  52. """
  53. assert(src==None or 'rb' in repr(src) or 'BufferedReader' in repr(src) or 'BytesIO' in repr(src) or type(src)==type(u""))
  54. assert(dest==None or 'wb' in repr(dest) or 'BufferedWriter' in repr(dest) or 'BytesIO' in repr(dest) or type(dest)==type(u""))
  55. self.src_file = src
  56. self.dest_file = dest
  57. self.document = None
  58. def loaddoc(self):
  59. if (sys.version_info[0]==3 and (isinstance(self.src_file, str) or (isinstance(self.src_file, io.IOBase)))) or (sys.version_info[0]==2 and isinstance(self.src_file, basestring)):
  60. # src_file is a filename, check if it is a zip-file
  61. if not zipfile.is_zipfile(self.src_file):
  62. raise TypeError(u"%s is no odt file." % self.src_file)
  63. elif self.src_file is None:
  64. # use stdin if no file given
  65. self.src_file = sys.stdin
  66. self.document = load(self.src_file)
  67. def savedoc(self):
  68. # write output
  69. if self.dest_file is None:
  70. # use stdout if no filename given
  71. self.document.save(u'-')
  72. else:
  73. self.document.save(self.dest_file)
  74. def list_fields(self):
  75. """List (extract) all known user-fields.
  76. @return list of user-field names as unicode strings.
  77. """
  78. return [x[0] for x in self.list_fields_and_values()]
  79. def list_fields_and_values(self, field_names=None):
  80. """List (extract) user-fields with type and value.
  81. @param field_names list of field names as unicode strings
  82. to show, or None for all.
  83. @return list of tuples (<field name>, <field type>, <value>)
  84. as type (unicode string, stringified type, unicode string).
  85. """
  86. self.loaddoc()
  87. found_fields = []
  88. all_fields = self.document.getElementsByType(UserFieldDecl)
  89. for f in all_fields:
  90. value_type = f.getAttribute(u'valuetype')
  91. if value_type == u'string':
  92. value = f.getAttribute(u'stringvalue')
  93. else:
  94. value = f.getAttribute(u'value')
  95. field_name = f.getAttribute(u'name')
  96. if field_names is None or field_name in field_names:
  97. found_fields.append((field_name,
  98. value_type,
  99. value))
  100. return found_fields
  101. def list_values(self, field_names):
  102. """Extract the contents of given field names from the file.
  103. @param field_names list of field names as unicode strings
  104. @return list of field values as unicode strings.
  105. """
  106. return [x[2] for x in self.list_fields_and_values(field_names)]
  107. def get(self, field_name):
  108. """Extract the contents of this field from the file.
  109. @param field_name unicode string: name of a field
  110. @return field value as a unicode string or None if field does not exist.
  111. """
  112. assert(type(field_name)==type(u""))
  113. values = self.list_values([field_name])
  114. if not values:
  115. return None
  116. return values[0]
  117. def get_type_and_value(self, field_name):
  118. """Extract the type and contents of this field from the file.
  119. @param field_name unicode string: name of a field
  120. @return tuple (<type>, <field-value>) as a pair of unicode strings
  121. or None if field does not exist.
  122. """
  123. assert(type(field_name)==type(u""))
  124. fields = self.list_fields_and_values([field_name])
  125. if not fields:
  126. return None
  127. field_name, value_type, value = fields[0]
  128. return value_type, value
  129. def update(self, data):
  130. """Set the value of user fields. The field types will be the same.
  131. data ... dict, with field name as key, field value as value
  132. Returns None
  133. """
  134. self.loaddoc()
  135. all_fields = self.document.getElementsByType(UserFieldDecl)
  136. for f in all_fields:
  137. field_name = f.getAttribute(u'name')
  138. if field_name in data:
  139. value_type = f.getAttribute(u'valuetype')
  140. value = data.get(field_name)
  141. if value_type == u'string':
  142. f.setAttribute(u'stringvalue', value)
  143. else:
  144. f.setAttribute(u'value', value)
  145. self.savedoc()