JsonPath-PHP
JsonPath-PHP copied to clipboard
Returning key of found object
suppose I have
{
"a": {
"v": "va"
},
"b": {
"v": "vb"
}
}
$..[?(@.v=="va")]
returns
[
{
"v":"va"
}
]
how can I get the key of this object which is a
?
https://extendsclass.com/jsonpath-tester.html suports ~
, such that $..[?(@.v=="va")]~
returns
[
"a"
]
How can I do this in JsonPath-PHP?
This is not doable with JsonPath-PHP. I looked around and it does not seem to be part of the spec anywhere other than in the library backing the site you are sharing. If you check the readme it states that it is an addition, not provided in the spec.
Aside from that, feel free to implement it and open a PR with it. We can discuss what it should work like and the edge cases. I tried doing:
-
$.house.room~.length
expecting4
but gotroom
-
$.house.room.~
not only returns the keys of the children but also itself
Overall it seems to be a quirky functionality in the way it is implemented in that library. If we were to include it in JsonPath-PHP I'd expect a better definition (similar to how we included .length
a year ago).
I do not insist in a particular solution, but I do have the problem to get the key of objects in the result set.
Do you have an Idea of a workaround?
The ^and ~ are proposed in https://github.com/JSONPath-Plus/JSONPath.
There is one more thing which confuses me.
php app/test.php "$..*[?(@.price==22.99)]"
works fin in JsonPath-PHP but $..[?(@.price==22.99)]
does not yield a result.
in https://extendsclass.com/jsonpath-tester.html both expressions yield the same results. It appears to m that [] in jsonpath is either a step or a predicate.
Do you have an Idea of a workaround?
I don't think it is possible to do the equivalent of ~
with the current implementation of this library. Implementing it should not be overly complex, though. Honestly, I never thought of this usecase before 😅.
^
operator is also not available, but you can always do a subquery with more than one level. For example, say you want to get all objects that have a price ($..price^
), you can do $..*[?(@.price)]
. For more levels up just add more levels down in the subquery.
..*
vs...
I remember thinking about this one for quite a while when I implemented the library. My conclusion was that ..
should behave as .
but recursive. You can see this in the syntax definition of the language implemented by this library:
childname = '.' (var_name | '*')
recursive = '..' (var_name | '*')
The logic behind this is that in the same way you can't do foo.[1]
in js, you can't do $.foo.[1]
in jsonpath and, because ..
should behave the same, you can't have $..[1]
but you can have $..*[1]
, which is equivalent but different because *
is a valid variable name with special meaning. Following the logic above, you can do $.foo..price
, because foo.price
is valid in js.
thanks for the hint wrt ^
I will try this.
It would be of help if I could get the canonical jsonpath of the result as it is provided in https://jsonpath.com/.
thanks for the explanation about ..
. It sounds reasonable to me, but it is not compatible with other implementations. So one is stuck.
cannonical jsonpath
compatibility with other implementations
As I've said before, I implemented this before there were the number of implementations that exist today. I don't have the time to update this library to match other implementations' features.
Of course, PRs are very welcome 😄
that have a price ($..price^ ), you can do $..*[?(@.price)]. For more levels up just add more levels down in the subquery.
with
{"feldnamen": {
"familienname": {
"sample":"Bitter-Schwalenst\u00f6cker",
"ctabbildung":"dbfeld",
"ctmerkmalsgruppe":"",
"ctdbfeldnam":"name",
"ctfunktion":"ct_getnachname",
"cthinweis":""
}
}}
$..*[?(@.ctabbildung == "dbfeld")]
finds the `familienname``
but $..familienname[?(@.ctabbildung == "dbfeld")]
does not yield a result.
This also happens in https://jsonpath.com/ but I cannot see why.
So in datastructures which uses keys as values (such as familienname
I still cannot find out how to retrieve objects based on the key and properties of this key..
In [?(@.ctabbildung == "dbfeld")]
, @
is the value of each child of $..familienname
.
With $..familienname[?(@.ctabbildung == "dbfeld")]
you are looking for something like $..familienname.*.ctabbildung: "dbfeld"
, but what you want is $..familienname.ctabbildung: "dbfeld"
.
I think the query you are looking for is $..*[?(@.familienname.ctabbildung == "dbfeld")].familienname
.
hi @bwl21,
Let me know if my last message solved your question.
Regarding the ~
operator, I don't have the time right now to implement it. If you have the time, feel free to open a PR for it.
Cheers!
@Galbar thanks for asking, I did not answer yet since I am still trying around but did not get the full understanding.
Nevertheless. What I want is the keys of all objects which have a property ctabbildung
with the value of dbfeld
. For exsamle familienname
.
so I tried $..*[?(@.*.ctabbildung == "dbfeld")]
and then read the array_keys of the result but still was not successful.
Hi @bwl21 I don't think there is a way to get the keys using this JSONPath implementation. I think the solution for this would be to add the ~
operation to this implementation.
I have an idea on how to implement the ~
operator but I don't have the time right now. I'm sorry.
The idea would be to duplicate the access operators (.<child_name>
, [...]
, ..*
, etc.) and add a ~
at the end of the regexes and duplicate functions to return the keys instead of the values in the array.
I am not sure if that is relevant to this issue but may be someone will find it useful:
#59