【问题标题】:How to update a certain value inside this jackson JsonNode?如何更新此杰克逊 JsonNode 中的某个值?
【发布时间】:2021-06-24 06:27:51
【问题描述】:

TLDR: 我想更新 JsonNode 键 dependsOn 的某个值并将结果作为 JsonNode 返回。目前我正在将值转换为String,对字符进行切片,然后使用ObjectMapper 将字符串转换回JsonNode

我有一个如下所示的 json 对象

{
    "name": "somename",
    "type": "sometype",
    "description": "some desc",
    "properties": {
        "path": "some path",
        
        "dependsOn": [
            "ABC:zzz","DEF:sdc","GHI:ere"
        ],
        
        "checkpoint": "some checkpoint",
        "format": "some format",
        "output": "some output",
        "table": "some table"
    }
}

我目前正在解析上述 json 数据并将dependsOn 作为 JsonNode 元素获取(如下所示)

JsonNode components = model.get("properties");
JsonNode dependsOn = components.get("dependsOn");

当我打印dependsOn 时,它看起来像这样"["ABC:zzz","DEF:sdc","GHI:ere"]"

我的要求是strip : 之后的所有内容来自 dependsOn 数组

以下代码帮助我将 JsonNode 转换为 String,然后剥离 :whatever,然后将其转换回 JsonNode

if (dependsOn != null && !dependsOn.isEmpty()) {
  String dependsOnString =
          components
                  .get("dependsOn")
                  .get(0)
                  .textValue()
                  .substring(
                          0,
                          (components.get("dependsOn").get(0).textValue().lastIndexOf(":") != -1)
                                  ? components.get("dependsOn").get(0).textValue().lastIndexOf(":")
                                  : components.get("dependsOn").get(0).textValue().length());
  ObjectMapper mapper = new ObjectMapper();
  dependsOn = mapper.readTree("[\"" + dependsOnString + "\"]");
}

输入:

"["ABC:zzz","DEF:sdc","GHI:ere"]"

输出

"["ABC","DEF:sdc","GHI:ere"]"

上面的代码只去除了数组的第一个元素,我可以循环并为其余元素执行相同的操作。但我有几个关于我想做的事情的问题

首先,我这样做是正确的还是有更简单的 技术做到这一点?而不是将其转换为字符串,然后 再次到 JsonNode..

接下来,我只对first element of the array做了这个 我想循环并为all the elements of the array 执行此操作。有没有比使用 for/while 循环更简单的解决方案?

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    您可以在将dependsOn 转换为ArrayNode 后对其进行迭代并为其设置值:

    ArrayNode array = ((ArrayNode) dependsOn);
    List<String> newValues = new ArrayList<>();
    
    for(int i=0;i<array.size();i++) {
        newValues.add(array.get(i).asText().split(":")[0]);
    }
    
    array.removeAll();
    newValues.forEach(array::add); 
    

    编辑:如果您不想更新原来的 dependsOn,请使用:

    JsonNode copy = dependsOn.deepCopy();
    // or you could invoke `deepCopy` on the `ArrayNode` as well
    

    现在传递这个copy 对象进行切片操作。使原来的json保持不变。

    【讨论】:

    • 在此之后,切片值的最终数组将在 dependsOn 节点中吗?或者我应该在这之后添加dependsOn = array
    • @Akhil,不,dependsOn 已经更新了。如果你输出 components 你可以看到更新的 json
    • 是的,明白了。经过测试并按预期工作“除了”我的dependsOn不应该像上面的代码那样被覆盖(ArrayNode强制转换正在这样做),因为我将dependsOn传递给不同的函数并且它不应该发送切片内容而不是前一个数据
    • @Akhil 我想你没有在问题中提到这个用例。无论如何,我已经更新了答案。您可以使用deepCopy 来避免更新原始节点。
    【解决方案2】:

    这应该可以工作,无需转换为字符串并再次解析为 jsonNode

    JsonNode prop = node.get("properties");
    JsonNode arrayCopy = prop.get("dependsOn").deepCopy();
    var array = ((ObjectNode)prop).putArray("dependsOn");
    IntStream.range(0, arrayCopy.size())
        .forEach(index -> {
          String elem = arrayCopy.get(index).asText();
          String finalElem = elem.substring(0,elem.contains(":") ? elem.lastIndexOf(':') : elem.length());
          array.add(finalElem);
        });
    

    【讨论】:

      【解决方案3】:

      由于我的用例建议我的 dependsOn 值不应在节点级别被覆盖,我必须将 JsonNode 转换为 String,然后使用正则表达式匹配器在每个元素中将:xyz 替换为空字符串,然后将其转换JsonNode

      String pattern = ":[a-zA-Z]+";
              String newDependsOn = dependsOn.toString().replaceAll(pattern, "");
              ObjectMapper mapper = new ObjectMapper();
              dependsOn = mapper.readTree(newDependsOn);
      

      @Gautham 的解决方案也确实有效,但我认为它在根部被覆盖,并且旧值在循环之外不再可用

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-03-13
        • 1970-01-01
        • 1970-01-01
        • 2019-08-22
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多