[#3896bk] Support parsing XML files
This commit is contained in:
parent
6e9606bc89
commit
1be21b7078
1
go.mod
1
go.mod
|
@ -8,6 +8,7 @@ require (
|
|||
github.com/Microsoft/go-winio v0.4.7 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23
|
||||
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448 // indirect
|
||||
github.com/creasty/defaults v1.3.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -8,6 +8,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV
|
|||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448 h1:PUD50EuOMkXVcpBIA/R95d56duJR9VxhwncsFbNnxW4=
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/beevik/etree"
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/magiconair/properties"
|
||||
|
@ -106,11 +107,93 @@ func (f *ConfigurationFile) Parse(path string) error {
|
|||
case Ini:
|
||||
err = f.parseIniFile(path)
|
||||
break
|
||||
case Xml:
|
||||
err = f.parseXmlFile(path)
|
||||
break
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Parses an xml file.
|
||||
func (f *ConfigurationFile) parseXmlFile(path string) error {
|
||||
doc := etree.NewDocument()
|
||||
file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err := doc.ReadFrom(file); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// If there is no root we should create a basic start to the file. This isn't required though,
|
||||
// and if it doesn't work correctly I'll just remove the code.
|
||||
if doc.Root() == nil {
|
||||
doc.CreateProcInst("xml", `version="1.0" encoding="utf-8"`)
|
||||
}
|
||||
|
||||
for i, replacement := range f.Replace {
|
||||
value, _, err := f.LookupConfigurationValue(replacement)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// If this is the first item and there is no root element, create that root now and apply
|
||||
// it for future use.
|
||||
if i == 0 && doc.Root() == nil {
|
||||
parts := strings.SplitN(replacement.Match, ".", 2)
|
||||
doc.SetRoot(doc.CreateElement(parts[0]))
|
||||
}
|
||||
|
||||
path := "./" + strings.Replace(replacement.Match, ".", "/", -1)
|
||||
|
||||
// If we're not doing a wildcard replacement go ahead and create the
|
||||
// missing element if we cannot find it yet.
|
||||
if !strings.Contains(path, "*") {
|
||||
parts := strings.Split(replacement.Match, ".")
|
||||
|
||||
// Set the initial element to be the root element, and then work from there.
|
||||
var element = doc.Root()
|
||||
|
||||
// Iterate over the path to create the required structure for the given element's path.
|
||||
// This does not set a value, only ensures that the base structure exists. We start at index
|
||||
// 1 because an XML document can only contain a single root element, and from there we'll
|
||||
// work our way down the chain.
|
||||
for _, tag := range parts[1:] {
|
||||
if e := element.FindElement(tag); e == nil {
|
||||
element = element.CreateElement(tag)
|
||||
} else {
|
||||
element = e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the elements we found and update their values.
|
||||
for _, element := range doc.FindElements(path) {
|
||||
element.SetText(string(value))
|
||||
}
|
||||
}
|
||||
|
||||
// If you don't truncate the file you'll end up duplicating the data in there (or just appending
|
||||
// to the end of the file. We don't want to do that.
|
||||
if err := file.Truncate(0); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// Move the cursor to the start of the file to avoid weird spacing issues.
|
||||
file.Seek(0, 0)
|
||||
|
||||
// Ensure the XML is indented properly.
|
||||
doc.Indent(2)
|
||||
|
||||
// Write the XML to the file.
|
||||
_, err = doc.WriteTo(file)
|
||||
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// Parses an ini file.
|
||||
func (f *ConfigurationFile) parseIniFile(path string) error {
|
||||
// Ini package can't handle a non-existent file, so handle that automatically here
|
||||
|
|
Loading…
Reference in New Issue
Block a user