Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expression for testing root object for key #16

Closed
FrankReh opened this issue May 20, 2019 · 1 comment
Closed

Expression for testing root object for key #16

FrankReh opened this issue May 20, 2019 · 1 comment

Comments

@FrankReh
Copy link

A very interesting parser. I'm trying to use it to parse log files that contain objects at the top level where the object structure being logged is different from line to line. The log file is not one valid JSON object, but rather a series of valid JSON objects. I have logic that parses one object byte slice at a time, and unmarshals to map[string]interface{}.

But I haven't found a jsonpath syntax for testing the root object for the property of having a particular key. I believe I've looked through all the unit tests to better understand the syntax and saw no examples where the root was an object and the test was for the existence of a key. But there also wasn't anything in the documentation (that I found) to explain why this shouldn't be possible.

I could get things working if I read the entire file into memory and created an array out of them ([]interface{}) or if I wrapped each object in a single entry array but now I'm curious whether this should even be possible given the description of a jsonpath.

I've tried a number of things, most nonsensical anyway, but here are a few attempts with their corresponding errors.

package play_test

import (
	"encoding/json"
	"fmt"
	"strings"
	"testing"

	"github.com/PaesslerAG/jsonpath"
)

func TestPlay(t *testing.T) {
	for idx, c := range []struct{ expr, data, expect string }{
		{
			// This works. No surprise.
			expr:   `$.ip`,
			data:   `{"ip": "8.8.8.8", "action": "dns"}`,
			expect: `result: 8.8.8.8`,
		},
		{
			// This one doesn't. It is not legal to request a key that does not exist.
			expr:   `$.ip`,
			data:   `{"action": "dns"}`,
			expect: `error : unknown key ip`,
		},
		{
			// Same error.
			expr:   `($.ip)`,
			data:   `{"action": "dns"}`,
			expect: `error : unknown key ip`,
		},
		{
			// Other illegal syntax.
			expr: `?($.ip != "")`,
			data: `{"action": "dns"}`,
			expect: `error : parsing error: ?($.ip != "")	:1:1 - 1:2 unexpected "?" while scanning extensions`,
		},
		{
			// So how to test whether a key exists?
			// Here the syntax is legal but the result is an empty array.
			expr:   `$[?($.ip)]`,
			data:   `{"ip": "8.8.8.8, "action": "dns"}`,
			expect: `result: []`,
		},
		{
			// This doesn't parse correctly.
			expr: `("ip" in $)`,
			data: `{"ip": "8.8.8.8, "action": "dns"}`,
			expect: `error : parsing error: ("ip" in $)	:1:7 - 1:9 unexpected Ident while scanning parentheses expected ")"`,
		},
		{
			// This doesn't parse correctly either.
			expr: `$[?("ip" in $)]`,
			data: `{"ip": "8.8.8.8, "action": "dns"}`,
			expect: `error : parsing error: $[?("ip" in $)]	:1:10 - 1:12 unexpected Ident while scanning parentheses expected ")"`,
		},
	} {
		v := interface{}(nil)
		json.Unmarshal([]byte(c.data), &v)
		result, err := jsonpath.Get(c.expr, v)
		var buf strings.Builder
		if err == nil {
			fmt.Fprint(&buf, "result: ", result)
		} else {
			fmt.Fprint(&buf, "error : ", err)
		}
		got := buf.String()
		if c.expect != got {
			t.Errorf("idx %d failed comparison", idx)
			t.Log("expect:", c.expect)
			t.Log("got   :", got)
		}
	}

}
@FrankReh
Copy link
Author

Sorry for the bother. Reading through things more, I learned how easy it is to add a function to the language. So I can use a function that tests for the key existence in an object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant