Skip to content

Commit 16cfed1

Browse files
committed
Fix XML format, and fix missing metadata when reading/writing to model values
1 parent d5dff5b commit 16cfed1

File tree

7 files changed

+113
-56
lines changed

7 files changed

+113
-56
lines changed

model/value_map.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (v *Value) SetMapKey(key string, value *Value) error {
4545
if err != nil {
4646
return fmt.Errorf("error getting map: %w", err)
4747
}
48-
m.Set(key, value.value.Interface())
48+
m.Set(key, value)
4949
return nil
5050
case v.isStandardMap():
5151
unpacked, err := v.UnpackUntilKind(reflect.Map)
@@ -93,9 +93,16 @@ func (v *Value) GetMapKey(key string) (*Value, error) {
9393
if !ok {
9494
return nil, MapKeyNotFound{Key: key}
9595
}
96+
if modelValue, isValue := val.(*Value); isValue {
97+
modelValue.setFn = func(newValue *Value) error {
98+
m.Set(key, newValue)
99+
return nil
100+
}
101+
return modelValue, nil
102+
}
96103
res := NewValue(val)
97104
res.setFn = func(newValue *Value) error {
98-
m.Set(key, newValue.value.Interface())
105+
m.Set(key, newValue)
99106
return nil
100107
}
101108
return res, nil

model/value_slice.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,12 @@ func (v *Value) GetSliceIndex(i int) (*Value, error) {
7979
return nil, SliceIndexOutOfRange{Index: i}
8080
}
8181

82-
res := NewValue(unpacked.value.Index(i))
82+
item := unpacked.value.Index(i)
83+
if item.Kind() == reflect.Ptr && item.Type() == reflect.TypeFor[*Value]() {
84+
return item.Interface().(*Value), nil
85+
}
86+
87+
res := NewValue(item)
8388
return res, nil
8489
}
8590

@@ -95,7 +100,7 @@ func (v *Value) SetSliceIndex(i int, val *Value) error {
95100
if i < 0 || i >= unpacked.value.Len() {
96101
return SliceIndexOutOfRange{Index: i}
97102
}
98-
unpacked.value.Index(i).Set(val.value)
103+
unpacked.value.Index(i).Set(reflect.ValueOf(val))
99104
return nil
100105
}
101106

parsing/xml/reader.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ func (j *xmlReader) parseElement(decoder *xml.Decoder, element xml.StartElement)
156156
})
157157
}
158158

159+
var processingInstructions []*xmlProcessingInstruction
160+
159161
for {
160162
t, err := decoder.Token()
161163
if errors.Is(err, io.EOF) {
@@ -171,6 +173,7 @@ func (j *xmlReader) parseElement(decoder *xml.Decoder, element xml.StartElement)
171173
if err != nil {
172174
return nil, err
173175
}
176+
child.ProcessingInstructions = processingInstructions
174177
el.Children = append(el.Children, child)
175178
case xml.CharData:
176179
if unicode.IsSpace([]rune(string(t))[0]) {
@@ -186,7 +189,7 @@ func (j *xmlReader) parseElement(decoder *xml.Decoder, element xml.StartElement)
186189
Target: t.Target,
187190
Value: string(t.Inst),
188191
}
189-
el.ProcessingInstructions = append(el.ProcessingInstructions, pi)
192+
processingInstructions = append(processingInstructions, pi)
190193
continue
191194
case xml.Directive:
192195
continue

parsing/xml/writer.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@ func (j *xmlWriter) Write(value *model.Value) ([]byte, error) {
2929
}()
3030
writer.Indent("", " ")
3131

32-
element, err := j.toElement(value)
32+
element, err := j.toElement("root", value)
3333
if err != nil {
3434
return nil, fmt.Errorf("failed to convert to element: %w", err)
3535
}
36-
37-
if err := writer.Encode(element); err != nil {
38-
return nil, err
36+
for _, c := range element.Children {
37+
if err := writer.Encode(c); err != nil {
38+
return nil, err
39+
}
40+
if err := writer.EncodeToken(xml.CharData("\n")); err != nil {
41+
return nil, err
42+
}
3943
}
4044

4145
if err := writer.Flush(); err != nil {
@@ -48,7 +52,7 @@ func (j *xmlWriter) Write(value *model.Value) ([]byte, error) {
4852
return outBytes, nil
4953
}
5054

51-
func (j *xmlWriter) toElement(value *model.Value) (*xmlElement, error) {
55+
func (j *xmlWriter) toElement(key string, value *model.Value) (*xmlElement, error) {
5256
readProcessingInstructions := func() []*xmlProcessingInstruction {
5357
if piMeta, ok := value.MetadataValue("xml_processing_instructions"); ok && piMeta != nil {
5458
if pis, ok := piMeta.([]*xmlProcessingInstruction); ok {
@@ -62,7 +66,7 @@ func (j *xmlWriter) toElement(value *model.Value) (*xmlElement, error) {
6266
case model.TypeString:
6367
strVal, err := valueToString(value)
6468
return &xmlElement{
65-
Name: "root",
69+
Name: key,
6670
Content: strVal,
6771
ProcessingInstructions: readProcessingInstructions(),
6872
}, err
@@ -74,7 +78,7 @@ func (j *xmlWriter) toElement(value *model.Value) (*xmlElement, error) {
7478
}
7579

7680
el := &xmlElement{
77-
Name: "root",
81+
Name: key,
7882
ProcessingInstructions: readProcessingInstructions(),
7983
}
8084

@@ -99,27 +103,34 @@ func (j *xmlWriter) toElement(value *model.Value) (*xmlElement, error) {
99103
continue
100104
}
101105

102-
childEl, err := j.toElement(kv.Value)
106+
childEl, err := j.toElement(kv.Key, kv.Value)
103107
if err != nil {
104108
return nil, fmt.Errorf("failed to convert child element %q to element: %w", kv.Key, err)
105109
}
106-
childEl.Name = kv.Key
107-
el.Children = append(el.Children, childEl)
110+
if childEl.useChildrenOnly {
111+
el.Children = append(el.Children, childEl.Children...)
112+
} else {
113+
el.Children = append(el.Children, childEl)
114+
}
108115
}
109116

110117
return el, nil
111118
case model.TypeSlice:
112119
el := &xmlElement{
113120
Name: "root",
114121
ProcessingInstructions: readProcessingInstructions(),
122+
useChildrenOnly: true,
115123
}
116124
if err := value.RangeSlice(func(i int, value *model.Value) error {
117-
childEl, err := j.toElement(value)
125+
childEl, err := j.toElement(key, value)
118126
if err != nil {
119127
return err
120128
}
121-
childEl.Name = "item"
122-
el.Children = append(el.Children, childEl)
129+
if childEl.useChildrenOnly {
130+
el.Children = append(el.Children, childEl.Children...)
131+
} else {
132+
el.Children = append(el.Children, childEl)
133+
}
123134

124135
return nil
125136
}); err != nil {
@@ -181,21 +192,20 @@ func (e *xmlElement) MarshalXML(enc *xml.Encoder, start xml.StartElement) error
181192
}
182193
}
183194
start.Name = xml.Name{Local: e.Name}
184-
if err := enc.EncodeToken(start); err != nil {
185-
return err
186-
}
187195

188196
if len(e.Attrs) > 0 {
189197
for _, attr := range e.Attrs {
190-
if err := enc.EncodeToken(xml.Attr{
198+
start.Attr = append(start.Attr, xml.Attr{
191199
Name: xml.Name{Local: attr.Name},
192200
Value: attr.Value,
193-
}); err != nil {
194-
return err
195-
}
201+
})
196202
}
197203
}
198204

205+
if err := enc.EncodeToken(start); err != nil {
206+
return err
207+
}
208+
199209
if len(e.Content) > 0 {
200210
if err := enc.EncodeToken(xml.CharData(e.Content)); err != nil {
201211
return err

parsing/xml/writer_test.go

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package xml_test
22

33
import (
4+
"github.com/tomwright/dasel/v3/model"
45
"testing"
56

67
"github.com/tomwright/dasel/v3/parsing"
@@ -42,21 +43,19 @@ func TestXmlReader_Write(t *testing.T) {
4243
t.Fatalf("Unexpected error: %s", err)
4344
}
4445

45-
expected := `<root>
46-
<Document>
47-
<Sender>Ivanov</Sender>
48-
<In_N_Document>
49-
<N_Document>1024</N_Document>
50-
<Date_Reg>2024-06-21T15:07:29.0451517+03:00</Date_Reg>
51-
</In_N_Document>
52-
<Out_N_Document>
53-
<N_Document>2043</N_Document>
54-
<Date_Reg>2024-05-01T00:00:00</Date_Reg>
55-
</Out_N_Document>
56-
<Content>Skzzkz</Content>
57-
<DSP>true</DSP>
58-
</Document>
59-
</root>
46+
expected := `<Document>
47+
<Sender>Ivanov</Sender>
48+
<In_N_Document>
49+
<N_Document>1024</N_Document>
50+
<Date_Reg>2024-06-21T15:07:29.0451517+03:00</Date_Reg>
51+
</In_N_Document>
52+
<Out_N_Document>
53+
<N_Document>2043</N_Document>
54+
<Date_Reg>2024-05-01T00:00:00</Date_Reg>
55+
</Out_N_Document>
56+
<Content>Skzzkz</Content>
57+
<DSP>true</DSP>
58+
</Document>
6059
`
6160
if string(xmlBytes) != expected {
6261
t.Fatalf("Expected:\n%s\nGot:\n%s", expected, string(xmlBytes))
@@ -93,30 +92,62 @@ func TestXmlReader_Write(t *testing.T) {
9392
t.Fatalf("Unexpected error: %s", err)
9493
}
9594

95+
doc, err := data.GetMapKey("Document")
96+
if err != nil {
97+
t.Fatalf("Unexpected error: %s", err)
98+
}
99+
docProcessingInstructions, ok := doc.MetadataValue("xml_processing_instructions")
100+
if !ok || docProcessingInstructions == nil {
101+
t.Fatalf("Expected processing instructions on Document element")
102+
}
103+
96104
jsonBytes, err := w.Write(data)
97105
if err != nil {
98106
t.Fatalf("Unexpected error: %s", err)
99107
}
100108

101109
expected := `<?xml version="1.0" encoding="utf-8" standalone="yes"?>
102-
<root>
103-
<Document>
104-
<Sender>Ivanov</Sender>
105-
<In_N_Document>
106-
<N_Document>1024</N_Document>
107-
<Date_Reg>2024-06-21T15:07:29.0451517+03:00</Date_Reg>
108-
</In_N_Document>
109-
<Out_N_Document>
110-
<N_Document>2043</N_Document>
111-
<Date_Reg>2024-05-01T00:00:00</Date_Reg>
112-
</Out_N_Document>
113-
<Content>Skzzkz</Content>
114-
<DSP>true</DSP>
115-
</Document>
116-
</root>
110+
<Document>
111+
<Sender>Ivanov</Sender>
112+
<In_N_Document>
113+
<N_Document>1024</N_Document>
114+
<Date_Reg>2024-06-21T15:07:29.0451517+03:00</Date_Reg>
115+
</In_N_Document>
116+
<Out_N_Document>
117+
<N_Document>2043</N_Document>
118+
<Date_Reg>2024-05-01T00:00:00</Date_Reg>
119+
</Out_N_Document>
120+
<Content>Skzzkz</Content>
121+
<DSP>true</DSP>
122+
</Document>
117123
`
118124
if string(jsonBytes) != expected {
119125
t.Fatalf("Expected:\n%s\nGot:\n%s", expected, string(jsonBytes))
120126
}
121127
})
128+
129+
t.Run("encode attributes", func(t *testing.T) {
130+
w, err := xml.XML.NewWriter(parsing.DefaultWriterOptions())
131+
if err != nil {
132+
t.Fatalf("Unexpected error: %s", err)
133+
}
134+
135+
toEncode := model.NewMapValue()
136+
foo := model.NewMapValue()
137+
_ = foo.SetMapKey("-fiz", model.NewStringValue("hello"))
138+
_ = foo.SetMapKey("bar", model.NewStringValue(""))
139+
_ = toEncode.SetMapKey("foo", foo)
140+
141+
got, err := w.Write(toEncode)
142+
if err != nil {
143+
t.Fatalf("Unexpected error: %s", err)
144+
}
145+
exp := []byte(`<foo fiz="hello">
146+
<bar></bar>
147+
</foo>
148+
`)
149+
if string(got) != string(exp) {
150+
t.Errorf("Expected:\n%s\nGot:\n%s", string(exp), string(got))
151+
}
152+
})
122153
}

parsing/xml/xml.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ type xmlElement struct {
3333
Children []*xmlElement
3434
Content string
3535
ProcessingInstructions []*xmlProcessingInstruction
36+
useChildrenOnly bool
3637
}

parsing/yaml/yaml_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ list:
183183
name2: *name
184184
`,
185185
out: `name: Tom
186-
name2: Tom
186+
name2: *name
187187
`,
188188
}.run)
189189
}

0 commit comments

Comments
 (0)