带位置信息的YAML反序列化器?
有人知道YAML反序列化程序可以为构造的对象提供位置信息吗 我知道如何将YAML文件反序列化为Java对象。简单的说明。 但是,我想对反序列化对象进行一些算法验证,并向指向YAML中导致错误的位置的用户报告错误 例如: ==========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
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