ohler55 / ojg

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

'' is not a valid operation at 16 in $..book[?@.isbn] #147

Closed fkarakas closed 10 months ago

fkarakas commented 10 months ago

Hello, Great work on this lib. Currently evaluating it. From the jsonpath specification i grabbed a query from the examples that i found interesting, and i got an error

x, err := jp.ParseString("$..book[?@.isbn]")

failed as follow

'' is not a valid operation at 16 in $..book[?@.isbn]

Did i miss something because you mentionned that you fully support jsonpath specs.

Regards

PS: specs example queries

+========================+=======================================+
| JSONPath               | Intended result                       |
+========================+=======================================+
| $.store.book[*].author | the authors of all books in the store |
+------------------------+---------------------------------------+
| $..author              | all authors                           |
+------------------------+---------------------------------------+
| $.store.*              | all things in store, which are some   |
|                        | books and a red bicycle               |
+------------------------+---------------------------------------+
| $.store..price         | the prices of everything in the store |
+------------------------+---------------------------------------+
| $..book[2]             | the third book                        |
+------------------------+---------------------------------------+
| $..book[2].author      | the third book's author               |
+------------------------+---------------------------------------+
| $..book[2].publisher   | empty result: the third book does not |
|                        | have a "publisher" member             |
+------------------------+---------------------------------------+
| $..book[-1]            | the last book in order                |
+------------------------+---------------------------------------+
| $..book[0,1]           | the first two books                   |
| $..book[:2]            |                                       |
+------------------------+---------------------------------------+
| $..book[?@.isbn]       | all books with an ISBN number         |
+------------------------+---------------------------------------+
| $..book[?@.price<10]   | all books cheaper than 10             |
+------------------------+---------------------------------------+
| $..*                   | all member values and array elements  |
|                        | contained in the input value          |
+------------------------+---------------------------------------+
ohler55 commented 10 months ago

Looks like a bug. I'll try to fix it this weekend.

You didn't miss anything. The intent is indeed to fully support the JSONPath draft specification. That doesn't mean there aren't bugs.

ohler55 commented 10 months ago

Please try the "jp-exists-bug" branch.

fkarakas commented 10 months ago

I have tried and it is working, great work 👍

My first plan was to use your lib with a special kind of json called jsonld (https://json-ld.org/) used by google. It is a regular json but with some field starting with @ character. Here is an example:

  {
    "@context": "http://schema.org",
    "@type": "DataFeed",
    "dateModified": "2023-10-25T12:05:01Z",
    "dataFeedElement": [
      {
        "@context": [
          "http://schema.org",
          {
            "@language": "fr"
          }
        ],
        "@type": "TVEpisode",
        "@id": "https://tv.com",
        "url": "https://tv.com/video1",
        "name": "video 1",
        "image": {
          "@context": "http://schema.org",
          "@type": "ImageObject",
          "contentUrl": "https://tv.com/video1",
          "additionalProperty": [
            {
              "@type": "PropertyValue",
              "name": "contentAttributes",
              "value": [
                "iconic",
                "poster",
                "smallFormat",
                "largeFormat"
              ]
            }
          ]
        },
        "episodeNumber": 10000,
        "partOfSeason": {
          "@type": "TVSeason",
          "@id": "https://tv.com/season1",
          "url": "https://tv.com/season1",
          "seasonNumber": 1
        },
        "partOfSeries": {
          "@type": "TVSeries",
          "@id": "https://tv.com/series1",
          "url": "https://tv.com/series1",
          "name": "Quotidien"
        },
        "potentialAction": [
          {
            "@type": "WatchAction",
            "target": {
              "@type": "EntryPoint",
              "urlTemplate": "https://tv.com/series1",
              "inLanguage": "fr",
              "actionPlatform": [
                "http://schema.org/AndroidPlatform",
                "http://schema.org/DesktopWebPlatform",
                "http://schema.org/IOSPlatform",
                "http://schema.org/MobileWebPlatform"
              ]
            },
            "actionAccessibilityRequirement": {
              "@type": "ActionAccessSpecification",
              "category": "free",
              "availabilityStarts": "2017-01-16T18:40:00Z",
              "availabilityEnds": "2029-12-31T20:00:00Z",
              "eligibleRegion": [
                {
                  "@type": "Country",
                  "name": "US"
                }
              ]
            }
          },
          {
            "@type": "WatchAction",
            "target": {
              "@type": "EntryPoint",
              "urlTemplate": "https://tv.com/video1",
              "inLanguage": "fr",
              "actionPlatform": [
                "http://schema.org/AndroidTVPlatform"
              ]
            },
            "actionAccessibilityRequirement": {
              "@type": "ActionAccessSpecification",
              "category": "free",
              "availabilityStarts": "2017-01-16T18:40:00Z",
              "availabilityEnds": "2029-12-31T20:00:00Z",
              "eligibleRegion": [
                {
                  "@type": "Country",
                  "name": "FR"
                }
              ]
            }
          }
        ]
      }
    ]
  }

So i think it is a regular json file but with "special" field name.

when i try to query something like :

x, err := jp.ParseString("$..dataFeedElement[?(@.@type=='TVEpisode')]")

i got the error: an expression fragment can not start with a '@' at 25 in $..dataFeedElement[?(@.@type=='TVEpisode')]

I can understand that your lib cannot handle this and to be honest i don't know if the jsonpath specification anticipated this kind of use cases. Because jsonld is for me a valid json....

So tell me what you thing about it.

ohler55 commented 10 months ago

A little background first. The notation of @.type is shorthand for a path comprised of '@' and 'type'. The alternate or maybe the primary notation is bracket notation so instead of @.@type which uses a special character in the second token the bracket notation can be used and the path would look like @['@type'].

I added a test in script_test.go:64 as an example.

fkarakas commented 10 months ago

i have tried

x, err := jp.ParseString("(@['@type'] == 'TVEpisode')")

and got

parse error at 1 in (@['@type'] == 'TVEpisode')

i want to get all element of the array where the field @type is equal to 'TVEpisode' (there is other type of content in the array). Sorry if i do something wrong, a little newbie in jsonpath :)

ohler55 commented 10 months ago

Hmm, should work. I'll get it fixed. Maybe tomorrow.

ohler55 commented 10 months ago

After looking at the string being parsed, it is not a JSONPath string. If the intent was to format a filter or script then @[?@['@type'] == 'TVEpisode'] would be more appropriate.

Added a test to parse_test.go:35.

fkarakas commented 10 months ago

Thank you, the following filter works as you said:

x, err := jp.ParseString("$.dataFeedElement[?(@['@type'] == 'TVEpisode')]")

We can close this issue. Thanks

ohler55 commented 10 months ago

Great. I'll release tonight and close after that.