Skip to content

Commit 4ef342c

Browse files
committed
Start implementing CSV parser
1 parent 3ac9c8b commit 4ef342c

File tree

8 files changed

+310
-44
lines changed

8 files changed

+310
-44
lines changed

cmd/dasel/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
_ "github.com/tomwright/dasel/v3/parsing/d"
99
_ "github.com/tomwright/dasel/v3/parsing/json"
1010
_ "github.com/tomwright/dasel/v3/parsing/toml"
11+
_ "github.com/tomwright/dasel/v3/parsing/xml"
1112
_ "github.com/tomwright/dasel/v3/parsing/yaml"
1213
)
1314

execution/execute_binary.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,17 @@ func binaryExprExecutor(opts *Options, e ast.BinaryExpr) (expressionExecutor, er
6565
case lexer.Equals:
6666
doOperation = func(a *model.Value, b *model.Value) (*model.Value, error) {
6767
err := a.Set(b)
68-
return b, err
68+
if err != nil {
69+
return nil, fmt.Errorf("error setting value: %w", err)
70+
}
71+
switch a.Type() {
72+
case model.TypeMap:
73+
return a, nil
74+
case model.TypeSlice:
75+
return a, nil
76+
default:
77+
return b, nil
78+
}
6979
}
7080
case lexer.And:
7181
doOperation = func(a *model.Value, b *model.Value) (*model.Value, error) {

execution/execute_branch.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,37 @@ import (
1010
func branchExprExecutor(opts *Options, e ast.BranchExpr) (expressionExecutor, error) {
1111
return func(data *model.Value) (*model.Value, error) {
1212
res := model.NewSliceValue()
13+
res.MarkAsBranch()
1314

14-
for _, expr := range e.Exprs {
15-
r, err := ExecuteAST(expr, data, opts)
16-
if err != nil {
17-
return nil, fmt.Errorf("failed to execute branch expr: %w", err)
15+
if len(e.Exprs) == 0 {
16+
if err := data.RangeSlice(func(_ int, value *model.Value) error {
17+
if err := res.Append(value); err != nil {
18+
return fmt.Errorf("failed to append branch result: %w", err)
19+
}
20+
return nil
21+
}); err != nil {
22+
return nil, fmt.Errorf("failed to range slice: %w", err)
1823
}
24+
} else {
25+
for _, expr := range e.Exprs {
26+
r, err := ExecuteAST(expr, data, opts)
27+
if err != nil {
28+
return nil, fmt.Errorf("failed to execute branch expr: %w", err)
29+
}
1930

20-
// This deals with the spread operator in the branch expression.
21-
valsToAppend, err := prepareSpreadValues(r)
22-
if err != nil {
23-
return nil, fmt.Errorf("error handling spread values: %w", err)
24-
}
25-
for _, v := range valsToAppend {
26-
if err := res.Append(v); err != nil {
27-
return nil, fmt.Errorf("failed to append branch result: %w", err)
31+
// This deals with the spread operator in the branch expression.
32+
valsToAppend, err := prepareSpreadValues(r)
33+
if err != nil {
34+
return nil, fmt.Errorf("error handling spread values: %w", err)
35+
}
36+
for _, v := range valsToAppend {
37+
if err := res.Append(v); err != nil {
38+
return nil, fmt.Errorf("failed to append branch result: %w", err)
39+
}
2840
}
2941
}
3042
}
3143

32-
res.MarkAsBranch()
33-
3444
return res, nil
3545
}, nil
3646
}

internal/cli/query.go

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package cli
22

33
import (
44
"fmt"
5-
"github.com/tomwright/dasel/v3"
65
"io"
76

87
"github.com/tomwright/dasel/v3/execution"
@@ -71,38 +70,24 @@ func (c *QueryCmd) Run(ctx *Globals) error {
7170

7271
opts = append(opts, execution.WithVariable("root", inputData))
7372

74-
out, num, err := dasel.Query(inputData, c.Query, opts...)
73+
options := execution.NewOptions(opts...)
74+
out, err := execution.ExecuteSelector(c.Query, inputData, options)
7575
if err != nil {
7676
return err
7777
}
7878

7979
if c.ReturnRoot {
80-
outputBytes, err := writer.Write(inputData)
81-
if err != nil {
82-
return fmt.Errorf("error writing output: %w", err)
83-
}
84-
85-
_, err = ctx.Stdout.Write(outputBytes)
86-
if err != nil {
87-
return fmt.Errorf("error writing output: %w", err)
88-
}
89-
return nil
80+
out = inputData
9081
}
9182

92-
if num == 0 {
93-
return nil
83+
outputBytes, err := writer.Write(out)
84+
if err != nil {
85+
return fmt.Errorf("error writing output: %w", err)
9486
}
9587

96-
for _, o := range out {
97-
outputBytes, err := writer.Write(o)
98-
if err != nil {
99-
return fmt.Errorf("error writing output: %w", err)
100-
}
101-
102-
_, err = ctx.Stdout.Write(outputBytes)
103-
if err != nil {
104-
return fmt.Errorf("error writing output: %w", err)
105-
}
88+
_, err = ctx.Stdout.Write(outputBytes)
89+
if err != nil {
90+
return fmt.Errorf("error writing output: %w", err)
10691
}
10792

10893
return nil

model/value.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ type KeyValue struct {
3232
// Values represents a list of values.
3333
type Values []*Value
3434

35+
func (v Values) ToSliceValue() (*Value, error) {
36+
slice := NewSliceValue()
37+
for _, val := range v {
38+
if err := slice.Append(val); err != nil {
39+
return nil, err
40+
}
41+
}
42+
return slice, nil
43+
}
44+
3545
// Value represents a value.
3646
type Value struct {
3747
Value reflect.Value

parsing/json/json.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,28 @@ func (j *jsonWriter) Write(value *model.Value) ([]byte, error) {
220220
return err
221221
}
222222

223-
if err := j.write(buf, encoderFn, es, value); err != nil {
224-
return nil, err
225-
}
223+
if value.IsBranch() {
224+
if err := value.RangeSlice(func(i int, v *model.Value) error {
225+
if err := j.write(buf, encoderFn, es, v); err != nil {
226+
return err
227+
}
226228

227-
if _, err := buf.Write([]byte("\n")); err != nil {
228-
return nil, err
229+
if _, err := buf.Write([]byte("\n")); err != nil {
230+
return err
231+
}
232+
233+
return nil
234+
}); err != nil {
235+
return nil, err
236+
}
237+
} else {
238+
if err := j.write(buf, encoderFn, es, value); err != nil {
239+
return nil, err
240+
}
241+
242+
if _, err := buf.Write([]byte("\n")); err != nil {
243+
return nil, err
244+
}
229245
}
230246

231247
return buf.Bytes(), nil

parsing/xml/xml.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package xml
2+
3+
import (
4+
"bytes"
5+
"encoding/xml"
6+
"errors"
7+
"fmt"
8+
"io"
9+
"unicode"
10+
11+
"github.com/tomwright/dasel/v3/model"
12+
"github.com/tomwright/dasel/v3/parsing"
13+
)
14+
15+
const (
16+
// XML represents the XML file format.
17+
XML parsing.Format = "xml"
18+
)
19+
20+
var _ parsing.Reader = (*xmlReader)(nil)
21+
var _ parsing.Writer = (*xmlWriter)(nil)
22+
23+
//var _ parsing.Writer = (*xmlWriter)(nil)
24+
25+
func init() {
26+
parsing.RegisterReader(XML, newXMLReader)
27+
parsing.RegisterWriter(XML, newXMLWriter)
28+
}
29+
30+
func newXMLReader() (parsing.Reader, error) {
31+
return &xmlReader{}, nil
32+
}
33+
34+
// NewXMLWriter creates a new XML writer.
35+
func newXMLWriter(options parsing.WriterOptions) (parsing.Writer, error) {
36+
return &xmlWriter{
37+
options: options,
38+
}, nil
39+
}
40+
41+
type xmlReader struct{}
42+
43+
// Read reads a value from a byte slice.
44+
func (j *xmlReader) Read(data []byte) (*model.Value, error) {
45+
decoder := xml.NewDecoder(bytes.NewReader(data))
46+
decoder.Strict = true
47+
48+
el, err := j.parseElement(decoder, xml.StartElement{
49+
Name: xml.Name{
50+
Local: "root",
51+
},
52+
})
53+
if err != nil {
54+
return nil, err
55+
}
56+
57+
return el.toModel()
58+
}
59+
60+
type xmlAttr struct {
61+
Name string
62+
Value string
63+
}
64+
65+
type xmlElement struct {
66+
Name string
67+
Attrs []xmlAttr
68+
Children []*xmlElement
69+
Content string
70+
}
71+
72+
func (e *xmlElement) toModel() (*model.Value, error) {
73+
attrs := model.NewMapValue()
74+
for _, attr := range e.Attrs {
75+
if err := attrs.SetMapKey(attr.Name, model.NewStringValue(attr.Value)); err != nil {
76+
return nil, err
77+
}
78+
}
79+
res := model.NewMapValue()
80+
if err := res.SetMapKey("name", model.NewStringValue(e.Name)); err != nil {
81+
return nil, err
82+
}
83+
if err := res.SetMapKey("attrs", attrs); err != nil {
84+
return nil, err
85+
}
86+
87+
if err := res.SetMapKey("content", model.NewStringValue(e.Content)); err != nil {
88+
return nil, err
89+
}
90+
children := model.NewSliceValue()
91+
for _, child := range e.Children {
92+
childModel, err := child.toModel()
93+
if err != nil {
94+
return nil, err
95+
}
96+
if err := children.Append(childModel); err != nil {
97+
return nil, err
98+
}
99+
}
100+
if err := res.SetMapKey("children", children); err != nil {
101+
return nil, err
102+
}
103+
return res, nil
104+
}
105+
106+
func (j *xmlReader) parseElement(decoder *xml.Decoder, element xml.StartElement) (*xmlElement, error) {
107+
el := &xmlElement{
108+
Name: element.Name.Local,
109+
Attrs: make([]xmlAttr, 0),
110+
Children: make([]*xmlElement, 0),
111+
}
112+
113+
for _, attr := range element.Attr {
114+
el.Attrs = append(el.Attrs, xmlAttr{
115+
Name: attr.Name.Local,
116+
Value: attr.Value,
117+
})
118+
}
119+
120+
for {
121+
t, err := decoder.Token()
122+
if errors.Is(err, io.EOF) {
123+
if el.Name == "root" {
124+
return el, nil
125+
}
126+
return nil, fmt.Errorf("unexpected EOF")
127+
}
128+
129+
switch t := t.(type) {
130+
case xml.StartElement:
131+
child, err := j.parseElement(decoder, t)
132+
if err != nil {
133+
return nil, err
134+
}
135+
el.Children = append(el.Children, child)
136+
case xml.CharData:
137+
if unicode.IsSpace([]rune(string(t))[0]) {
138+
continue
139+
}
140+
el.Content += string(t)
141+
case xml.EndElement:
142+
return el, nil
143+
default:
144+
return nil, fmt.Errorf("unexpected token: %v", t)
145+
}
146+
}
147+
}
148+
149+
type xmlWriter struct {
150+
options parsing.WriterOptions
151+
}
152+
153+
// Write writes a value to a byte slice.
154+
func (j *xmlWriter) Write(value *model.Value) ([]byte, error) {
155+
return nil, nil
156+
}

0 commit comments

Comments
 (0)