2012-11-15 35 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