arraysjsonjenkinsgroovy

Jenkins get JSON array element by key value pair


Let say I have a JSON file contains this elements:

{
"metadata":
    {
    "result":1,"version":1,"command":"dumpzone","reason":"Zone Serialized"
    },
"data":
    {"zone":
    [
        {"record":
        [
            {"type":"$TTL","ttl":"14400","Line":3},
            {"ttl":86400,"Line":5,"type":"NS","class":"IN","name":"domain.tld.","nsdname":"ns01.domain.tld"},
            {"type":"NS","ttl":86400,"Line":6,"class":"IN","nsdname":"ns01.domain.tld","name":"domain.tld."},
            {"address":"1.2.3.4","type":"A","Line":8,"ttl":14400,"class":"IN","name":"domain.tld."},
            {"Line":9,"ttl":14400,"type":"MX","class":"IN","name":"domain.tld.","exchange":"mail.domain.tld","preference":"5"},
            {"type":"MX","ttl":14400,"Line":10,"class":"IN","name":"domain.tld.","preference":"10","exchange":"anothermail.domain.tld"},
            {"name":"example1.domain.tld.","class":"IN","ttl":14400,"type":"A","Line":492,"address":"1.2.3.4"},
            {"name":"example2.domain.tld.","class":"IN","address":"1.2.3.4","ttl":14400,"Line":493,"type":"A"},
            {"name":"example3.domain.tld.","class":"IN","ttl":14400,"Line":494,"type":"A","address":"1.2.3.4"},
            {"name":"example4.domain.tld.","class":"IN","ttl":14400,"Line":1109,"type":"A","address":"1.2.3.4"},
            {"ttl":14400,"Line":1110,"type":"A","address":"1.2.3.4","class":"IN","name":"exampleX.domain.tld."}
        ]
        }
    ]
    }
}

I have a Jenkins pipeline as well, what will echo the Line value for name example2.domain.tld.:

pipeline {
...
    stages {
        stage ('Validate actions') {
            steps {
                script {
                    def jsonString = '{"metadata":{"result":1,"version":1,"command":"dumpzone","reason":"Zone Serialized"},"data":{"zone":[{"record":[{"type":"$TTL","ttl":"14400","Line":3},{"ttl":86400,"Line":5,"type":"NS","class":"IN","name":"domain.tld.","nsdname":"ns01.domain.tld"},{"type":"NS","ttl":86400,"Line":6,"class":"IN","nsdname":"ns01.domain.tld","name":"domain.tld."},{"address":"1.2.3.4","type":"A","Line":8,"ttl":14400,"class":"IN","name":"domain.tld."},{"Line":9,"ttl":14400,"type":"MX","class":"IN","name":"domain.tld.","exchange":"mail.domain.tld","preference":"5"},{"type":"MX","ttl":14400,"Line":10,"class":"IN","name":"domain.tld.","preference":"10","exchange":"anothermail.domain.tld"},{"name":"example1.domain.tld.","class":"IN","ttl":14400,"type":"A","Line":492,"address":"1.2.3.4"},{"name":"example2.domain.tld.","class":"IN","address":"1.2.3.4","ttl":14400,"Line":493,"type":"A"},{"name":"example3.domain.tld.","class":"IN","ttl":14400,"Line":494,"type":"A","address":"1.2.3.4"},{"name":"example4.domain.tld.","class":"IN","ttl":14400,"Line":1109,"type":"A","address":"1.2.3.4"},{"ttl":14400,"Line":1110,"type":"A","address":"1.2.3.4","class":"IN","name":"exampleX.domain.tld."}]}]}}'
                    def props = readJSON text: jsonString
                    echo "Line number for the record: ${props.data.zone[0].record[7].Line}"
                }
            }
        }
    }
}

In this case, because I know it is the 8th line, I give the array element number, then it will echo the line. Let say I don't know which element contains the "name":"example2.domain.tld." AND "type":"A" key:value pairs, so I would like to search for its element in array record then echo the Line key's value. If there are multiple matches (it might possible) then I would like to know only the first match. How should I modify my pipeline to achive this?


Solution

  • Instead of

    props.data.zone[0].record[7].Line
    

    you can do

    props.data.zone[0].record.find{ it.name == 'example2.domain.tld.' && it.type == 'A' }.Line
    

    You can use safe navigation ?. if you want to harden against some unexpected data. And I would strongly encourage to always call readJSON with returnPojo: true, otherwise you are getting an object with some unexpected properties.