diff --git a/modules/base/pymod/table.py b/modules/base/pymod/table.py
index fc8ed05c8c8a157873b59a65a1fa4efbf6aad022..e5f46b260f01cc96d2d07457ffb6af04817d5124 100644
--- a/modules/base/pymod/table.py
+++ b/modules/base/pymod/table.py
@@ -1641,6 +1641,8 @@ class Table(object):
     ost             ost-specific format (human readable)
     csv             comma separated values (human readable)
     pickle          pickled byte stream (binary)
+    html            HTML table
+    context         ConTeXt table
     =============   =======================================
 
     :param stream_or_filename: filename or stream for writing output
@@ -1658,6 +1660,10 @@ class Table(object):
       return self._SaveCSV(stream_or_filename, sep=sep)
     if format=='pickle':
       return self._SavePickle(stream_or_filename)
+    if format=='html':
+      return self._SaveHTML(stream_or_filename)
+    if format=='context':
+      return self._SaveContext(stream_or_filename)
     raise ValueError('unknown format "%s"' % format)
 
   def _SavePickle(self, stream):
@@ -1665,6 +1671,79 @@ class Table(object):
       stream=open(stream, 'wb')
     cPickle.dump(self, stream, cPickle.HIGHEST_PROTOCOL)
 
+  def _SaveHTML(self, stream_or_filename):
+    def _escape(s):
+      return s.replace('&', '&amp;').replace('>', '&gt;').replace('<', '&lt;')
+
+    file_opened = False
+    if not hasattr(stream_or_filename, 'write'):
+      stream = open(stream_or_filename, 'w')
+      file_opened = True
+    else:
+      stream = stream_or_filename
+    stream.write('<table>') 
+    stream.write('<tr>')
+    for col_name in self.col_names:
+      stream.write('<th>%s</th>' % _escape(col_name)) 
+    stream.write('</tr>')
+    for row in self.rows:
+      stream.write('<tr>')
+      for i, col in enumerate(row):
+        val = ''
+        if col != None:
+           if self.col_types[i] == 'float':
+             val = '%.3f' % col
+           elif self.col_types[i] == 'int':
+             val = '%d' % col
+           elif self.col_types[i] == 'bool':
+             val = col and 'true' or 'false'
+           else:
+             val  = str(col)
+        stream.write('<td>%s</td>' % _escape(val))
+      stream.write('</tr>')
+    stream.write('</table>')
+    if file_opened:
+      stream.close()
+  def _SaveContext(self, stream_or_filename):
+    file_opened = False
+    if not hasattr(stream_or_filename, 'write'):
+      stream = open(stream_or_filename, 'w')
+      file_opened = True
+    else:
+      stream = stream_or_filename
+    stream.write('\\starttable[') 
+    for col_type in self.col_types:
+      if col_type =='string':
+        stream.write('l|')
+      elif col_type=='int':
+        stream.write('r|')
+      elif col_type =='float':
+        stream.write('i3r|')
+      else:
+        stream.write('l|')
+    stream.write(']\n\\HL\n')
+    for col_name in self.col_names:
+      stream.write('\\NC \\bf %s' % col_name) 
+    stream.write(' \\AR\\HL\n')
+    for row in self.rows:
+      for i, col in enumerate(row):
+        val = '---'
+        if col != None:
+           if self.col_types[i] == 'float':
+             val = '%.3f' % col
+           elif self.col_types[i] == 'int':
+             val = '%d' % col
+           elif self.col_types[i] == 'bool':
+             val = col and 'true' or 'false'
+           else:
+             val  = str(col)
+        stream.write('\\NC %s' % val)
+      stream.write(' \\AR\n')
+    stream.write('\\HL\n')
+    stream.write('\\stoptable')
+    if file_opened:
+      stream.close()
+
   def _SaveCSV(self, stream, sep):
     if not hasattr(stream, 'write'):
       stream=open(stream, 'wb')
@@ -2400,4 +2479,3 @@ def Merge(table1, table2, by, only_matching=False):
       new_tab.AddRow(row)
   return new_tab
 
-  
diff --git a/modules/base/tests/test_table.py b/modules/base/tests/test_table.py
index 5e2e82824cad6963f3da7a5ce81e3ec70309a2ba..7a10f4ee131ac625e24d33a4cca634ca53d57803 100644
--- a/modules/base/tests/test_table.py
+++ b/modules/base/tests/test_table.py
@@ -853,6 +853,19 @@ class TestTable(unittest.TestCase):
     # read from disc
     tab_loaded_fname = Table.Load('saveloadtable_withspaces_filename_out.tab')
     self.CompareDataFromDict(tab_loaded_fname, {'first': ['x','foo',None,'hello spaces'], 'second': [3,None,9,10], 'third': [None,2.2,3.3,10.1]})
+  def testSaveTableHTML(self):
+    import StringIO
+    tab = self.CreateTestTable()
+    stream = StringIO.StringIO()
+    tab.Save(stream, format='html')
+    self.assertEqual(stream.getvalue(), '<table><tr><th>first</th><th>second</th><th>third</th></tr><tr><td>x</td><td>3</td><td></td></tr><tr><td>foo</td><td></td><td>2.200</td></tr><tr><td></td><td>9</td><td>3.300</td></tr></table>')
+  def testSaveTableContext(self):
+    import StringIO
+    tab = self.CreateTestTable()
+    stream = StringIO.StringIO()
+    tab.Save(stream, format='context')
+    self.assertEqual(stream.getvalue(), 
+                     '\\starttable[l|r|i3r|]\n\\HL\n\\NC \\bf first\\NC \\bf second\\NC \\bf third \\AR\\HL\n\\NC x\\NC 3\\NC --- \\AR\n\\NC foo\NC ---\NC 2.200 \\AR\n\\NC ---\\NC 9\\NC 3.300 \\AR\n\\HL\n\\stoptable')
 
   def testSaveLoadTableCSV(self):
     tab = self.CreateTestTable()