ohler55 / ojg

Optimized JSON for Go
MIT License
839 stars 50 forks source link

Extracting Multiple Fields #117

Closed UNC1739 closed 1 year ago

UNC1739 commented 1 year ago

Does the JSONPath implementation within the OJG library support extracting multiple values from different keys within the same JSONPath query? I haven't been able to find a way to do this using the library, unfortunately. I've got a quick example I can provide if that helps.

Below is some example JSON data that contains information about an AWS S3 bucket.

{
        "accountId": "192547438240",
        "additionalDetails": {
          "ResourceDescription": {
            "Identifier": "elasticbeanstalk-us-east-1-192547438240",
            "Properties": {
              "BucketName": "elasticbeanstalk-us-east-1-192547438240",
              "RegionalDomainName": "elasticbeanstalk-us-east-1-192547438240.s3.us-east-1.amazonaws.com",
              "DomainName": "elasticbeanstalk-us-east-1-192547438240.s3.amazonaws.com",
              "WebsiteURL": "http://elasticbeanstalk-us-east-1-192547438240.s3-website-us-east-1.amazonaws.com",
              "DualStackDomainName": "elasticbeanstalk-us-east-1-192547438240.s3.dualstack.us-east-1.amazonaws.com",
              "Arn": "arn:aws:s3:::elasticbeanstalk-us-east-1-192547438240"
            }
          },
          "TypeName": "AWS::S3::Bucket"
        },
        "region": "ap-northeast-3",
        "resource": {
          "Identifier": "elasticbeanstalk-us-east-1-192547438240",
          "Properties": "{\"BucketName\":\"elasticbeanstalk-us-east-1-192547438240\"}"
        },
        "type": "AWS::S3::Bucket"
      }

I've written the following JSONPath query to extract this data:

$.additionalDetails.ResourceDescription.Properties[WebsiteURL,DualStackDomainName]

I've found using an online JSONPath tool (jsonpath.com) that this query when run against the previously provided sample data produces the following result:

[
  "http://elasticbeanstalk-us-east-1-192547438240.s3-website-us-east-1.amazonaws.com",
  "elasticbeanstalk-us-east-1-192547438240.s3.dualstack.us-east-1.amazonaws.com"
]

However, when using the OJG library I'm not getting any results back from this JSONPath query. Below is the sample code I'm using:

package main

import (
    "fmt"
    "reflect"

    "github.com/ohler55/ojg/jp"
    "github.com/ohler55/ojg/oj"
)

func main() {
    obj, _ := oj.ParseString(`{
        "accountId": "192547438240",
        "additionalDetails": {
          "ResourceDescription": {
            "Identifier": "elasticbeanstalk-us-east-1-192547438240",
            "Properties": {
              "BucketName": "elasticbeanstalk-us-east-1-192547438240",
              "RegionalDomainName": "elasticbeanstalk-us-east-1-192547438240.s3.us-east-1.amazonaws.com",
              "DomainName": "elasticbeanstalk-us-east-1-192547438240.s3.amazonaws.com",
              "WebsiteURL": "http://elasticbeanstalk-us-east-1-192547438240.s3-website-us-east-1.amazonaws.com",
              "DualStackDomainName": "elasticbeanstalk-us-east-1-192547438240.s3.dualstack.us-east-1.amazonaws.com",
              "Arn": "arn:aws:s3:::elasticbeanstalk-us-east-1-192547438240"
            }
          },
          "TypeName": "AWS::S3::Bucket"
        },
        "region": "ap-northeast-3",
        "resource": {
          "Identifier": "elasticbeanstalk-us-east-1-192547438240",
          "Properties": "{\"BucketName\":\"elasticbeanstalk-us-east-1-192547438240\"}"
        },
        "type": "AWS::S3::Bucket"
      }`)

    //
    x, _ := jp.ParseString("$.additionalDetails.ResourceDescription.Properties[WebsiteURL,DualStackDomainName]")
    ys := x.Get(obj)

    fmt.Println("ys =", ys)
    fmt.Println("reflect.TypeOf(ys) = ", reflect.TypeOf(ys))
}

Below is the output from running this program:

➜  test-ojg-jsonpath go build main.go
➜  test-ojg-jsonpath ./main
ys = []
reflect.TypeOf(ys) =  []interface {}
➜  test-ojg-jsonpath
ohler55 commented 1 year ago

My interpretation of one of the early (maybe original) description of JSONPath (https://goessner.net/articles/JsonPath) is that the element in a union can be either numbers which are treated as indexes or names which would be quoted. I know the owner of the jsonpath.com domain has a nice evaluator but that does not make it a standard. There is quite a range of interpretations of what JSONPath is as you can see from https://cburgmer.github.io/json-path-comparison. Anyway to cut the story short, the way OjG expects a union like you want would be:

$.additionalDetails.ResourceDescription.Properties['WebsiteURL','DualStackDomainName']

I did not test with your example but there are similar, albeit simpler, tests in the jp/get_test.go file.

UNC1739 commented 1 year ago

Thanks @ohler55! That worked for what I was trying to accomplish.