【问题标题】:Modifying YAML in java while preserving comments在保留注释的同时在 java 中修改 YAML
【发布时间】:2018-09-23 12:29:06
【问题描述】:

我们如何修改现有的 YAML 并在其中保留 cmets。 是否有任何 Java 解析器可以做到这一点? 例如,如果我有以下 YAML:

#This is a test YAML
 name: abcd
 age: 23
#Test YAML ends here.

有没有办法可以使用 java 解析器编辑这个 Yaml 并保留 cmets。

【问题讨论】:

  • 你吃过蛇山药吗?默认不支持吗?

标签: java yaml snakeyaml


【解决方案1】:

如果你使用snakeyaml,你应该修改ScannerImpl文件。

注意:将内嵌注释读取为文本

private Token scanPlain() {
        StringBuilder chunks = new StringBuilder();
        Mark startMark = reader.getMark();
        Mark endMark = startMark;
        int indent = this.indent + 1;
        String spaces = "";
        while (true) {
            int c;
            int length = 0;
            // A comment indicates the end of the scalar.
            // read the in-line comment as text
//            if (reader.peek() == '#' && ) {
//                break;
//            }
            while (true) {
                c = reader.peek(length);
                if (Constant.NULL_BL_T_LINEBR.has(c)
                        || (c == ':' && Constant.NULL_BL_T_LINEBR.has(reader.peek(length + 1), flowLevel != 0 ? ",[]{}":""))
                        || (this.flowLevel != 0 && ",?[]{}".indexOf(c) != -1)) {
                    break;
                }
                length++;
            }
            if (length == 0) {
                break;
            }
            this.allowSimpleKey = false;
            chunks.append(spaces);
            chunks.append(reader.prefixForward(length));
            endMark = reader.getMark();
            spaces = scanPlainSpaces();
            // System.out.printf("spaces[%s]\n", spaces);
            if (spaces.length() == 0
                    // read the in-line comment as text
//                    || reader.peek() == '#'
                    || (this.flowLevel == 0 && this.reader.getColumn() < indent)) {
                break;
            }
        }
        return new ScalarToken(chunks.toString(), startMark, endMark, true);
    }

【讨论】:

    【解决方案2】:

    我写了一个 groovy 脚本来解决这个问题。 Java 版本非常相似:

    def key = "name"
    def value = "efgh"
    def yamlFile = new File("file.yaml")
    def yamlFileLines = new StringBuilder()
    def foundKey = false
    yamlFile.text.eachLine { line ->
        if (!foundKey && line.contains("$key:")) {
            line = line.replaceAll(/$key:.*/, "$key: $value")
            foundKey = true
        }
        yamlFileLines.append("$line\n")
    }
    if (foundKey) {
        yamlFile.text = yamlFileLines.toString()
    } else {
        throw new StopExecutionException("Could not find key '$key' in file ${yamlFile.getAbsolutePath()}")
    }
    

    【讨论】:

      【解决方案3】:

      截至撰写本文时,还没有适用于 Java 的往返 YAML 解析器。有著名的SnakeYAML,它不保留cmets(参见author's comment here),还有一个名为camel的较新项目,我对此知之甚少;但绝对不是往返。

      理论上你可以做的是使用 SnakeYaml 的 Yaml.parse 然后遍历事件。每个事件都有一个开始和一个结束标记,给出了事件的开始和结束行和列。这使得将事件映射回源并发现源中未解析为事件的部分(可能是 cmets)成为可能。有了这个映射,您现在可以修改事件列表并将其写回。最后,您再次阅读结果,发现原始 YAML 中存在 cmets 而修改后的 YAML 中没有的事件之间的差距,然后重新插入这些 cmets,为您提供修改后的最终 YAML cmets。

      当然,这是非常复杂的。我不建议这样做,除非你 a) 对 YAML 的结构有深刻的理解或愿意学习它,并且 b) 你的用例证明了这么多工作是合理的。

      【讨论】:

        猜你喜欢
        • 2015-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 2018-05-03
        • 2011-03-04
        • 2016-10-26
        • 1970-01-01
        相关资源
        最近更新 更多