From 7e0f9935ba9d59a06072ac4159fe38fcbce2db94 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Tue, 21 Dec 2021 14:58:36 +1100 Subject: [PATCH] Fin. --- pkg/yqlib/decode_xml_test.go | 6 +++++- pkg/yqlib/doc/operators/encode-decode.md | 16 ++++++++++++++++ .../doc/operators/headers/encode-decode.md | 1 + pkg/yqlib/expression_tokeniser.go | 10 ++++++---- pkg/yqlib/operator_encoder_decoder.go | 18 +++++++++++++++++- pkg/yqlib/operator_encoder_decoder_test.go | 8 ++++++++ scripts/copy-docs.sh | 3 ++- 7 files changed, 55 insertions(+), 7 deletions(-) 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