This commit is contained in:
Mike Farah 2021-12-21 14:58:36 +11:00
parent d289ddc7e3
commit 7e0f9935ba
7 changed files with 55 additions and 7 deletions

View File

@ -88,7 +88,11 @@ func documentXmlScenario(t *testing.T, w *bufio.Writer, i interface{}) {
node := decodeXml(t, s.inputXml) 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())) writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", output.String()))

View File

@ -271,3 +271,19 @@ cat thing1,thing2 true 3.40
dog thing3 false 12 dog thing3 false 12
``` ```
## Decode a xml encoded string
Given a sample.yml file of:
```yaml
a: <foo>bar</foo>
```
then
```bash
yq eval '.b = (.a | from_xml)' sample.yml
```
will output
```yaml
a: <foo>bar</foo>
b:
foo: bar
```

View File

@ -14,6 +14,7 @@ These operators are useful to process yaml documents that have stringified embed
| Properties | | to_props/@props | | Properties | | to_props/@props |
| CSV | | to_csv/@csv | | CSV | | to_csv/@csv |
| TSV | | to_tsv/@tsv | | 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). 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).

View File

@ -346,11 +346,13 @@ func initLexer() (*lex.Lexer, error) {
lexer.Add([]byte(`to_tsv`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: TsvOutputFormat})) lexer.Add([]byte(`to_tsv`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: TsvOutputFormat}))
lexer.Add([]byte(`@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(`fromyaml`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: YamlInputFormat}))
lexer.Add([]byte(`fromjson`), opToken(decodeOpType)) 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_yaml`), opTokenWithPrefs(decodeOpType, nil, decoderPreferences{format: YamlInputFormat}))
lexer.Add([]byte(`from_json`), opToken(decodeOpType)) 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(`sortKeys`), opToken(sortKeysOpType))
lexer.Add([]byte(`sort_keys`), opToken(sortKeysOpType)) lexer.Add([]byte(`sort_keys`), opToken(sortKeysOpType))

View File

@ -68,9 +68,23 @@ func encodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
return context.ChildContext(results), nil return context.ChildContext(results), nil
} }
type decoderPreferences struct {
format InputFormat
}
/* takes a string and decodes it back into an object */ /* takes a string and decodes it back into an object */
func decodeOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { 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() var results = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode) candidate := el.Value.(*CandidateNode)
@ -79,7 +93,9 @@ func decodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
var dataBucket yaml.Node var dataBucket yaml.Node
log.Debugf("got: [%v]", candidate.Node.Value) 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) errorReading := decoder.Decode(&dataBucket)
if errorReading != nil { if errorReading != nil {
return Context{}, errorReading return Context{}, errorReading

View File

@ -168,6 +168,14 @@ var encoderDecoderOperatorScenarios = []expressionScenario{
"D0, P[], (doc)::a: \"foo:\\n a: frog\"\n", "D0, P[], (doc)::a: \"foo:\\n a: frog\"\n",
}, },
}, },
{
description: "Decode a xml encoded string",
document: `a: "<foo>bar</foo>"`,
expression: `.b = (.a | from_xml)`,
expected: []string{
"D0, P[], (doc)::a: \"<foo>bar</foo>\"\nb:\n foo: bar\n",
},
},
} }
func TestEncoderDecoderOperatorScenarios(t *testing.T) { func TestEncoderDecoderOperatorScenarios(t *testing.T) {

View File

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
cp how-it-works.md ../yq-gitbook/. cp how-it-works.md ../yq-gitbook/.
cp pkg/yqlib/doc/*.md ../yq-gitbook/operators/. cp pkg/yqlib/doc/operators/*.md ../yq-gitbook/operators/.
cp pkg/yqlib/doc/usage/*.md ../yq-gitbook/usage/.