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

ERROR : Error(4, 76): syntax, near '$'. in C# when i Parse the expression #36

Closed
ImAbhishekTomar opened this issue Feb 16, 2022 · 9 comments

Comments

@ImAbhishekTomar
Copy link

Hi,

My expression is working fine with the online editor but when I used the same expression with the same data in c# it's giving me the below error.

  • Version : JmesPath.Net - 1.0.153
  • Framwork - Dot net core
  • Language - C#

ERROR

Error(4, 76): syntax, near '$'.
at DevLab.JmesPath.JmesPathScanner.yyerror(String format, Object[] args)
at DevLab.JmesPath.JmesPathScanner.Scan()
at DevLab.JmesPath.JmesPathScanner.yylex()
at StarodubOleg.GPPG.Runtime.ShiftReduceParser`2.Parse()
at DevLab.JmesPath.Parser.Parse(Stream stream, Encoding encoding, IJmesPathGenerator generator)
at DevLab.JmesPath.JmesPath.Parse(Stream stream)
at DevLab.JmesPath.JmesPath.Parse(String expression)
at AzureFunctionDurableTic.AzureFunctionTIC.d__16.MoveNext() in /Users/atomar10/Projects/AzureFunctionDurableTic/AzureFunctionDurableTic/AzureFunctionTIC.cs:line 203

CODE

            var q2 = @"
                            in_network[].{
                                                      unique_id:join('_',[negotiation_arrangement,name,billing_code_type,billing_code_type_version,billing_code,description,negotiated_rates[].tin | [0],negotiated_rates[].negotiated_price.expiration_date | [0],negotiated_rates[].negotiated_price.negotiated_type | [0]]),                 
                                                      reporting_entity_name:$.reporting_entity_name,
                                                      name:name,                   
                                                      billing_code:billing_code,                   
                                                      billing_code_type:billing_code_type,
                                                      billing_code_type_version:billing_code_type_version,                   
                                                      description:description,                   
                                                      negotiation_arrangement:negotiation_arrangement,    
                                                                     negotiated_rates:negotiated_rates[*].{
                                                                        providers:providers,
                                                                        tin:tin,
                                                                        service_code:service_code,
                                                                        expiration_date:negotiated_price.expiration_date,
                                                                        negotiated_rate:negotiated_price.negotiated_rate,
                                                                        negotiated_type:negotiated_price.negotiated_type
                                                                    }                 
                                                }";

            return q2;

  var jmes = new JmesPath();
  var exp = jmes.Parse(expression).Transform(data);
@jdevillard
Copy link
Owner

Hello,

thanks for opening this issue, I would like to reproduce the issue.
I understand that q2 seem to be the "transform expression" and it seems to be an parsing issue with some special characters.

Could you provide a sample input? or does it have sensitive information?
I would like to be sure what you meant using the "$" on your input.

@ImAbhishekTomar
Copy link
Author

ImAbhishekTomar commented Feb 16, 2022

@jdevillard Sample JSON data. I am validating my query with this editor https://api.gopipeline.io/jmespath-tester

{
  "reporting_entity_name": "***********",
  "reporting_entity_type": "***********",
  "plan_name": "***********",
  "plan_id_type":  "***********",
  "plan_id": 1111,
  "plan_market_type":  "***********",
  "last_updated_on": "2021-08-30",
   "in_network" : [
        {
            "negotiation_arrangement" : "***********",
            "name" : "***********",
            "billing_code_type" : "***********",
            "billing_code_type_version" : "201",
            "billing_code" : "***********",
            "description" : "***********",
            "negotiated_rates" : [ {
            "providers" : [ 11111111,22222222,4444444,666666,777777,1111 ],
            "tin" : "***********",
            "service_code" : "***********-***********",
            "negotiated_price" : {
                "negotiated_type" : "***********",
                "negotiated_rate" : 10.000,
                "expiration_date" : "9999-12-31"
            }
            }]
        },
          {
            "negotiation_arrangement": "***********",
            "name": "***********",
            "billing_code_type": "***********",
            "billing_code_type_version": "201",
            "billing_code": "***********",
            "description": "***********",
            "negotiated_rates": [
              {
                "providers": [2342432, 234234, 243234, 234234, 24324, 424324234],
                "tin": "023432324324",
                "service_code": "***********-***********",
                "negotiated_price": {
                  "negotiated_type": "***********",
                  "negotiated_rate": 10.0,
                  "expiration_date": "9999-12-31"
                }
              }
            ]
          }
    ]
}

@jdevillard
Copy link
Owner

Thanks for this info and for providing the link to the tester.

The online tester you mention use the library available at https://www.npmjs.com/package/@metrichor/jmespath

This library provide some extension for the initial spec like this one :

Root value access with $ symbol

search({foo: {bar: 999}, baz: [1, 2, 3]}, '$.baz[*].[@, $.foo.bar]')

// OUTPUTS:
// [ [ 1, 999 ], [ 2, 999 ], [ 3, 999 ] ]

However, it could be a good idea to include this extensions in the .Net Specification.
We're currently checking with the team how specification could be extended and re-integrated in the initial spec to be sure that every language follow the same spec.

Thanks a lot.

@ImAbhishekTomar
Copy link
Author

ImAbhishekTomar commented Feb 16, 2022

Does this package available for dot net core? https://www.npmjs.com/package/@metrichor/jmespath or there is any workaround to access Root value?

Screenshot 2022-02-16 at 11 08 01 PM

@jdevillard
Copy link
Owner

Does this package available for dot net core? https://www.npmjs.com/package/@metrichor/jmespath or there is any workaround to access Root value?

Screenshot 2022-02-16 at 11 08 01 PM

no it's specific to javascript implementation.

We will see how to implement this as well on the dotnet version

@glenveegee
Copy link

Hey folks, The $ symbol is definitely not standard JMESPath spec but there are a number of JMESPath libraries developed in the community that have extended the spec to include it because it's easy to implement and really useful. Another low hanging fruit that many folks implement (and you might consider) is a means to define custom functions.

@springcomp
Copy link
Collaborator

springcomp commented Feb 17, 2022

@glenveegee Thanks for the feedback.

JmesPath.Net does support custom functions. The parser includes a hook to register custom functions. Builtin functions are actually registered using this mechanism on startup.
Please, look at this repository for samples.

We plan to draft a JEP to submit a proposal that the official specification implements the $ symbol.

@springcomp
Copy link
Collaborator

springcomp commented Feb 26, 2022

We are discussing whether to support the $ keyword.
However it seems it would be better served by extending the let() function from the Lexical Scoping proposal by supporting expressions like:

let({root: @}, &...)

@springcomp
Copy link
Collaborator

@ImAbhishekTomar A new version of JMESPath.NET has been released.

It includes an implementation of the let() function that lets you capture any lexical scope you need for later use.

This may help you work around the non-standard $ symbol.

You will need to register the let() function:

var parser = new JmesPath();
parser.FunctionRepository
    .Register<ItemsFunction>()
    .Register<ToObjectFunction>()
    .Register<ZipFunction>()
    .Register<LetFunction>()
    ;

The example you refer to can be written like so:

search( let({dollar: @}, &baz[*].[@, dollar.foo.bar]), {"foo": {"bar": 999}, "baz": [1, 2, 3]})
    -> [[1,999],[2,999],[3,999]]

Or, in C#

var document = "{\"foo\": {\"bar\": 999}, \"baz\": [1, 2, 3]}";
var expression = "let({dollar: @}, &baz[*].[@, dollar.foo.bar])";

var result = parser.Transform(document, expression);

Console.WriteLine(result);

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

No branches or pull requests

4 participants