在保留注释的同时修改java中的YAML

在保留注释的同时修改java中的YAML,java,yaml,snakeyaml,Java,Yaml,Snakeyaml,如何修改现有YAML并在其中保留注释。 有没有这样的Java解析器? 例如,如果我有以下YAML: #This is a test YAML name: abcd age: 23 #Test YAML ends here. 是否有一种方法可以使用java解析器编辑此Yaml并保留注释 在撰写本文时,还没有针对Java的往返YAML解析器。有一个著名的项目,它不保留注释(参见),还有一个新的项目,名为,我对它知之甚少;但这绝对不是往返 理论上,您可以使用SnakeYaml的Yaml.pars

如何修改现有YAML并在其中保留注释。 有没有这样的Java解析器? 例如,如果我有以下YAML:

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

是否有一种方法可以使用java解析器编辑此Yaml并保留注释

在撰写本文时,还没有针对Java的往返YAML解析器。有一个著名的项目,它不保留注释(参见),还有一个新的项目,名为,我对它知之甚少;但这绝对不是往返

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


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

我编写了一个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()}")
}

如果使用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);
    }
private-Token-scanplane(){
StringBuilder chunks=新的StringBuilder();
markstartmark=reader.getMark();
标记endMark=开始标记;
int indent=this.indent+1;
字符串空格=”;
while(true){
INTC;
整数长度=0;
//注释表示标量的结束。
//以文本形式阅读内嵌注释
//if(reader.peek(){
//中断;
//            }
while(true){
c=读卡器.窥视(长度);
if(常数为空)br.has(c)
||(c==':'&&Constant.NULL_BL_T_LINEBR.has(reader.peek(长度+1),flowLevel!=0?,[]{}:“)
||(this.flowLevel!=0&&“,?[{}”.indexOf(c)!=-1)){
打破
}
长度++;
}
如果(长度==0){
打破
}
this.allowSimpleKey=false;
chunks.append(空格);
append(reader.prefixForward(length));
endMark=reader.getMark();
空格=扫描平面空格();
//System.out.printf(“空格[%s]\n”,空格);
if(spaces.length()==0
//以文本形式阅读内嵌注释
//| | reader.peek()=='#'
||(this.flowLevel==0&&this.reader.getColumn()
你试过蛇山药吗?默认情况下不支持吗?