This commit is contained in:
Mike Farah 2021-12-21 17:59:44 +11:00
parent c48b1612df
commit 4d9583d1ee
6 changed files with 148 additions and 40 deletions

View File

@ -1,15 +1,8 @@
strings:
- a: banana
- a: cat
- a: apple
numbers:
- a: 12
- a: 13
- a: 120
obj:
- a: {cat: "adog"}
- a: {cat: "doga"}
- a: apple
# above_cat
cat: # inline_cat
# above_array
array: # inline_array
- 3 # inline_3
# above_4
- 4 # inline_4
# below_cat

View File

@ -108,7 +108,8 @@ yq e -o=xml '.' sample.yml
```
will output
```xml
<cat>purrs</cat>```
<cat>purrs</cat>
```
## Encode xml: array
Given a sample.yml file of:
@ -127,7 +128,8 @@ will output
<pets>
<cat>purrs</cat>
<cat>meows</cat>
</pets>```
</pets>
```
## Encode xml: attributes
Fields with the matching xml-attribute-prefix are assumed to be attributes.
@ -147,7 +149,8 @@ will output
```xml
<cat name="tiger">
<meows>true</meows>
</cat>```
</cat>
```
## Encode xml: attributes with content
Fields with the matching xml-content-name is assumed to be content.
@ -165,5 +168,33 @@ yq e -o=xml '.' sample.yml
```
will output
```xml
<cat name="tiger">cool</cat>```
<cat name="tiger">cool</cat>
```
## Encode xml: comments
A best attempt is made to copy comments to xml.
Given a sample.yml file of:
```yaml
# above_cat
cat: # inline_cat
# above_array
array: # inline_array
- val1 # inline_val1
# above_val2
- val2 # inline_val2
# below_cat
```
then
```bash
yq e -o=xml '.' sample.yml
```
will output
```xml
<!-- above_cat inline_cat--><cat><!-- above_array inline_array-->
<array><!-- inline_val1-->val1</array>
<array><!-- above_val2 inline_val2-->val2</array>
</cat><!-- below_cat-->
```

View File

@ -3,7 +3,6 @@ package yqlib
import (
"fmt"
"io"
"strings"
"github.com/magiconair/properties"
yaml "gopkg.in/yaml.v3"
@ -30,9 +29,7 @@ func (pe *propertiesEncoder) Encode(node *yaml.Node) error {
}
func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, path string) error {
p.SetComment(path,
strings.Replace(node.HeadComment, "#", "", 1)+
strings.Replace(node.LineComment, "#", "", 1))
p.SetComment(path, headAndLineComment(node))
switch node.Kind {
case yaml.ScalarNode:
_, _, err := p.Set(path, node.Value)

View File

@ -32,14 +32,20 @@ func (e *xmlEncoder) Encode(node *yaml.Node) error {
if err != nil {
return err
}
var charData xml.CharData = []byte("\n")
err = e.xmlEncoder.EncodeToken(charData)
case yaml.DocumentNode:
err := e.encodeComment(headAndLineComment(node))
if err != nil {
return err
}
err = e.Encode(unwrapDoc(node))
if err != nil {
return err
}
err = e.encodeComment(footComment(node))
if err != nil {
return err
}
return e.xmlEncoder.Flush()
case yaml.DocumentNode:
return e.Encode(unwrapDoc(node))
case yaml.ScalarNode:
var charData xml.CharData = []byte(node.Value)
err := e.xmlEncoder.EncodeToken(charData)
@ -47,8 +53,12 @@ func (e *xmlEncoder) Encode(node *yaml.Node) error {
return err
}
return e.xmlEncoder.Flush()
default:
return fmt.Errorf("unsupported type %v", node.Tag)
}
return fmt.Errorf("unsupported type %v", node.Tag)
var charData xml.CharData = []byte("\n")
return e.xmlEncoder.EncodeToken(charData)
}
func (e *xmlEncoder) encodeTopLevelMap(node *yaml.Node) error {
@ -57,7 +67,16 @@ func (e *xmlEncoder) encodeTopLevelMap(node *yaml.Node) error {
value := node.Content[i+1]
start := xml.StartElement{Name: xml.Name{Local: key.Value}}
err := e.doEncode(value, start)
err := e.encodeComment(headAndLineComment(key))
if err != nil {
return err
}
err = e.doEncode(value, start)
if err != nil {
return err
}
err = e.encodeComment(footComment(key))
if err != nil {
return err
}
@ -65,6 +84,22 @@ func (e *xmlEncoder) encodeTopLevelMap(node *yaml.Node) error {
return nil
}
func (e *xmlEncoder) encodeStart(node *yaml.Node, start xml.StartElement) error {
err := e.xmlEncoder.EncodeToken(start)
if err != nil {
return err
}
return e.encodeComment(headAndLineComment(node))
}
func (e *xmlEncoder) encodeEnd(node *yaml.Node, start xml.StartElement) error {
err := e.xmlEncoder.EncodeToken(start.End())
if err != nil {
return err
}
return e.encodeComment(footComment(node))
}
func (e *xmlEncoder) doEncode(node *yaml.Node, start xml.StartElement) error {
switch node.Kind {
case yaml.MappingNode:
@ -72,22 +107,33 @@ func (e *xmlEncoder) doEncode(node *yaml.Node, start xml.StartElement) error {
case yaml.SequenceNode:
return e.encodeArray(node, start)
case yaml.ScalarNode:
err := e.xmlEncoder.EncodeToken(start)
err := e.encodeStart(node, start)
if err != nil {
return err
}
var charData xml.CharData = []byte(node.Value)
err = e.xmlEncoder.EncodeToken(charData)
if err != nil {
return err
}
return e.xmlEncoder.EncodeToken(start.End())
return e.encodeEnd(node, start)
}
return fmt.Errorf("unsupported type %v", node.Tag)
}
func (e *xmlEncoder) encodeComment(commentStr string) error {
if commentStr != "" {
var comment xml.Comment = []byte(commentStr)
err := e.xmlEncoder.EncodeToken(comment)
if err != nil {
return err
}
}
return nil
}
func (e *xmlEncoder) encodeArray(node *yaml.Node, start xml.StartElement) error {
for i := 0; i < len(node.Content); i++ {
value := node.Content[i]
@ -116,7 +162,7 @@ func (e *xmlEncoder) encodeMap(node *yaml.Node, start xml.StartElement) error {
}
}
err := e.xmlEncoder.EncodeToken(start)
err := e.encodeStart(node, start)
if err != nil {
return err
}
@ -126,6 +172,11 @@ func (e *xmlEncoder) encodeMap(node *yaml.Node, start xml.StartElement) error {
key := node.Content[i]
value := node.Content[i+1]
err := e.encodeComment(headAndLineComment(key))
if err != nil {
return err
}
if !strings.HasPrefix(key.Value, e.attributePrefix) && key.Value != e.contentName {
start := xml.StartElement{Name: xml.Name{Local: key.Value}}
err := e.doEncode(value, start)
@ -140,7 +191,11 @@ func (e *xmlEncoder) encodeMap(node *yaml.Node, start xml.StartElement) error {
return err
}
}
err = e.encodeComment(footComment(key))
if err != nil {
return err
}
}
return e.xmlEncoder.EncodeToken(start.End())
return e.encodeEnd(node, start)
}

View File

@ -236,6 +236,15 @@ func createScalarNode(value interface{}, stringValue string) *yaml.Node {
return node
}
func headAndLineComment(node *yaml.Node) string {
return strings.Replace(node.HeadComment, "#", "", 1) +
strings.Replace(node.LineComment, "#", "", 1)
}
func footComment(node *yaml.Node) string {
return strings.Replace(node.FootComment, "#", "", 1)
}
func createValueOperation(value interface{}, stringValue string) *Operation {
var node *yaml.Node = createScalarNode(value, stringValue)

View File

@ -52,6 +52,22 @@ type xmlScenario struct {
encodeScenario bool
}
var yamlWithComments = `# above_cat
cat: # inline_cat
# above_array
array: # inline_array
- val1 # inline_val1
# above_val2
- val2 # inline_val2
# below_cat
`
var expectedXmlWithComments = `<!-- above_cat inline_cat--><cat><!-- above_array inline_array-->
<array><!-- inline_val1-->val1</array>
<array><!-- above_val2 inline_val2-->val2</array>
</cat><!-- below_cat-->
`
var xmlScenarios = []xmlScenario{
{
description: "Parse xml: simple",
@ -79,33 +95,40 @@ var xmlScenarios = []xmlScenario{
{
description: "Encode xml: simple",
input: "cat: purrs",
expected: "<cat>purrs</cat>",
expected: "<cat>purrs</cat>\n",
encodeScenario: true,
},
{
description: "Encode xml: array",
input: "pets:\n cat:\n - purrs\n - meows",
expected: "<pets>\n <cat>purrs</cat>\n <cat>meows</cat>\n</pets>",
expected: "<pets>\n <cat>purrs</cat>\n <cat>meows</cat>\n</pets>\n",
encodeScenario: true,
},
{
description: "Encode xml: attributes",
subdescription: "Fields with the matching xml-attribute-prefix are assumed to be attributes.",
input: "cat:\n +name: tiger\n meows: true\n",
expected: "<cat name=\"tiger\">\n <meows>true</meows>\n</cat>",
expected: "<cat name=\"tiger\">\n <meows>true</meows>\n</cat>\n",
encodeScenario: true,
},
{
skipDoc: true,
input: "cat:\n ++name: tiger\n meows: true\n",
expected: "<cat +name=\"tiger\">\n <meows>true</meows>\n</cat>",
expected: "<cat +name=\"tiger\">\n <meows>true</meows>\n</cat>\n",
encodeScenario: true,
},
{
description: "Encode xml: attributes with content",
subdescription: "Fields with the matching xml-content-name is assumed to be content.",
input: "cat:\n +name: tiger\n +content: cool\n",
expected: "<cat name=\"tiger\">cool</cat>",
expected: "<cat name=\"tiger\">cool</cat>\n",
encodeScenario: true,
},
{
description: "Encode xml: comments",
subdescription: "A best attempt is made to copy comments to xml.",
input: yamlWithComments,
expected: expectedXmlWithComments,
encodeScenario: true,
},
}