【问题标题】:How to change the value (and type) of a jsonslurped lazymap entry如何更改 jsonslurper 惰性映射条目的值(和类型)
【发布时间】:2016-03-21 14:33:41
【问题描述】:

我有以下 JSON:

{"name":"Guillaume","age":33,"address":"main st","pets":[{"type":"dog", "color":"brown"},{"type":"dog", "color":"brown"}]}}

我已经使用 JsonSlurper 来解析它。我需要能够根据各种标准修改 JSON 的内容。我要修改的键是外部定义的。

我可以轻松更改字符串值,如下所示。以下导致lazyMap中的地址字段从“main st”更改为“second st”。

import groovy.json.JsonSlurper
def slurper = new JsonSlurper()  
def result = slurper.parseText('{"person": {"name":"Guillaume","age":33,"address":"main st","pets":[{"type":"dog", "color":"brown"},{"type":"dog", "color":"brown"}]}}')
String address = "result.person.address"  // Note: this is externalized
String newAddressValue = "second st"
Eval.me('result', result, "$address = '$newAddressValue'")
println result.person.address

我似乎无法解决的问题是,如果我想将地址值从字符串更改为地图。

import groovy.json.JsonSlurper
def slurper = new JsonSlurper()  
def result = slurper.parseText('{"person": {"name":"Guillaume","age":33,"address":"main st","pets":[{"type":"dog", "color":"brown"},{"type":"dog", "color":"brown"}]}}')

Map newAddressMap = slurper.parseText(/{"street":"Third Street", "city":"New York", "state":"New York"}/)

Eval.me('result', result, "$address = $newAddressMap")
println result.person.address.getClass()
println result.person.address

上面的 $newAddressMap 被解释为一个字符串,导致以下错误:

启动失败:Script1.groovy:1:当前范围已包含 名称为 York @ 第 1 行,第 51 列的变量。 s = [city:New 约克,州:纽约州

但是,以下方法有效(将地址键值从字符串更改为 LazyMap),但需要我的键是已知的/硬编码的:

result.person.address = newAddressMap
println result.person.address.getClass()
println result.person.address

下面没有错误,但是 $newAddressMap 是一个字符串,而lazyMap 键“address”仍然是一个字符串。

Eval.me('result', result, "$address = '$newAddressMap'")
println result.person.address.getClass()
println result.person.address

如何在运行时定义地址键值的同时将地址键值从字符串更改为映射?

【问题讨论】:

    标签: json groovy eval jsonslurper


    【解决方案1】:

    你的意思是这样吗?

    import groovy.json.*
    
    def slurper = new JsonSlurper()
    // Given your document
    def document = slurper.parseText('{"person": {"name":"Guillaume","age":33,"address":"main st","pets":[{"type":"dog", "color":"brown"},{"type":"dog", "color":"brown"}]}}')
    // And your replacement
    def newAddressMap = slurper.parseText('{"street":"Third Street", "city":"New York", "state":"New York"}')
    
    // And the location of the attribute you want to replace
    def addressPath = 'person.address'
    
    // Split the path, and replace the property with the new map (this mutates document)
    addressPath.split('\\.').with {
        def parent = it[0..-2].inject(document) { d, k -> d."$k" }
        parent[it[-1]] = newAddressMap
    }    
    
    println new JsonBuilder(document).toPrettyString()
    

    哪些打印:

    {
        "person": {
            "address": {
                "city": "New York",
                "state": "New York",
                "street": "Third Street"
            },
            "age": 33,
            "name": "Guillaume",
            "pets": [
                {
                    "color": "brown",
                    "type": "dog"
                },
                {
                    "color": "brown",
                    "type": "dog"
                }
            ]
        }
    }
    

    【讨论】:

    • 这是一个有趣的方法。我的实际 json 是嵌套的并且有列表。我想要更改的字段可能会有很大差异。例如,我需要能够在我的 json 中找到并更改以下预定义占位符:activity[1].person[2].address 和 activity[3].person[0].relative[1].address。做类似 Eval.me('result', result, "$address = '$newAddressValue'") 的事情很有吸引力,因为我不必遍历 json 来查找该字段,但它似乎仅限于更改字符串值.
    • 这些占位符是从哪里来的?如果他们使用输入,则 Eval 是一个相当大的安全风险,如果他们不使用,那么每个人的关闭可能会更好?此外,将这个要求放在问题中可以为我们双方节省一些时间
    • 感谢您的回复。我希望弄清楚为什么我不能使用 eval 分配地图。占位符是通过搜索 json 实例和搜索配置的字段(如人员地址或相对地址)得出的。 json 的每个实例可能有也可能没有字段。所以它们是程序派生的,而不是用户提供的。我对 groovy 很陌生,非常感谢您的帮助。您能否举例说明每个占位符的闭包是什么意思?您的意见有助于实施解决方案,非常感谢。
    猜你喜欢
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多