最适合存储交叉引用的文件格式

时间:2018-06-01 11:01:37

标签: python json xml reference yaml

我需要在我的资产之间存储一些元信息和依赖关系,在我可以用来做一些验证的文件中。

以JSON为例,我的元数据文件看起来像这样(/publish/path/metadata/poster.json):

{
    'created_by': 'John',
    'creation_date': '12112018',
    'version': '005',
    'creator_comments': 'Updated to latest published images for Poppy',
    'path_to_file': '/publish/path/images/poster.png',
    'dependencies': [
                     '/publish/path/metadata/poppy.json',
                     '/publish/path/metadata/dwarf.json',
                     '/publish/path/metadata/giant.json'
                     ]
}

和(/publish/path/metadata/poppy.json):

  {
        'created_by': 'Daug',
        'creation_date': '12102018',
        'version': '003',
        'creator_comments': 'Poppy is more red on top',
        'path_to_file': '/publish/path/images/poppy.png',
        'dependencies': [
                         '/publish/path/metadata/poppy_drawing.json',
                         '/publish/path/metadata/poppy_effect.json'
                         ]
    }

我正在寻找一种最合适的文件格式

  1. 能够存储对其他文件的引用
  2. 由可以处理引用的python库支持
  3. 可以被人类轻松阅读
  4. 允许我遍历引用文件的查看器或浏览器支持
  5. 您认为哪种方式最适合我的用例?

2 个答案:

答案 0 :(得分:1)

JSON,YAML和XML都是流行的文件格式,有一些优点和缺点。还有其他文件格式,例如TOMLINI files等。以下是JSON,YAML和XML的概述:

<强> JSON

  • 赞成
  • 缺点
    • 难以阅读多行,因为换行符表示为\n
    • 不太适合手工创作
  • 实现
    • Google应用凭据
    • NPM package.json
    • Swagger / OpenAPI

<强> YAML

  • 赞成
  • 缺点
    • 没有出现在与JSON
    • 一样多的核心语言库中
  • 一些实现
    • Ruby on Rails配置文件
    • Swagger / OpenAPI

<强> XML

  • 赞成
  • 缺点
    • 非常详细且难以阅读
    • XML库用于解析和创建,例如libxml2的。
  • 一些实现
    • 的RSS / Atom

<强>摘要

  • JSON,如果您的数据量有限,并且没有包含多个行值的数据,或者人类不希望读取的多行值。这对配置文件很有用,因为通常不需要外部依赖
  • YAML如果您有更多需要人工创建/编辑的数据,包括多行值
  • XML,如果您有大量数据,则在GB范围内

对于您的查看者要求,您可以使用模式来标识文件链接,然后修改现有查看器以在存在时添加链接。当然,您也可以从头开始创建自己的。

根据您的要求,JSON和YAML似乎是最合适和最受欢迎的。好处是有许多通用工具可以来回转换JSON和YAML。自动转换并不像其他文件格式那样普遍。

答案 1 :(得分:0)

YAML旨在包括人类可读的数据形式,例如您的数据(但有多种方式在YAML中表示不太可读的数据)

XML,我看到它被描述为具有二进制的可读性以及ASCII的低效率。

JSON有太多双引号使其实际数据脱颖而出。如果你想手动编辑数据,你必须要注意数组和对象中的尾随逗号。

当然没有直接支持您的格式的查看器或浏览器,但如果您从JSON开始,则可以编写一个JavaScript程序,使用超链接正确显示每个数据集。通过浏览器内置的de DOMparser开始使用XML时,也可以这样做。在javascript中也有YAML解析器可以对基于YAML的数据执行相同的操作,但是这些必须安装并加载到浏览器中。

如果你不想用javascript编程,我会把数据放在YAML中并有一个Python程序(递归地)查看所有单独的YAML文件并从这些文件生成HTML,包括正确的超链接(到依赖项的HTML“版本”,或者链接到图像,或者就地显示图像。如果包含YAML文档的相应文件具有更新的时间戳,则使程序足够智能以仅(重新)生成HTML。

这类似于一些博客系统如何工作,从标记生成静态视图。既然你想要使用Python处理数据,你应该能够重复使用你编写的一些代码。

您应该制作/publish/path/metadata/poster.yaml

created_by: John
creation_date: 2018-11-12
version: 005
creator_comments: Updated to latest published images for Poppy
path_to_file: /publish/path/images/poster.png
dependencies:
- /publish/path/metadata/poppy.yaml
- /publish/path/metadata/dwarf.yaml
- /publish/path/metadata/giant.yaml

正如您所看到的,您不必将日期写为字符串,YAML直接支持YYYY-MM-DD格式(不清楚您的creation_date是否为美国或DDMMYYYY中使用的MMDDYYYY,因为更多wideley在其他英语国家使用)。如何在HTML中显示日期当然是您的首选。

使用您的YAML,您应该遵守最新规范(2009年为1.2)并使用ruamel.yaml(免责声明:我是该软件包的作者)。如果您选择YAML 1.1(在这种情况下您可以使用PyYAML),您必须引用并将您的版本定义为标量字符串,因为PyYAML会将version: 015解释为数字13. ruamel.yaml也正确往返并使用前导零再次写入此类整数。如果您的版本包含非数字数据,则YAML会自动将其作为字符串加载(无需引用)。

对于转储HTML,有许多选项,使用一些库来创建树结构然后转储,这样做的好处是无法生成无效的HTML。但即使您“手动”生成HTML,也应该相对快速地调试输出。

转换程序当然也可以检查所有引用是否存在,如果不存在则发出警告。

执行上述操作的简单程序(HTML不如输出):

from datetime import date
from pathlib import Path
from ruamel.yaml import YAML
from ruamel.yaml.scalarint import ScalarInt

yaml = YAML()

def convert_data(d, fp, level=0):
    """recursively write a loaded YAML document as HTML"""
    if isinstance(d, dict):
        print('<table>', file=fp)
        for k in d:
            print('<tr><td>', file=fp)
            convert_data(k, fp, level=level+1)
            print('</td><td>', file=fp)
            v = d[k]
            convert_data(v, fp, level=level+1)
            print('</td></tr>', file=fp)
        print('</table>', file=fp)
        return
    if isinstance(d, list):
        print('<ul>', file=fp)
        for elem in d:
            print('<li>', file=fp)
            convert_data(elem, fp, level=level+1)
            print('</li>', file=fp)
        print('</ul>', file=fp)
        return
    if isinstance(d, str) and d and d[0] == '/':
        if d.endswith('.yaml'):
            h = Path(d).with_suffix('.html')
            print('<a href="{}">{}</a>'.format(h, d), file=fp)
            return
        if d.endswith('.png'):
            print('<img src="{}">'.format(d), file=fp)
            return
    if isinstance(d, ScalarInt):
        if d._width is not None:
            # integer with leading zeros
            print('{:0{}d}'.format(d, d._width), file=fp)
        return
    if isinstance(d, date):
        # print the date in DDMMYYYY format
        print('{:%d%m%Y}'.format(d), file=fp)
        return
    print(d, file=fp)

def convert_file(yaml_file, html_file):
    data = yaml.load(yaml_file)
    with html_file.open('w') as fp:
        print('<html>\n<body>', file=fp)
        convert_data(data, fp)
        print('</body>\n</html>', file=fp)

def main():
    for yaml_file in Path('.').glob('*.yaml'):
        html_file = yaml_file.with_suffix('.html')
        if True or not html_file.exists() or \
           html_file.stat().st_mtime < yaml_file.stat().st_mtime:
            convert_file(yaml_file, html_file)


if __name__ == '__main__':
    main()

您当然可以使用标记(!link /publish/path/metadata/poppy.yaml!img /publish/path/images/poster.png来显示链接和图像,并使用包含这些标记的构造函数的类然后转储适当的HTML。但这不一定会给您带来更好的可读YAML。