YAML(Ruby)加载“on”作为true

4

我正在尝试从YAML文件中加载单词列表。在文件中有一个条目

- on

Ruby将其加载为“true”,而不是“on”。同样,“off”被加载为“false”。Psych代码的快速检查显示“yes”和“no”被以相同方式处理。

除了在on和off周围添加引号外,有没有其他方法可以更改此行为?

如果使用read方法和解析而不是load_file,我可以看到值。

# test.yaml
- true
- false
- yes
- no
- on
- off
- y
- n
- Y
- N

我通过解析而非加载获取了一份心理学文档,其中包含转换成原生格式之前的文本。
YAML.parse_file('test.yaml')

想知道如何正确提取数据。

从文档中得知

"表示阶段意味着已经组成为YAML::BaseNode对象的数据。在此阶段,文档可用作节点对象树。您可以在此级别执行YPath查询和转换。(请参见YAML::parse。)"

需要帮助编写全面的YPath查询以提取数据。

(PS:这可能看起来有点绕,但对于我的数据管理来说,这清理了很多东西)


你有编辑 yaml 文件的权限吗? - Arup Rakshit
4个回答

5

在YAML 参考卡中列出了它,但我找不到规范中对它的任何参考。

独立于语言的标量类型:
   …
    { Y, true, Yes, ON  }    : 布尔值 true
    { n, FALSE, No, off }    : 布尔值 false
   …

我认为引号是你唯一的选择。


有趣!在心理学中,Y和n没有作为布尔值实现。 - Geordee Naliyath
1
FYI,true/false的yes/no别名在YAML 1.2规范(当前版本)中已被删除。这可能是你没有看到它的原因。它在YAML 1.1中存在,我猜一些软件包仍然支持1.1。 - LearningFast

2
如其他答案中所解释的那样,on 被认为是“真实”的值。这种行为是 故意编码在心理学中 的。
正如 Arup Rakshit 和 Mikhail P 所解释的那样,问题的最佳解决方案是引用该值。然而,考虑到您的问题要求提供另一种选择,这里有一个替代方案。
Psych 中的标量转换是硬编码在 Psych::ScalarScanner#tokenize 中的。一个可能的(但强烈不建议的)选项是对此方法进行 monkey patch,以更改这个 case 语句
    when /^(yes|true|on)$/i
      true
    when /^(no|false|off)$/i
      false

您可能已经意识到,在查看源代码时,这种方法非常冗长,而猴子补丁将迫使您复制/粘贴相当大的代码块。没有简单的方法,选项是硬编码到选择案例中(这更表明这不是一个好主意)。
个人而言,我永远不会走这条路。修改Psych的核心行为可能会导致几个意外的副作用,因为其他库可能依赖于此行为。
另一个选择是,如果您不想在物理上修改原始文件,则可以编写代理程序,在运行时更改它。
实际上,您可以创建一个CustomYaml解析器,它实现了一个parse_file方法。该方法将在内存中读取文件内容,执行任何未转义的on出现的“搜索和替换”,将其替换为"on",然后使用YAML.load()加载。
这将欺骗YAML解析器,导致它将每个"on"标记解释为标量字符串。
类似于这种预处理方法,您可以采用后处理方法,通过遍历Psych返回的YAML AST来实现。

进行预处理是一种选择。谢谢! - Geordee Naliyath
如果以YAML参考卡(请参见Mikhail P的帖子)为基础,Psych会忽略“Y”和“N”。 - Geordee Naliyath

1

正如你提示的那样,我通过修改AST使其工作。

代码如下:

src = YAML.parse(data)
src.select{ |node| node.is_a?(Psych::Nodes::Scalar) &&
                   %w(on off).include?(node.value) }
  .each{|node| node.quoted = true }

基本上,这只是欺骗系统认为所有带有值 onoff 的值节点都带引号。这使它们看起来像字符串。
当然,这是依赖于具体实现的,对于其他不同于Psych的情况,可能需要采用不同的方法。

我想现在我有一个更简单的版本,只适用于我的当前需求。然而,在更一般的情况下,我们可能需要做类似的事情。 - Geordee Naliyath

0

这似乎对我的当前需求有效。

require 'yaml'

ydoc = YAML.parse_file('test.yaml')
puts ydoc.children.map { |sequence| sequence.children.map { |scalar| scalar.value }}

"children"可以帮助从心理文档>心理序列>心理标量下移。

请告诉我您的意见。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接