mirror of
https://github.com/gocsaf/csaf.git
synced 2025-12-22 11:55:40 +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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/csaf-poc/csaf_distribution/util"
|
||||
|
|
@ -36,83 +35,28 @@ type AdvisorySummary struct {
|
|||
TLPLabel string
|
||||
}
|
||||
|
||||
type extractFunc func(string) (interface{}, error)
|
||||
|
||||
// NewAdvisorySummary creates a summary from an advisory doc
|
||||
// with the help of an expression evaluator expr.
|
||||
func NewAdvisorySummary(
|
||||
expr *util.PathEval,
|
||||
pe *util.PathEval,
|
||||
doc interface{},
|
||||
) (*AdvisorySummary, error) {
|
||||
|
||||
e := new(AdvisorySummary)
|
||||
|
||||
path := func(s string) (interface{}, error) {
|
||||
return expr.Eval(s, doc)
|
||||
e := &AdvisorySummary{
|
||||
Publisher: new(Publisher),
|
||||
}
|
||||
|
||||
for _, fn := range []func(extractFunc) error{
|
||||
extractText(idExpr, &e.ID),
|
||||
extractText(titleExpr, &e.Title),
|
||||
extractTime(currentReleaseDateExpr, &e.CurrentReleaseDate),
|
||||
extractTime(initialReleaseDateExpr, &e.InitialReleaseDate),
|
||||
extractText(summaryExpr, &e.Summary),
|
||||
extractText(tlpLabelExpr, &e.TLPLabel),
|
||||
e.extractPublisher,
|
||||
} {
|
||||
if err := fn(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := pe.Match([]util.PathEvalMatcher{
|
||||
{Expr: idExpr, Action: util.StringMatcher(&e.ID)},
|
||||
{Expr: titleExpr, Action: util.StringMatcher(&e.Title)},
|
||||
{Expr: currentReleaseDateExpr, Action: util.TimeMatcher(&e.CurrentReleaseDate, time.RFC3339)},
|
||||
{Expr: initialReleaseDateExpr, Action: util.TimeMatcher(&e.InitialReleaseDate, time.RFC3339)},
|
||||
{Expr: summaryExpr, Action: util.StringMatcher(&e.Summary)},
|
||||
{Expr: tlpLabelExpr, Action: util.StringMatcher(&e.TLPLabel)},
|
||||
{Expr: publisherExpr, Action: util.ReMarshalMatcher(e.Publisher)},
|
||||
}, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/PaesslerAG/gval"
|
||||
"github.com/PaesslerAG/jsonpath"
|
||||
|
|
@ -56,3 +57,61 @@ func (pe *PathEval) Eval(expr string, doc interface{}) (interface{}, error) {
|
|||
}
|
||||
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