mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 05:40:11 +01:00
Impove Jsonpath matcher
* Simplifed mass jsonpath extractions json document
This commit is contained in:
parent
de4f50787d
commit
41e4029b0d
2 changed files with 72 additions and 69 deletions
|
|
@ -9,7 +9,6 @@
|
||||||
package csaf
|
package csaf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/csaf-poc/csaf_distribution/util"
|
"github.com/csaf-poc/csaf_distribution/util"
|
||||||
|
|
@ -36,83 +35,28 @@ type AdvisorySummary struct {
|
||||||
TLPLabel string
|
TLPLabel string
|
||||||
}
|
}
|
||||||
|
|
||||||
type extractFunc func(string) (interface{}, error)
|
|
||||||
|
|
||||||
// NewAdvisorySummary creates a summary from an advisory doc
|
// NewAdvisorySummary creates a summary from an advisory doc
|
||||||
// with the help of an expression evaluator expr.
|
// with the help of an expression evaluator expr.
|
||||||
func NewAdvisorySummary(
|
func NewAdvisorySummary(
|
||||||
expr *util.PathEval,
|
pe *util.PathEval,
|
||||||
doc interface{},
|
doc interface{},
|
||||||
) (*AdvisorySummary, error) {
|
) (*AdvisorySummary, error) {
|
||||||
|
|
||||||
e := new(AdvisorySummary)
|
e := &AdvisorySummary{
|
||||||
|
Publisher: new(Publisher),
|
||||||
path := func(s string) (interface{}, error) {
|
|
||||||
return expr.Eval(s, doc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fn := range []func(extractFunc) error{
|
if err := pe.Match([]util.PathEvalMatcher{
|
||||||
extractText(idExpr, &e.ID),
|
{Expr: idExpr, Action: util.StringMatcher(&e.ID)},
|
||||||
extractText(titleExpr, &e.Title),
|
{Expr: titleExpr, Action: util.StringMatcher(&e.Title)},
|
||||||
extractTime(currentReleaseDateExpr, &e.CurrentReleaseDate),
|
{Expr: currentReleaseDateExpr, Action: util.TimeMatcher(&e.CurrentReleaseDate, time.RFC3339)},
|
||||||
extractTime(initialReleaseDateExpr, &e.InitialReleaseDate),
|
{Expr: initialReleaseDateExpr, Action: util.TimeMatcher(&e.InitialReleaseDate, time.RFC3339)},
|
||||||
extractText(summaryExpr, &e.Summary),
|
{Expr: summaryExpr, Action: util.StringMatcher(&e.Summary)},
|
||||||
extractText(tlpLabelExpr, &e.TLPLabel),
|
{Expr: tlpLabelExpr, Action: util.StringMatcher(&e.TLPLabel)},
|
||||||
e.extractPublisher,
|
{Expr: publisherExpr, Action: util.ReMarshalMatcher(e.Publisher)},
|
||||||
} {
|
}, doc); err != nil {
|
||||||
if err := fn(path); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractText(expr string, store *string) func(extractFunc) error {
|
|
||||||
|
|
||||||
return func(path extractFunc) error {
|
|
||||||
s, err := path(expr)
|
|
||||||
if text, ok := s.(string); ok && err == nil {
|
|
||||||
*store = text
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractTime(expr string, store *time.Time) func(extractFunc) error {
|
|
||||||
|
|
||||||
return func(path extractFunc) error {
|
|
||||||
s, err := path(expr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
text, ok := s.(string)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not a string")
|
|
||||||
}
|
|
||||||
date, err := time.Parse(time.RFC3339, text)
|
|
||||||
if err == nil {
|
|
||||||
*store = date.UTC()
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *AdvisorySummary) extractPublisher(path extractFunc) error {
|
|
||||||
p, err := path(publisherExpr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: It's a bit cumbersome to serialize and deserialize
|
|
||||||
// it into our own structure.
|
|
||||||
publisher := new(Publisher)
|
|
||||||
if err := util.ReMarshalJSON(publisher, p); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := publisher.Validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
e.Publisher = publisher
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
59
util/json.go
59
util/json.go
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/PaesslerAG/gval"
|
"github.com/PaesslerAG/gval"
|
||||||
"github.com/PaesslerAG/jsonpath"
|
"github.com/PaesslerAG/jsonpath"
|
||||||
|
|
@ -56,3 +57,61 @@ func (pe *PathEval) Eval(expr string, doc interface{}) (interface{}, error) {
|
||||||
}
|
}
|
||||||
return eval(context.Background(), doc)
|
return eval(context.Background(), doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PathEvalMatcher is a pair of an expression and an action
|
||||||
|
// when doing extractions via PathEval.Match.
|
||||||
|
type PathEvalMatcher struct {
|
||||||
|
// Expr is the expression to evaluate
|
||||||
|
Expr string
|
||||||
|
// Action is executed with the result of the match.
|
||||||
|
Action func(interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReMarshalMatcher is an action to re-marshal the result to another type.
|
||||||
|
func ReMarshalMatcher(dst interface{}) func(interface{}) error {
|
||||||
|
return func(src interface{}) error {
|
||||||
|
return ReMarshalJSON(dst, src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringMatcher stores the matched result in a string.
|
||||||
|
func StringMatcher(dst *string) func(interface{}) error {
|
||||||
|
return func(x interface{}) error {
|
||||||
|
s, ok := x.(string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not a string")
|
||||||
|
}
|
||||||
|
*dst = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeMatcher stores a time with a given format.
|
||||||
|
func TimeMatcher(dst *time.Time, format string) func(interface{}) error {
|
||||||
|
return func(x interface{}) error {
|
||||||
|
s, ok := x.(string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not a string")
|
||||||
|
}
|
||||||
|
t, err := time.Parse(format, s)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
*dst = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match matches a list of PathEvalMatcher pairs against a document.
|
||||||
|
func (pe *PathEval) Match(matcher []PathEvalMatcher, doc interface{}) error {
|
||||||
|
for _, m := range matcher {
|
||||||
|
x, err := pe.Eval(m.Expr, doc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := m.Action(x); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue