...

Source file src/github.com/PaesslerAG/jsonpath/parse.go

Documentation: github.com/PaesslerAG/jsonpath

     1  package jsonpath
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"text/scanner"
     8  
     9  	"github.com/PaesslerAG/gval"
    10  )
    11  
    12  type parser struct {
    13  	*gval.Parser
    14  	path path
    15  }
    16  
    17  func parseRootPath(ctx context.Context, gParser *gval.Parser) (r gval.Evaluable, err error) {
    18  	p := newParser(gParser)
    19  	return p.parse(ctx)
    20  }
    21  
    22  func parseCurrentPath(ctx context.Context, gParser *gval.Parser) (r gval.Evaluable, err error) {
    23  	p := newParser(gParser)
    24  	p.appendPlainSelector(currentElementSelector())
    25  	return p.parse(ctx)
    26  }
    27  
    28  func newParser(p *gval.Parser) *parser {
    29  	return &parser{Parser: p, path: plainPath{}}
    30  }
    31  
    32  func (p *parser) parse(c context.Context) (r gval.Evaluable, err error) {
    33  	err = p.parsePath(c)
    34  
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return p.path.evaluate, nil
    39  }
    40  
    41  func (p *parser) parsePath(c context.Context) error {
    42  	switch p.Scan() {
    43  	case '.':
    44  		return p.parseSelect(c)
    45  	case '[':
    46  		keys, seperator, err := p.parseBracket(c)
    47  
    48  		if err != nil {
    49  			return err
    50  		}
    51  
    52  		switch seperator {
    53  		case ':':
    54  			if len(keys) > 3 {
    55  				return fmt.Errorf("range query has at least the parameter [min:max:step]")
    56  			}
    57  			keys = append(keys, []gval.Evaluable{
    58  				p.Const(0), p.Const(float64(math.MaxInt32)), p.Const(1)}[len(keys):]...)
    59  			p.appendAmbiguousSelector(rangeSelector(keys[0], keys[1], keys[2]))
    60  		case '?':
    61  			if len(keys) != 1 {
    62  				return fmt.Errorf("filter needs exactly one key")
    63  			}
    64  			p.appendAmbiguousSelector(filterSelector(keys[0]))
    65  		default:
    66  			if len(keys) == 1 {
    67  				p.appendPlainSelector(directSelector(keys[0]))
    68  			} else {
    69  				p.appendAmbiguousSelector(multiSelector(keys))
    70  			}
    71  		}
    72  		return p.parsePath(c)
    73  	case '(':
    74  		return p.parseScript(c)
    75  	default:
    76  		p.Camouflage("jsonpath", '.', '[', '(')
    77  		return nil
    78  	}
    79  }
    80  
    81  func (p *parser) parseSelect(c context.Context) error {
    82  	scan := p.Scan()
    83  	switch scan {
    84  	case scanner.Ident:
    85  		p.appendPlainSelector(directSelector(p.Const(p.TokenText())))
    86  		return p.parsePath(c)
    87  	case '.':
    88  		p.appendAmbiguousSelector(mapperSelector())
    89  		return p.parseMapper(c)
    90  	case '*':
    91  		p.appendAmbiguousSelector(starSelector())
    92  		return p.parsePath(c)
    93  	default:
    94  		return p.Expected("JSON select", scanner.Ident, '.', '*')
    95  	}
    96  }
    97  
    98  func (p *parser) parseBracket(c context.Context) (keys []gval.Evaluable, seperator rune, err error) {
    99  	for {
   100  		scan := p.Scan()
   101  		skipScan := false
   102  		switch scan {
   103  		case '?':
   104  			skipScan = true
   105  		case ':':
   106  			i := float64(0)
   107  			if len(keys) == 1 {
   108  				i = math.MaxInt32
   109  			}
   110  			keys = append(keys, p.Const(i))
   111  			skipScan = true
   112  		case '*':
   113  			if p.Scan() != ']' {
   114  				return nil, 0, p.Expected("JSON bracket star", ']')
   115  			}
   116  			return []gval.Evaluable{}, 0, nil
   117  		case ']':
   118  			if seperator == ':' {
   119  				skipScan = true
   120  				break
   121  			}
   122  			fallthrough
   123  		default:
   124  			p.Camouflage("jsonpath brackets")
   125  			key, err := p.ParseExpression(c)
   126  			if err != nil {
   127  				return nil, 0, err
   128  			}
   129  			keys = append(keys, key)
   130  		}
   131  		if !skipScan {
   132  			scan = p.Scan()
   133  		}
   134  		if seperator == 0 {
   135  			seperator = scan
   136  		}
   137  		switch scan {
   138  		case ':', ',':
   139  		case ']':
   140  			return
   141  		case '?':
   142  			if len(keys) != 0 {
   143  				return nil, 0, p.Expected("JSON filter", ']')
   144  			}
   145  		default:
   146  			return nil, 0, p.Expected("JSON bracket separator", ':', ',')
   147  		}
   148  		if seperator != scan {
   149  			return nil, 0, fmt.Errorf("mixed %v and %v in JSON bracket", seperator, scan)
   150  		}
   151  	}
   152  }
   153  
   154  func (p *parser) parseMapper(c context.Context) error {
   155  	scan := p.Scan()
   156  	switch scan {
   157  	case scanner.Ident:
   158  		p.appendPlainSelector(directSelector(p.Const(p.TokenText())))
   159  	case '[':
   160  		keys, seperator, err := p.parseBracket(c)
   161  
   162  		if err != nil {
   163  			return err
   164  		}
   165  		switch seperator {
   166  		case ':':
   167  			return fmt.Errorf("mapper can not be combined with range query")
   168  		case '?':
   169  			if len(keys) != 1 {
   170  				return fmt.Errorf("filter needs exactly one key")
   171  			}
   172  			p.appendAmbiguousSelector(filterSelector(keys[0]))
   173  		default:
   174  			p.appendAmbiguousSelector(multiSelector(keys))
   175  		}
   176  	case '*':
   177  		p.appendAmbiguousSelector(starSelector())
   178  	case '(':
   179  		return p.parseScript(c)
   180  	default:
   181  		return p.Expected("JSON mapper", '[', scanner.Ident, '*')
   182  	}
   183  	return p.parsePath(c)
   184  }
   185  
   186  func (p *parser) parseScript(c context.Context) error {
   187  	script, err := p.ParseExpression(c)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	if p.Scan() != ')' {
   192  		return p.Expected("jsnopath script", ')')
   193  	}
   194  	p.appendPlainSelector(newScript(script))
   195  	return p.parsePath(c)
   196  }
   197  
   198  func (p *parser) appendPlainSelector(next plainSelector) {
   199  	p.path = p.path.withPlainSelector(next)
   200  }
   201  
   202  func (p *parser) appendAmbiguousSelector(next ambiguousSelector) {
   203  	p.path = p.path.withAmbiguousSelector(next)
   204  }
   205  

View as plain text