Comments (10)
Being open source, I'll take a peek and see if there is a PR I can craft up. But in the meantime, I'd love any sort of discussion around this.
from jsonpath.
I'm starting to think this could be a feature request for this repo or https://github.com/PaesslerAG/gVal because I'm not sure there is a way to parse the JSONPath (complex enough to avoid doing at all/most costs) and use the placeholder hack to generate full paths for all resolved values. I think for simple cases (direct value resolution, single-segment wildcards, single-levels of recursion) it could be possible but more complex cases (recursion with segments after recursion, any level of nested recursion) fails based on my understanding. I think there are other cases that I remember being difficult/impossible but that's the gist of it.
I'll keep digging but as of right now, this is definitely not straight forward.
from jsonpath.
To shed some light on this based on a slightly convoluted example (modified from https://jsonpath.com), here is an example JSON document and the example placeholders returned for a few JSONPath expressions:
JSON
{
"firstName": "John",
"lastName": "doe",
"age": 26,
"address": {
"streetAddress": "naist street",
"city": "Nara",
"postalCode": "630-0192"
},
"phoneNumbers": [
{
"type": "iPhone",
"number": "0123-4567-8888"
},
{
"type": "home",
"number": "0123-4567-8910"
},
{
"miscellaneous": [
{
"type": "mobile",
"number": "0123-4567-8910",
"nested": [
{
"type": "work",
"number": "0123-4567-8910"
}
]
}
]
}
],
"others": [
{
"number": {
"details": {
"type": "home",
"content": "0123-4567-8910"
}
}
},
{
"number": {
"details": {
"type": "work",
"content": "0123-4567-8910"
}
}
}
],
"nested": {
"others": [
{
"number": {
"details": {
"type": "home",
"content": "0123-4567-8910"
}
}
},
{
"number": {
"details": {
"type": "work",
"content": "0123-4567-8910"
}
}
}
]
}
}
Results
jsonpath.Get($)
* $
jsonpath.Get($..number)
* $["others"]["1"]
* $["phoneNumbers"]["0"]
* $["phoneNumbers"]["1"]
* $["phoneNumbers"]["2"]["miscellaneous"]["0"]
* $["phoneNumbers"]["2"]["miscellaneous"]["0"]["nested"]["0"]
* $["nested"]["others"]["0"]
* $["nested"]["others"]["1"]
* $["others"]["0"]
jsonpath.Get($.phoneNumbers[?(@.type == "home")].number)
* $["1"]
jsonpath.Get($..phoneNumbers..number)
* $["0"]
* $["1"]
* $["2"]["miscellaneous"]["0"]
* $["2"]["miscellaneous"]["0"]["nested"]["0"]
jsonpath.Get($.phoneNumbers..number)
* $["0"]
* $["1"]
* $["2"]["miscellaneous"]["0"]
* $["2"]["miscellaneous"]["0"]["nested"]["0"]
jsonpath.Get($.phoneNumbers[*].number)
* $["0"]
* $["1"]
jsonpath.Get($.others..details.type)
* $["1"]["number"]
* $["0"]["number"]
jsonpath.Get($..number..type)
* $["nested"]["others"]["0"]["details"]
* $["nested"]["others"]["1"]["details"]
* $["others"]["0"]["details"]
* $["others"]["1"]["details"]
Based on these examples (convoluted, I know...but I'm trying to identify edge cases), assuming I could correctly parse the JSONPath, I could reconstruct the actual path for all non-multi-nested expressions. But for multi-nested expressions (Example: $..number..type
), I can't tell which segments belong to the first ..
and which belong to the second ..
.
from jsonpath.
Actually, https://github.com/PaesslerAG/jsonpath/blob/master/jsonpath.go#L7 may have just given me a possibility, but if I understand things, it won't be ideal due to the fact you'd have to evaluate the JSONPath expression N times (where N is the number of wildcards).
from jsonpath.
After a good deal of mucking around, it seems like the context between the JSONPath parsing and the gVal execution is different, so attempting to update parse.go
and placeholder.go
to work in uniform isn't possible from what I can tell. I can get parse.go
to keep track of the path segments it knows of and I can get placeholder.go
to keep track of the wildcard path segments, but tying them together appropriately hasn't worked (yet).
If anyone more knowledgeable on gVal and/or jsonpath can share some ideas, let me know. I'm going to punt for a bit, I've been stuck on this for a few days and I need to make progress elsewhere. @generikvault maybe?
from jsonpath.
Okay, I just found out about gval.NewEvaluableWithContext...gonna give this a shot.
from jsonpath.
Using gval.NewEvaluableWithContext
doesn't seem to yield any success, the disconnect is still there.
from jsonpath.
What if we just created a new API like GetWithPaths
that works like the placeholder hack but it returns a map of full paths to resolved values? I'll look into this, but figuring out the best way to keep track of path segments for nested selectors has been painful thus far.
from jsonpath.
Okay, I will have a PR together that should handle this and it does not use the "placeholder hack". While I would also consider this to be a hack of sorts, it works and instead of hoping to share a common scope to keep track of these automatically, I resort to a much simpler approach. Here is the process:
- At parse time, turn the provided JSONPath into a more sanitized path replacing ambiguous selectors with
*
. (For example,$.phoneNumbers[*].number
would become["phoneNumbers", "*", "number"]
, and$..number
would become["*", "number"]
.) - parse.go was updated with the following:
a.parser
was updated to have asanitizedPath
set at parse time
b..parseRootPath
sets a context variable (computePathsContextKey{}
) totrue
c..parseCurrentPath
sets a context variable (computePathsContextKey{}
) tofalse
d.parser.parse
was updated to return a closure that checks the value of the aforementioned context variable and returns either the raw value (parseCurrentPath
) or a map whose keys are the full JSONPath to the matched value and whose values are the matched value. - jsonpath.go was updated to have a new
GetWithPaths
function that will return a map (key is the quoted JSONPath similar to the placeholder approach, value is the resolved value) (thanks to a helper method that makes it whereGet
andGetWithPaths
work appropriately).
For the example above, here are the new keys (matched values are identical to Get
prior to these changes):
jsonpath.Get($)
$
jsonpath.Get($.phoneNumbers[0].type)
$["phoneNumbers"]["0"]["type"]
jsonpath.Get($.phoneNumbers..nested[0].number)
$["phoneNumbers"]["2"]["miscellaneous"]["0"]["nested"]["0"]["number"]
jsonpath.Get($.phoneNumbers[*])
$["phoneNumbers"]["0"]
$["phoneNumbers"]["1"]
$["phoneNumbers"]["2"]
jsonpath.Get($.phoneNumbers)
$["phoneNumbers"]
jsonpath.Get($..number)
$["nested"]["others"]["1"]["number"]
$["others"]["0"]["number"]
$["others"]["1"]["number"]
$["phoneNumbers"]["0"]["number"]
$["phoneNumbers"]["1"]["number"]
$["phoneNumbers"]["2"]["miscellaneous"]["0"]["number"]
$["phoneNumbers"]["2"]["miscellaneous"]["0"]["nested"]["0"]["number"]
$["nested"]["others"]["0"]["number"]
jsonpath.Get($.phoneNumbers[?(@.type == "home")].number)
$["phoneNumbers"]["1"]["number"]
jsonpath.Get($..phoneNumbers..number)
$["phoneNumbers"]["2"]["miscellaneous"]["0"]["nested"]["0"]["number"]
$["phoneNumbers"]["0"]["number"]
$["phoneNumbers"]["1"]["number"]
$["phoneNumbers"]["2"]["miscellaneous"]["0"]["number"]
jsonpath.Get($.phoneNumbers..number)
$["phoneNumbers"]["0"]["number"]
$["phoneNumbers"]["1"]["number"]
$["phoneNumbers"]["2"]["miscellaneous"]["0"]["number"]
$["phoneNumbers"]["2"]["miscellaneous"]["0"]["nested"]["0"]["number"]
jsonpath.Get($.phoneNumbers[*].number)
$["phoneNumbers"]["0"]["number"]
$["phoneNumbers"]["1"]["number"]
jsonpath.Get($.others..details.type)
$["others"]["0"]["number"]["details"]["type"]
$["others"]["1"]["number"]["details"]["type"]
jsonpath.Get($.others..details["type"])
$["others"]["0"]["number"]["details"]["type"]
$["others"]["1"]["number"]["details"]["type"]
jsonpath.Get($..number..type)
$["others"]["1"]["number"]["details"]["type"]
$["nested"]["others"]["0"]["number"]["details"]["type"]
$["nested"]["others"]["1"]["number"]["details"]["type"]
$["others"]["0"]["number"]["details"]["type"]
from jsonpath.
I ended up with a much simpler approach, although sanitizing the paths returned by ambiguousPath
required a little extra work to figure out. All-in-all, I think PR #44 is in decent shape. Let me know what your thoughts are.
from jsonpath.
Related Issues (20)
- can't deal some strings with numbers and special chars!!!!! HOT 3
- Incorrect return value when querying for array HOT 8
- Error when using multiple array ranges
- Incorrect full path on search - bug HOT 1
- Results do not match other implementations
- Is it possible to find all nodes that have a certain key? HOT 3
- No error with incorrect path and missing field
- JSONPath comparison and standardisation
- error "mixed 63 and 44 in JSON bracket" is not helpful HOT 1
- Honor JSON annotations
- Single quotes are not supported HOT 1
- Support for [(@.length-1)]
- Support for `json.Number`
- undefined: jsonpath.PlaceholderExtension, how to fix it? HOT 1
- Question: How to update JSON at path HOT 1
- Option to allow for Single-Quoted strings HOT 2
- filter with a boolean value doesn't work
- Invalid/undefined keys error out in JSONPath, but not in GVal
- Consider implementing RFC 9535
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jsonpath.