diff --git a/pkg/yqlib/decode_xml_test.go b/pkg/yqlib/decode_xml_test.go
index cf1e2427..e0d72d21 100644
--- a/pkg/yqlib/decode_xml_test.go
+++ b/pkg/yqlib/decode_xml_test.go
@@ -88,7 +88,11 @@ func documentXmlScenario(t *testing.T, w *bufio.Writer, i interface{}) {
node := decodeXml(t, s.inputXml)
- printer.PrintResults(node.AsList())
+ err := printer.PrintResults(node.AsList())
+ if err != nil {
+ t.Error(err)
+ return
+ }
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", output.String()))
diff --git a/pkg/yqlib/doc/operators/encode-decode.md b/pkg/yqlib/doc/operators/encode-decode.md
index d4416608..d77aa917 100644
--- a/pkg/yqlib/doc/operators/encode-decode.md
+++ b/pkg/yqlib/doc/operators/encode-decode.md
@@ -271,3 +271,19 @@ cat thing1,thing2 true 3.40
dog thing3 false 12
```
+## Decode a xml encoded string
+Given a sample.yml file of:
+```yaml
+a: bar
+```
+then
+```bash
+yq eval '.b = (.a | from_xml)' sample.yml
+```
+will output
+```yaml
+a: bar
+b:
+ foo: bar
+```
+
diff --git a/pkg/yqlib/doc/operators/headers/encode-decode.md b/pkg/yqlib/doc/operators/headers/encode-decode.md
index 92ff9f5a..847240b3 100644
--- a/pkg/yqlib/doc/operators/headers/encode-decode.md
+++ b/pkg/yqlib/doc/operators/headers/encode-decode.md
@@ -14,6 +14,7 @@ These operators are useful to process yaml documents that have stringified embed
| Properties | | to_props/@props |
| CSV | | to_csv/@csv |
| TSV | | to_tsv/@tsv |
+| XML | from_xml | |
CSV and TSV format both accept either a single array or scalars (representing a single row), or an array of array of scalars (representing multiple rows).
diff --git a/pkg/yqlib/expression_tokeniser.go b/pkg/yqlib/expression_tokeniser.go
index 36155b8f..d812039c 100644
--- a/pkg/yqlib/expression_tokeniser.go
+++ b/pkg/yqlib/expression_tokeniser.go
@@ -346,11 +346,13 @@ func initLexer() (*lex.Lexer, error) {
lexer.Add([]byte(`to_tsv`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: TsvOutputFormat}))
lexer.Add([]byte(`@tsv`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: TsvOutputFormat}))
- lexer.Add([]byte(`fromyaml`), opToken(decodeOpType))
- lexer.Add([]byte(`fromjson`), opToken(decodeOpType))
+ lexer.Add([]byte(`fromyaml`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: YamlInputFormat}))
+ lexer.Add([]byte(`fromjson`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: YamlInputFormat}))
+ lexer.Add([]byte(`fromxml`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: XmlInputFormat}))
- lexer.Add([]byte(`from_yaml`), opToken(decodeOpType))
- lexer.Add([]byte(`from_json`), opToken(decodeOpType))
+ lexer.Add([]byte(`from_yaml`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: YamlInputFormat}))
+ lexer.Add([]byte(`from_json`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: YamlInputFormat}))
+ lexer.Add([]byte(`from_xml`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: XmlInputFormat}))
lexer.Add([]byte(`sortKeys`), opToken(sortKeysOpType))
lexer.Add([]byte(`sort_keys`), opToken(sortKeysOpType))
diff --git a/pkg/yqlib/operator_encoder_decoder.go b/pkg/yqlib/operator_encoder_decoder.go
index d4d61b3f..a702d0f1 100644
--- a/pkg/yqlib/operator_encoder_decoder.go
+++ b/pkg/yqlib/operator_encoder_decoder.go
@@ -68,9 +68,23 @@ func encodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
return context.ChildContext(results), nil
}
+type decoderPreferences struct {
+ format InputFormat
+}
+
/* takes a string and decodes it back into an object */
func decodeOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
+ preferences := expressionNode.Operation.Preferences.(decoderPreferences)
+
+ var decoder Decoder
+ switch preferences.format {
+ case YamlInputFormat:
+ decoder = NewYamlDecoder()
+ case XmlInputFormat:
+ decoder = NewXmlDecoder("+a", "+content")
+ }
+
var results = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
@@ -79,7 +93,9 @@ func decodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
var dataBucket yaml.Node
log.Debugf("got: [%v]", candidate.Node.Value)
- decoder := yaml.NewDecoder(strings.NewReader(unwrapDoc(candidate.Node).Value))
+
+ decoder.Init(strings.NewReader(unwrapDoc(candidate.Node).Value))
+
errorReading := decoder.Decode(&dataBucket)
if errorReading != nil {
return Context{}, errorReading
diff --git a/pkg/yqlib/operator_encoder_decoder_test.go b/pkg/yqlib/operator_encoder_decoder_test.go
index 93b3376c..1c394356 100644
--- a/pkg/yqlib/operator_encoder_decoder_test.go
+++ b/pkg/yqlib/operator_encoder_decoder_test.go
@@ -168,6 +168,14 @@ var encoderDecoderOperatorScenarios = []expressionScenario{
"D0, P[], (doc)::a: \"foo:\\n a: frog\"\n",
},
},
+ {
+ description: "Decode a xml encoded string",
+ document: `a: "bar"`,
+ expression: `.b = (.a | from_xml)`,
+ expected: []string{
+ "D0, P[], (doc)::a: \"bar\"\nb:\n foo: bar\n",
+ },
+ },
}
func TestEncoderDecoderOperatorScenarios(t *testing.T) {
diff --git a/scripts/copy-docs.sh b/scripts/copy-docs.sh
index e3f39341..5c27efaa 100755
--- a/scripts/copy-docs.sh
+++ b/scripts/copy-docs.sh
@@ -1,4 +1,5 @@
#!/bin/bash
cp how-it-works.md ../yq-gitbook/.
-cp pkg/yqlib/doc/*.md ../yq-gitbook/operators/.
\ No newline at end of file
+cp pkg/yqlib/doc/operators/*.md ../yq-gitbook/operators/.
+cp pkg/yqlib/doc/usage/*.md ../yq-gitbook/usage/.
\ No newline at end of file