【问题标题】:Groovy/Java - JSON - Update JSON through variable pathGroovy/Java - JSON - 通过变量路径更新 JSON
【发布时间】:2017-05-02 13:53:30
【问题描述】:

有人知道如何在 groovy 中使用可变路径有效地设置 json 吗?

上下文:我正在使用测试工具 soapui。一些测试是数据驱动的候选者。我有很多变数。为了使一些可持续的东西在类似情况下易于实施,我想要一个能够让我设置变量的 Groovy 脚本。

我会将变量命名为“parent.subParent.child”。

我发现了什么:

我确实找到了其他东西,但没有全部记录下来。

我发现的直截了当的事情是评估。通过评估可以获得值,但不能设置它们。

Eval.x(jsonbuilder, 'x.content.' + path) = 'newValue'

将返回错误。但就像我说的,以这种方式检索 json 中的值没有问题。

我尝试了什么: 我有一个适用于一个级别的实现。 我可以说:

jsonbuilder.content.parent.subParent[child] = 'newValue'

这将设置请求实体的值。

然后我尝试将其扩展到未定义的级别。

//Assuming there is a jsonbuilder initialized
def jsonString = "{"parent":{"subParent":{"child":"oldValue"}}}"

def json = new JsonSlurper().parseText(jsonString)

def jsonbuilder = new JsonBuilder(json)

def path = 'parent.subParent.child'

def listPath = path.split("\\.")

def element = jsonbuilder.content

for(int i = 0; i < listPath.size(); i++) {
    element = element[listPath[i]]
}

element = 'newValue'

assert jsonbuilder.toString() == "{"parent":{"subParent":{"child":"newValue"}}}"

问题:原始 json 中的值未更新。可能是因为我将 jsonbuilder 变量分配给“元素”并继续使用该实体。

这给我留下了两个问题:

  • 如何获取原始json中的元素值?
  • 更一般性:如何使用可变路径更新 json?

使用 jsonbuilder 的基本 JSON 分配函数如下所示:jsonbuilder.content.parent.subParent.child = 'newValue' 以下答案之一中给出的不是我想要的。我正在寻找一种使整个事物充满活力的方法。我不想建立一个简单的任务,它已经存在并且运行良好。我正在寻找一台为我完成分配的机器,并将变量名解析为路径。最好在 groovy.json.* 环境中,但如果我必须涉及外部库,那就这样吧。

【问题讨论】:

    标签: java json groovy soapui


    【解决方案1】:

    我对 Eval 的具体实现视而不见。如果我从一开始就阅读文档,我的解决方案实际上很简单。

    您可以在此处找到 Eval 的文档:http://docs.groovy-lang.org/2.4.7/html/api/groovy/util/Eval.html

    与其尝试为评估的方法/函数分配一个值,现在我认为这不合逻辑,您需要将所有内容集成到评估的表达式中。根据我的发现,您最多可以在 Eval 函数中使用三个变量。

    我只需要两个。我需要 jsonbuilder 对象才能获取信息源。我需要设置要设置的值。路径本身可以原样使用,因为它已经是评估所需的:一个字符串。

    代码:

    import groovy.json.*
    
    def jsonString = '{"parent":{"child":"oldValue"}}'
    def newValue = 'newValue'
    def stringPath = 'parent.child'
    
    def json = new JsonSlurper().parseText(jsonString)
    def jsonbuilder = new JsonBuilder(json)
    
    Eval.xy(jsonbuilder, newValue, 'x.content.' + stringPath + '= y')
    
    System.out.println(jsonbuilder.toString()=='{"parent":{"child":"newValue"}}')
    System.out.println(jsonbuilder.content.parent.child == 'newValue')​​​​​​​
    

    通过使用Eval.xy(objectOne, objectTwo, StringExpression),我告诉我我正在传递一个要作为表达式求值的字符串,其中 x 代表 objectOne,y 代表 objectTwo。

    代码可以在此处的在线 groovy 脚本引擎中查看:https://groovyconsole.appspot.com/edit/5202721384693760

    小免责声明:我无法想象在代码库中使用评估表达式来让外部世界随机操纵变量。如果使用此表达式,它将在我的 SoapUI 项目的上下文中轻松使用。

    【讨论】:

    • 这要好得多,也更时髦。
    【解决方案2】:

    既然你愿意使用库,json-path 就会这样做。

    来自here@kalle 的致谢

    • here下载压缩文件
    • 从上面的 zip 中提取库及其依赖项
    • 复制到SOAPUI_HOME/bin/ext目录下
    • 重启 SoapUI

    给你:

    import com.jayway.jsonpath.Configuration
    import com.jayway.jsonpath.JsonPath
    import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider
    import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider
    
    Configuration configuration = Configuration.builder()
            .jsonProvider(new JacksonJsonNodeJsonProvider())
            .mappingProvider(new JacksonMappingProvider())
            .build()
    
    //You need to prepend $. before the path which becomes valid jsonpath
    def path = '$.parent.subParent.child'
    
    def originalJson = """{
        "parent": {
            "subParent": {
                "child": "oldValue"
            }
        }
    }"""
    
    def updatedJson = JsonPath.using(configuration).parse(originalJson).set(path, 'newValue').json()
    
    println(updatedJson.toString())
    

    【讨论】:

      【解决方案3】:

      给你:

      import groovy.json.JsonSlurper
      import groovy.json.JsonBuilder
      
      def jsonString = """{   "parent": {
        "subParent": {
         "child": "oldValue"
        }
      }
      
      }"""
      
      def json = new JsonSlurper().parseText(jsonString)  
      def jsonbuilder = new JsonBuilder(json)
      
      //Assign the value for child with new value
      jsonbuilder.content.parent.subParent.child = 'newValue'
      println jsonbuilder.toPrettyString()​​​​​​​​​​
      

      你可以在线尝试Demo

      【讨论】:

      • @Matthiasdirickx,感谢您为有用的答案投票。如果您认为这是最好的解决方案,请考虑接受它作为答案。或者您正在寻找不同的解决方案?
      • 但问题是如何让它动态化。并不总是三个级别,而且名称是事先不知道的。你给的例子就是我现在设置的。那么我将如何使路径变量?如问题正文中所示,在使用括号时可以使用变量。但这不允许不同的级别。
      • 至于你的问题,更多的上下文。在 SoapUI 中,您可以定义变量。我想通过 REST 服务对必填字段进行扩展测试。有 220 个字段,因此有 220 个变量。我没有为他们每个人创建一个分配,以便能够通过 Excel 表更新 SoapUI 中的 REST 请求消息,但我可能可以在它们的路径之后命名变量。无论如何,我必须定义它们。然后我可以创建一个更短的脚本,该脚本会自动将变量分配到 REST 请求中的正确位置。
      • 现在和将来拥有这样的机制似乎很方便。它将有助于使用 JSON POST 消息正文(我们有很多)对服务中的字段配置进行临时测试,而不必过多地研究任务和技术规范/脚本。这将使更多的公众更容易获得它。这只是为了添加一些上下文。也许有一种更有效的方法,我在这里叫错了三个...... :)
      • @Matthiasdirickx,请参阅您问题的其他答案。与 excel 相比,xlson 非常简单,所以建议这样做。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-03
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-12
      相关资源
      最近更新 更多