1 #!/usr/bin/env Python 2 """ 3 Tables Extension for Python-Markdown 4 ==================================== 5 6 Added parsing of tables to Python-Markdown. 7 8 A simple example: 9 10 First Header | Second Header 11 ------------- | ------------- 12 Content Cell | Content Cell 13 Content Cell | Content Cell 14 15 Copyright 2009 - [Waylan Limberg](http://achinghead.com) 16 """ 17 import markdown 18 from markdown import etree 19 20 21 class TableProcessor(markdown.blockprocessors.BlockProcessor): 22 """ Process Tables. """ 23 24 def test(self, parent, block): 25 rows = block.split('\n') 26 return (len(rows) > 2 and '|' in rows[0] and 27 '|' in rows[1] and '-' in rows[1] and 28 rows[1][0] in ['|', ':', '-']) 29 30 def run(self, parent, blocks): 31 """ Parse a table block and build table. """ 32 block = blocks.pop(0).split('\n') 33 header = block[:2] 34 rows = block[2:] 35 # Get format type (bordered by pipes or not) 36 border = False 37 if header[0].startswith('|'): 38 border = True 39 # Get alignment of columns 40 align = [] 41 for c in self._split_row(header[1], border): 42 if c.startswith(':') and c.endswith(':'): 43 align.append('center') 44 elif c.startswith(':'): 45 align.append('left') 46 elif c.endswith(':'): 47 align.append('right') 48 else: 49 align.append(None) 50 # Build table 51 table = etree.SubElement(parent, 'table') 52 thead = etree.SubElement(table, 'thead') 53 self._build_row(header[0], thead, align, border) 54 tbody = etree.SubElement(table, 'tbody') 55 for row in rows: 56 self._build_row(row, tbody, align, border) 57 58 def _build_row(self, row, parent, align, border): 59 """ Given a row of text, build table cells. """ 60 tr = etree.SubElement(parent, 'tr') 61 tag = 'td' 62 if parent.tag == 'thead': 63 tag = 'th' 64 cells = self._split_row(row, border) 65 # We use align here rather than cells to ensure every row 66 # contains the same number of columns. 67 for i, a in enumerate(align): 68 c = etree.SubElement(tr, tag) 69 try: 70 c.text = cells[i].strip() 71 except IndexError: 72 c.text = "" 73 if a: 74 c.set('align', a) 75 76 def _split_row(self, row, border): 77 """ split a row of text into list of cells. """ 78 if border: 79 if row.startswith('|'): 80 row = row[1:] 81 if row.endswith('|'): 82 row = row[:-1] 83 return row.split('|') 84 85 86 class TableExtension(markdown.Extension): 87 """ Add tables to Markdown. """ 88 89 def extendMarkdown(self, md, md_globals): 90 """ Add an instance of TableProcessor to BlockParser. """ 91 md.parser.blockprocessors.add('table', 92 TableProcessor(md.parser), 93 '<hashheader') 94 95 96 def makeExtension(configs={}): 97 return TableExtension(configs=configs) 98