ohler55/ojg

Extracting Multiple Fields

UNC1739 opened this issue · 2 comments

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

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.

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