带位置信息的YAML反序列化器?

带位置信息的YAML反序列化器?,yaml,Yaml,有人知道YAML反序列化程序可以为构造的对象提供位置信息吗 我知道如何将YAML文件反序列化为Java对象。简单的说明。 但是,我想对反序列化对象进行一些算法验证,并向指向YAML中导致错误的位置的用户报告错误 例如: ==========YAML文件========== name: Nathan Sweet age: 28 address: 4011 16th Ave S =======JAVA类====== public class Contact { public String

有人知道YAML反序列化程序可以为构造的对象提供位置信息吗

我知道如何将YAML文件反序列化为Java对象。简单的说明。 但是,我想对反序列化对象进行一些算法验证,并向指向YAML中导致错误的位置的用户报告错误

例如: ==========YAML文件==========

name: Nathan Sweet
age: 28
address: 4011 16th Ave S
=======JAVA类======

public class Contact {
    public String name;
    public int age;
    public String address;
}
想象一下,如果我想首先将yaml加载到Contact类中,然后根据某个存储库验证地址,如果地址无效,则返回错误。比如: '第3行第9列:地址与数据库中的有效条目不匹配'

问题是,目前无法从YAML获取反序列化对象内部的位置。


有人知道这个问题的解决方案吗?

大多数YAML解析器在构建语言本机对象时,如果保留任何关于其周围位置的信息,就会将其丢弃

在ª中,我保留了更多信息,因为我希望能够在尽量减少原始布局损失的情况下往返(例如,在映射中保留注释和键顺序)

我不保留关于单个键值对的信息,但我在映射的“左上”位置保留信息。由于映射项的顺序保持不变,所以您可以提供一些相当好的反馈。给定一个输入文件:

- name: anthon
  age: 53
  adres: Rijn en Schiekade 105
- name: Nathan Sweet
  age: 28
  address: 4011 16th Ave S
以及以输入文件作为参数调用的程序:

#! /usr/bin/env python2.7
# coding: utf-8
# http://stackoverflow.com/questions/30677517/yaml-deserializer-with-position-information?noredirect=1#comment49491314_30677517

import sys
import ruamel.yaml

up_arrow = '↑'

def key_error(key, value, line, col, error, e='E'):
    print('E[{}:{}]: {}'.format(line, col, error))
    print('{}{}: {}'.format(' '*col, key, value))
    print('{}{}'.format(' '*(col), up_arrow))
    print('---')


def value_error(key, value, line, col, error, e='E'):
    val_col = col + len(key) + 2
    print('{}[{}:{}]: {}'.format(e, line, val_col, error))
    print('{}{}: {}'.format(' '*col, key, value))
    print('{}{}'.format(' '*(val_col), up_arrow))
    print('---')

def value_warning(key, value, line, col, error):
    value_error(key, value, line, col, error, e='W')

class Contact(object):
    def __init__(self, vals):
        for offset, k in enumerate(vals):
            self.check(k, vals[k], vals.lc.line+offset, vals.lc.col)
        for k in ['name', 'address', 'age']:
            if k not in vals:
                print('K[{}:{}]: {}'.format(
                    vals.lc.line+offset, vals.lc.col, "missing key: "+k
                ))
                print('---')


    def check(self, key, value, line, col):
        if key == 'name':
            if value[0].lower() == value[0]:
                value_error(key, value, line, col,
                            'value should start with uppercase')
        elif key == 'age':
            if value < 50:
                value_warning(key, value, line, col,
                              'probably too young for knowing ALGOL 60')
        elif key == 'address':
            pass
        else:
            key_error(key, value, line, col,
                      "unexpected key")

data = ruamel.yaml.load(open(sys.argv[1]), Loader=ruamel.yaml.RoundTripLoader)

for x in data:
    contact = Contact(x)
您应该能够在任何语言的调用程序中解析它以提供反馈。
check
方法当然需要根据您的需求进行调整。这不如用应用程序的其他部分所使用的语言来实现这一点,但这可能比什么都不做要好

根据我的经验,处理上述格式肯定比扩展现有(开源)YAML解析器简单

1免责声明:我是该软件包的作者

²我希望在某些时候使用此类信息来保留伪换行符,这些换行符是为了可读性而插入的。在python中,您可以轻松编写自定义转储程序/加载程序对象,并使用它们加载(或转储)yaml代码。您可以让这些对象跟踪文件/行信息:

import yaml
from collections import OrderedDict

class YamlOrderedDict(OrderedDict):
    """
    An OrderedDict that was loaded from a yaml file, and is annotated
    with file/line info for reporting about errors in the source file
    """
    def _annotate(self, node):
        self._key_locs = {}
        self._value_locs = {}
        nodeiter = node.value.__iter__()
        for key in self:
            subnode = nodeiter.next()
            self._key_locs[key] = subnode[0].start_mark.name + ':' + \
                                  str(subnode[0].start_mark.line+1)
            self._value_locs[key] = subnode[1].start_mark.name + ':' + \
                                    str(subnode[1].start_mark.line+1)
    def key_loc(self, key):
        try:
            return self._key_locs[key]
        except AttributeError, KeyError:
            return ''
    def value_loc(self, key):
        try:
            return self._value_locs[key]
        except AttributeError, KeyError:
            return ''

# Use YamlOrderedDict objects for yaml maps instead of normal dict
yaml.add_representer(OrderedDict, lambda dumper, data:
    dumper.represent_dict(data.iteritems()))
yaml.add_representer(YamlOrderedDict, lambda dumper, data:
    dumper.represent_dict(data.iteritems()))
def _load_YamlOrderedDict(loader, node):
    rv = YamlOrderedDict(loader.construct_pairs(node))
    rv._annotate(node)
    return rv
yaml.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, _load_YamlOrderedDict)
现在,当您读取yaml文件时,所有映射对象都将被读取为YAMLORDEREDICT,这允许在映射对象中查找键的文件位置。还可以添加迭代器方法,如:

def iter_with_lines(self):
    for key, val in self.items():
        yield (key, val, self.key_loc(key))
…现在您可以编写如下循环:

for key,value,location in obj.iter_with_lines():
    # iterate through the key/value pairs in a YamlOrderedDict, with
    # the source file location

您的问题没有标记为Java,这是否意味着您愿意接受其他语言的答案?是的,我也对其他语言的解决方案感兴趣?是否有基于Java的解决方案?我还对带有位置信息的JSON反序列化器感兴趣。除了YAML不是JSON之外,应该使用相同的示例。行号和列号以0开头,对于用户反馈,您可能希望在其中添加1(一)。这非常好。然而,我的情况不同。我想给出的反馈并不是直接来自yaml的语法查找,而是我有一个复杂的java代码来分析对象模型并进行报告。这就是为什么我想创建一个带有行号的对象模型来为java管道提供有用的反馈。然而,我的情况不同。我想给出的反馈并不是直接来自yaml的语法查找,而是我有一个复杂的java代码来分析对象模型并进行报告。这就是为什么我想创建带有行号的by-object模型来为java管道提供有用的反馈。
for key,value,location in obj.iter_with_lines():
    # iterate through the key/value pairs in a YamlOrderedDict, with
    # the source file location