2012-11-15 33 views
3

有什麼辦法從對象(Python/Ruby/Java/C#)生成表?生成Markdown表?

我想以編程方式創建一個簡單的表格。我有一些對象,我想將一些屬性映射到標題,將集合映射到行。

爲什麼減價?因爲我想稍後手動編輯該文檔。眼下,整個過程是這樣的:

  • 報告引擎是在C#
  • 有從中產生DOCX對象(有中間XML或類似的東西)
  • 幾乎總是我必須做微小的修復,我必須在MS Word中打開docx文檔
  • 讓開發人員團隊修復每一個錯誤是很麻煩的,因爲他們根本沒有時間立即執行,我必須等待下一個版本。

我已經想通了,如果我得到Markdown文檔,我可以很容易地編輯它,插入一些變量並使用pandoc替換給定數據的變量。但要獲得Markdown,我必須知道開發人員如何在Markdown中生成表格。

+0

你沒有提到Haskell。如果您可以在Haskell中編寫簡單腳本,則可以使用pandoc API(特別是Text.Pandoc.Builder)輕鬆創建表,並將它們編寫爲pandoc支持的任何格式,包括markdown。 –

+0

我沒有提到,因爲我不知道haskell。然而。嗯,現在我正在尋找現成的解決方案。 =>降價表。如果沒有這樣的解決方案,我會嘗試編寫這樣的腳本,但是我怎麼可以在.NET代碼中集成haskell?需要做一些研究...... – Simon

+0

不幸的是,Markdown沒有(但?)支持表格,但有些擴展可以。特別是,Doxygen爲Markdown提供了很好的表格擴展。 –

回答

5

我需要做幾乎相同的事情來生成Doxygen Markdown表,所以我想我會分享。我已經在Python 2.7和3.3中成功運行了示例代碼,儘管我不能聲稱我已經嚴格測試了它。

# Generates tables for Doxygen flavored Markdown. See the Doxygen 
# documentation for details: 
# http://www.stack.nl/~dimitri/doxygen/manual/markdown.html#md_tables. 

# Translation dictionaries for table alignment 
left_rule = {'<': ':', '^': ':', '>': '-'} 
right_rule = {'<': '-', '^': ':', '>': ':'} 

def evalute_field(record, field_spec): 
    """ 
    Evalute a field of a record using the type of the field_spec as a guide. 
    """ 
    if type(field_spec) is int: 
     return str(record[field_spec]) 
    elif type(field_spec) is str: 
     return str(getattr(record, field_spec)) 
    else: 
     return str(field_spec(record)) 

def table(file, records, fields, headings, alignment = None): 
    """ 
    Generate a Doxygen-flavor Markdown table from records. 

    file -- Any object with a 'write' method that takes a single string 
     parameter. 
    records -- Iterable. Rows will be generated from this. 
    fields -- List of fields for each row. Each entry may be an integer, 
     string or a function. If the entry is an integer, it is assumed to be 
     an index of each record. If the entry is a string, it is assumed to be 
     a field of each record. If the entry is a function, it is called with 
     the record and its return value is taken as the value of the field. 
    headings -- List of column headings. 
    alignment - List of pairs alignment characters. The first of the pair 
     specifies the alignment of the header, (Doxygen won't respect this, but 
     it might look good, the second specifies the alignment of the cells in 
     the column. 

     Possible alignment characters are: 
      '<' = Left align (default for cells) 
      '>' = Right align 
      '^' = Center (default for column headings) 
    """ 

    num_columns = len(fields) 
    assert len(headings) == num_columns 

    # Compute the table cell data 
    columns = [[] for i in range(num_columns)] 
    for record in records: 
     for i, field in enumerate(fields): 
      columns[i].append(evalute_field(record, field)) 

    # Fill out any missing alignment characters. 
    extended_align = alignment if alignment != None else [] 
    if len(extended_align) > num_columns: 
     extended_align = extended_align[0:num_columns] 
    elif len(extended_align) < num_columns: 
     extended_align += [('^', '<') 
          for i in range[num_columns-len(extended_align)]] 

    heading_align, cell_align = [x for x in zip(*extended_align)] 

    field_widths = [len(max(column, key=len)) if len(column) > 0 else 0 
        for column in columns] 
    heading_widths = [max(len(head), 2) for head in headings] 
    column_widths = [max(x) for x in zip(field_widths, heading_widths)] 

    _ = ' | '.join(['{:' + a + str(w) + '}' 
        for a, w in zip(heading_align, column_widths)]) 
    heading_template = '| ' + _ + ' |' 
    _ = ' | '.join(['{:' + a + str(w) + '}' 
        for a, w in zip(cell_align, column_widths)]) 
    row_template = '| ' + _ + ' |' 

    _ = ' | '.join([left_rule[a] + '-'*(w-2) + right_rule[a] 
        for a, w in zip(cell_align, column_widths)]) 
    ruling = '| ' + _ + ' |' 

    file.write(heading_template.format(*headings).rstrip() + '\n') 
    file.write(ruling.rstrip() + '\n') 
    for row in zip(*columns): 
     file.write(row_template.format(*row).rstrip() + '\n') 

這裏有一個簡單的測試案例:

import sys 

sys.stdout.write('State Capitals (source: Wikipedia)\n\n') 

headings = ['State', 'Abrev.', 'Capital', 'Capital since', 'Population', 
      'Largest Population?'] 

data = [('Alabama', 'AL', '1819', 'Montgomery', '1846', 155.4, False, 
     205764), 
     ('Alaska', 'AK', '1959', 'Juneau', '1906', 2716.7, False, 31275), 
     ('Arizona', 'AZ', '1912', 'Phoenix', '1889',474.9, True, 1445632), 
     ('Arkansas', 'AR', '1836', 'Little Rock', '1821', 116.2, True, 
     193524)] 

fields = [0, 1, 3, 4, 7, lambda rec: 'Yes' if rec[6] else 'No'] 

align = [('^', '<'), ('^', '^'), ('^', '<'), ('^', '^'), ('^', '>'), 
     ('^','^')] 

table(sys.stdout, data, fields, headings, align) 

給出了這樣的輸出:

State Capitals (source: Wikipedia) 

| State | Abrev. | Capital | Capital since | Population | Largest Population? | 
| :------- | :----: | :---------- | :-----------: | ---------: | :-----------------: | 
| Alabama | AL | Montgomery |  1846  |  205764 |   No   | 
| Alaska | AK | Juneau  |  1906  |  31275 |   No   | 
| Arizona | AZ | Phoenix  |  1889  | 1445632 |   Yes   | 
| Arkansas | AR | Little Rock |  1821  |  193524 |   Yes   | 

的Doxygen呈現此爲:

Sample

+0

你的'table()'函數使用'str()'而不給出編碼。當與Unicode輸入數據一起使用時,它將引發UnicodeEncodeErrors –

+0

@AlastairMcCormack,這已經有一段時間了,但它一定是Python 2.7代碼。 –

+1

這是更多的其他人的筆記:)我最近回答了誰引用這個答案,但使用Unicode字符串:) –

0

我有一個要求以編程方式爲recent project生成Markdown,所以我構建了一個庫並將其發佈到GitHub上。希望你會發現它很有用。

該項目名爲MarkdownLog,它是一個輕量級的(即最小的依賴關係)可移植.NET庫(PCL),可以從.NET數據結構(如集合和詞典)生成Markdown。我使用它來記錄內部程序數據結構以進行診斷,但它也應該滿足您的需求。

下面是一個降價表是從集合來構建:

var data = new[] 
{ 
    new{Year = 1991, Album = "Out of Time", Songs=11, Rating = "* * * *"}, 
    new{Year = 1992, Album = "Automatic for the People", Songs=12, Rating = "* * * * *"}, 
    new{Year = 1994, Album = "Monster", Songs=12, Rating = "* * *"} 
}; 

Console.Write(data.ToMarkdownTable()); 

// Produces: 
// 
//  Year | Album     | Songs | Rating 
//  ----:| ------------------------ | -----:| --------- 
//  1991 | Out of Time    | 11 | * * * * 
//  1992 | Automatic for the People | 12 | * * * * * 
//  1994 | Monster     | 12 | * * *  

注意,當這個輸出與GitHub的味降價解析器解析它會產生一個HTML表格。

默認情況下,列根據其數據類型進行對齊(數字是右對齊的,字符串是左對齊的)並且從對象的屬性名稱生成標頭名稱。如果這不是你想要的,那麼有一些覆蓋可以讓你更好地控制輸出。

有內置支持所有的standard Markdown elementsGFM tables。我還添加了一些額外的元素類型(條形圖,iOS UITableView),我需要它們,它們被實現爲code blocks,因此它們仍然遵守Markdown標準。

我只是最近才把代碼上傳到GitHub中,所以文檔現在是基本的。說了這些之後,項目中會有大量的單元測試,這應該證明它是如何工作的。

我很感激自從問了這個問題以來,我已經有一段時間了,但是我希望這個項目對別人有用。

+0

我忘了說,我很想聽到任何意見或建議 – Wheelie