initial
This commit is contained in:
21
vendor/github.com/basgys/goxml2json/LICENSE
generated
vendored
Executable file
21
vendor/github.com/basgys/goxml2json/LICENSE
generated
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Bastien Gysler
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
107
vendor/github.com/basgys/goxml2json/README.md
generated
vendored
Executable file
107
vendor/github.com/basgys/goxml2json/README.md
generated
vendored
Executable file
@@ -0,0 +1,107 @@
|
||||
# goxml2json [](https://circleci.com/gh/basgys/goxml2json)
|
||||
|
||||
Go package that converts XML to JSON
|
||||
|
||||
### Install
|
||||
|
||||
go get -u github.com/basgys/goxml2json
|
||||
|
||||
### Importing
|
||||
|
||||
import github.com/basgys/goxml2json
|
||||
|
||||
### Usage
|
||||
|
||||
**Code example**
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
xj "github.com/basgys/goxml2json"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// xml is an io.Reader
|
||||
xml := strings.NewReader(`<?xml version="1.0" encoding="UTF-8"?><hello>world</hello>`)
|
||||
json, err := xj.Convert(xml)
|
||||
if err != nil {
|
||||
panic("That's embarrassing...")
|
||||
}
|
||||
|
||||
fmt.Println(json.String())
|
||||
// {"hello": "world"}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Input**
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<osm version="0.6" generator="CGImap 0.0.2">
|
||||
<bounds minlat="54.0889580" minlon="12.2487570" maxlat="54.0913900" maxlon="12.2524800"/>
|
||||
<foo>bar</foo>
|
||||
</osm>
|
||||
```
|
||||
|
||||
**Output**
|
||||
|
||||
```json
|
||||
{
|
||||
"osm": {
|
||||
"-version": 0.6,
|
||||
"-generator": "CGImap 0.0.2",
|
||||
"bounds": {
|
||||
"-minlat": "54.0889580",
|
||||
"-minlon": "12.2487570",
|
||||
"-maxlat": "54.0913900",
|
||||
"-maxlon": "12.2524800"
|
||||
},
|
||||
"foo": "bar"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**With type conversion**
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
xj "github.com/basgys/goxml2json"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// xml is an io.Reader
|
||||
xml := strings.NewReader(`<?xml version="1.0" encoding="UTF-8"?><price>19.95</price>`)
|
||||
json, err := xj.Convert(xml, xj.WithTypeConverter(xj.Float))
|
||||
if err != nil {
|
||||
panic("That's embarrassing...")
|
||||
}
|
||||
|
||||
fmt.Println(json.String())
|
||||
// {"price": 19.95}
|
||||
}
|
||||
```
|
||||
|
||||
### Contributing
|
||||
Feel free to contribute to this project if you want to fix/extend/improve it.
|
||||
|
||||
### Contributors
|
||||
|
||||
- [DirectX](https://github.com/directx)
|
||||
- [powerslacker](https://github.com/powerslacker)
|
||||
- [samuelhug](https://github.com/samuelhug)
|
||||
|
||||
### TODO
|
||||
|
||||
* Categorise errors
|
||||
* Option to prettify the JSON output
|
||||
* Benchmark
|
||||
26
vendor/github.com/basgys/goxml2json/converter.go
generated
vendored
Executable file
26
vendor/github.com/basgys/goxml2json/converter.go
generated
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
package xml2json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Convert converts the given XML document to JSON
|
||||
func Convert(r io.Reader, ps ...plugin) (*bytes.Buffer, error) {
|
||||
// Decode XML document
|
||||
root := &Node{}
|
||||
err := NewDecoder(r, ps...).Decode(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Then encode it in JSON
|
||||
buf := new(bytes.Buffer)
|
||||
e := NewEncoder(buf, ps...)
|
||||
err = e.Encode(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
155
vendor/github.com/basgys/goxml2json/decoder.go
generated
vendored
Executable file
155
vendor/github.com/basgys/goxml2json/decoder.go
generated
vendored
Executable file
@@ -0,0 +1,155 @@
|
||||
package xml2json
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/net/html/charset"
|
||||
)
|
||||
|
||||
const (
|
||||
attrPrefix = "-"
|
||||
contentPrefix = "#"
|
||||
)
|
||||
|
||||
// A Decoder reads and decodes XML objects from an input stream.
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
err error
|
||||
attributePrefix string
|
||||
contentPrefix string
|
||||
excludeAttrs map[string]bool
|
||||
formatters []nodeFormatter
|
||||
}
|
||||
|
||||
type element struct {
|
||||
parent *element
|
||||
n *Node
|
||||
label string
|
||||
}
|
||||
|
||||
func (dec *Decoder) SetAttributePrefix(prefix string) {
|
||||
dec.attributePrefix = prefix
|
||||
}
|
||||
|
||||
func (dec *Decoder) SetContentPrefix(prefix string) {
|
||||
dec.contentPrefix = prefix
|
||||
}
|
||||
|
||||
func (dec *Decoder) AddFormatters(formatters []nodeFormatter) {
|
||||
dec.formatters = formatters
|
||||
}
|
||||
|
||||
func (dec *Decoder) ExcludeAttributes(attrs []string) {
|
||||
for _, attr := range attrs {
|
||||
dec.excludeAttrs[attr] = true
|
||||
}
|
||||
}
|
||||
|
||||
func (dec *Decoder) DecodeWithCustomPrefixes(root *Node, contentPrefix string, attributePrefix string) error {
|
||||
dec.contentPrefix = contentPrefix
|
||||
dec.attributePrefix = attributePrefix
|
||||
return dec.Decode(root)
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder that reads from r.
|
||||
func NewDecoder(r io.Reader, plugins ...plugin) *Decoder {
|
||||
d := &Decoder{r: r, contentPrefix: contentPrefix, attributePrefix: attrPrefix, excludeAttrs: map[string]bool{}}
|
||||
for _, p := range plugins {
|
||||
d = p.AddToDecoder(d)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Decode reads the next JSON-encoded value from its
|
||||
// input and stores it in the value pointed to by v.
|
||||
func (dec *Decoder) Decode(root *Node) error {
|
||||
xmlDec := xml.NewDecoder(dec.r)
|
||||
|
||||
// That will convert the charset if the provided XML is non-UTF-8
|
||||
xmlDec.CharsetReader = charset.NewReaderLabel
|
||||
|
||||
// Create first element from the root node
|
||||
elem := &element{
|
||||
parent: nil,
|
||||
n: root,
|
||||
}
|
||||
|
||||
for {
|
||||
t, _ := xmlDec.Token()
|
||||
if t == nil {
|
||||
break
|
||||
}
|
||||
|
||||
switch se := t.(type) {
|
||||
case xml.StartElement:
|
||||
// Build new a new current element and link it to its parent
|
||||
elem = &element{
|
||||
parent: elem,
|
||||
n: &Node{},
|
||||
label: se.Name.Local,
|
||||
}
|
||||
|
||||
// Extract attributes as children
|
||||
for _, a := range se.Attr {
|
||||
if _, ok := dec.excludeAttrs[a.Name.Local]; ok {
|
||||
continue
|
||||
}
|
||||
elem.n.AddChild(dec.attributePrefix+a.Name.Local, &Node{Data: a.Value})
|
||||
}
|
||||
case xml.CharData:
|
||||
// Extract XML data (if any)
|
||||
elem.n.Data = trimNonGraphic(string(xml.CharData(se)))
|
||||
case xml.EndElement:
|
||||
// And add it to its parent list
|
||||
if elem.parent != nil {
|
||||
elem.parent.n.AddChild(elem.label, elem.n)
|
||||
}
|
||||
|
||||
// Then change the current element to its parent
|
||||
elem = elem.parent
|
||||
}
|
||||
}
|
||||
|
||||
for _, formatter := range dec.formatters {
|
||||
formatter.Format(root)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// trimNonGraphic returns a slice of the string s, with all leading and trailing
|
||||
// non graphic characters and spaces removed.
|
||||
//
|
||||
// Graphic characters include letters, marks, numbers, punctuation, symbols,
|
||||
// and spaces, from categories L, M, N, P, S, Zs.
|
||||
// Spacing characters are set by category Z and property Pattern_White_Space.
|
||||
func trimNonGraphic(s string) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
|
||||
var first *int
|
||||
var last int
|
||||
for i, r := range []rune(s) {
|
||||
if !unicode.IsGraphic(r) || unicode.IsSpace(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
if first == nil {
|
||||
f := i // copy i
|
||||
first = &f
|
||||
last = i
|
||||
} else {
|
||||
last = i
|
||||
}
|
||||
}
|
||||
|
||||
// If first is nil, it means there are no graphic characters
|
||||
if first == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return string([]rune(s)[*first : last+1])
|
||||
}
|
||||
2
vendor/github.com/basgys/goxml2json/doc.go
generated
vendored
Executable file
2
vendor/github.com/basgys/goxml2json/doc.go
generated
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
// Package xml2json is an XML to JSON converter
|
||||
package xml2json
|
||||
191
vendor/github.com/basgys/goxml2json/encoder.go
generated
vendored
Executable file
191
vendor/github.com/basgys/goxml2json/encoder.go
generated
vendored
Executable file
@@ -0,0 +1,191 @@
|
||||
package xml2json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// An Encoder writes JSON objects to an output stream.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
err error
|
||||
contentPrefix string
|
||||
attributePrefix string
|
||||
tc encoderTypeConverter
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer, plugins ...plugin) *Encoder {
|
||||
e := &Encoder{w: w, contentPrefix: contentPrefix, attributePrefix: attrPrefix}
|
||||
for _, p := range plugins {
|
||||
e = p.AddToEncoder(e)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// Encode writes the JSON encoding of v to the stream
|
||||
func (enc *Encoder) Encode(root *Node) error {
|
||||
if enc.err != nil {
|
||||
return enc.err
|
||||
}
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
enc.err = enc.format(root, 0)
|
||||
|
||||
// Terminate each value with a newline.
|
||||
// This makes the output look a little nicer
|
||||
// when debugging, and some kind of space
|
||||
// is required if the encoded value was a number,
|
||||
// so that the reader knows there aren't more
|
||||
// digits coming.
|
||||
enc.write("\n")
|
||||
|
||||
return enc.err
|
||||
}
|
||||
|
||||
func (enc *Encoder) format(n *Node, lvl int) error {
|
||||
if n.IsComplex() {
|
||||
enc.write("{")
|
||||
|
||||
// Add data as an additional attibute (if any)
|
||||
if len(n.Data) > 0 {
|
||||
enc.write("\"")
|
||||
enc.write(enc.contentPrefix)
|
||||
enc.write("content")
|
||||
enc.write("\": ")
|
||||
enc.write(sanitiseString(n.Data))
|
||||
enc.write(", ")
|
||||
}
|
||||
|
||||
i := 0
|
||||
tot := len(n.Children)
|
||||
for label, children := range n.Children {
|
||||
enc.write("\"")
|
||||
enc.write(label)
|
||||
enc.write("\": ")
|
||||
|
||||
if n.ChildrenAlwaysAsArray || len(children) > 1 {
|
||||
// Array
|
||||
enc.write("[")
|
||||
for j, c := range children {
|
||||
enc.format(c, lvl+1)
|
||||
|
||||
if j < len(children)-1 {
|
||||
enc.write(", ")
|
||||
}
|
||||
}
|
||||
enc.write("]")
|
||||
} else {
|
||||
// Map
|
||||
enc.format(children[0], lvl+1)
|
||||
}
|
||||
|
||||
if i < tot-1 {
|
||||
enc.write(", ")
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
enc.write("}")
|
||||
} else {
|
||||
s := sanitiseString(n.Data)
|
||||
if enc.tc == nil {
|
||||
// do nothing
|
||||
} else {
|
||||
s = enc.tc.Convert(s)
|
||||
}
|
||||
enc.write(s)
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) write(s string) {
|
||||
enc.w.Write([]byte(s))
|
||||
}
|
||||
|
||||
// https://golang.org/src/encoding/json/encode.go?s=5584:5627#L788
|
||||
var hex = "0123456789abcdef"
|
||||
|
||||
func sanitiseString(s string) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
buf.WriteByte('"')
|
||||
|
||||
start := 0
|
||||
for i := 0; i < len(s); {
|
||||
if b := s[i]; b < utf8.RuneSelf {
|
||||
if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if start < i {
|
||||
buf.WriteString(s[start:i])
|
||||
}
|
||||
switch b {
|
||||
case '\\', '"':
|
||||
buf.WriteByte('\\')
|
||||
buf.WriteByte(b)
|
||||
case '\n':
|
||||
buf.WriteByte('\\')
|
||||
buf.WriteByte('n')
|
||||
case '\r':
|
||||
buf.WriteByte('\\')
|
||||
buf.WriteByte('r')
|
||||
case '\t':
|
||||
buf.WriteByte('\\')
|
||||
buf.WriteByte('t')
|
||||
default:
|
||||
// This encodes bytes < 0x20 except for \n and \r,
|
||||
// as well as <, > and &. The latter are escaped because they
|
||||
// can lead to security holes when user-controlled strings
|
||||
// are rendered into JSON and served to some browsers.
|
||||
buf.WriteString(`\u00`)
|
||||
buf.WriteByte(hex[b>>4])
|
||||
buf.WriteByte(hex[b&0xF])
|
||||
}
|
||||
i++
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
c, size := utf8.DecodeRuneInString(s[i:])
|
||||
if c == utf8.RuneError && size == 1 {
|
||||
if start < i {
|
||||
buf.WriteString(s[start:i])
|
||||
}
|
||||
buf.WriteString(`\ufffd`)
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
// U+2028 is LINE SEPARATOR.
|
||||
// U+2029 is PARAGRAPH SEPARATOR.
|
||||
// They are both technically valid characters in JSON strings,
|
||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
if c == '\u2028' || c == '\u2029' {
|
||||
if start < i {
|
||||
buf.WriteString(s[start:i])
|
||||
}
|
||||
buf.WriteString(`\u202`)
|
||||
buf.WriteByte(hex[c&0xF])
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
i += size
|
||||
}
|
||||
if start < len(s) {
|
||||
buf.WriteString(s[start:])
|
||||
}
|
||||
|
||||
buf.WriteByte('"')
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
74
vendor/github.com/basgys/goxml2json/jstype.go
generated
vendored
Executable file
74
vendor/github.com/basgys/goxml2json/jstype.go
generated
vendored
Executable file
@@ -0,0 +1,74 @@
|
||||
package xml2json
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// https://cswr.github.io/JsonSchema/spec/basic_types/
|
||||
// JSType is a JavaScript extracted from a string
|
||||
type JSType int
|
||||
|
||||
const (
|
||||
Bool JSType = iota
|
||||
Int
|
||||
Float
|
||||
String
|
||||
Null
|
||||
)
|
||||
|
||||
// Str2JSType extract a JavaScript type from a string
|
||||
func Str2JSType(s string) JSType {
|
||||
var (
|
||||
output JSType
|
||||
)
|
||||
s = strings.TrimSpace(s) // santize the given string
|
||||
switch {
|
||||
case isBool(s):
|
||||
output = Bool
|
||||
case isFloat(s):
|
||||
output = Float
|
||||
case isInt(s):
|
||||
output = Int
|
||||
case isNull(s):
|
||||
output = Null
|
||||
default:
|
||||
output = String // if all alternatives have been eliminated, the input is a string
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func isBool(s string) bool {
|
||||
return s == "true" || s == "false"
|
||||
}
|
||||
|
||||
func isFloat(s string) bool {
|
||||
var output = false
|
||||
if strings.Contains(s, ".") {
|
||||
_, err := strconv.ParseFloat(s, 64)
|
||||
if err == nil { // the string successfully converts to a decimal
|
||||
output = true
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func isInt(s string) bool {
|
||||
var output = false
|
||||
if len(s) >= 1 {
|
||||
_, err := strconv.Atoi(s)
|
||||
if err == nil { // the string successfully converts to an int
|
||||
if s != "0" && s[0] == '0' {
|
||||
// if the first rune is '0' and there is more than 1 rune, then the input is most likely a float or intended to be
|
||||
// a string value -- such as in the case of a guid, or an international phone number
|
||||
} else {
|
||||
output = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func isNull(s string) bool {
|
||||
return s == "null"
|
||||
}
|
||||
161
vendor/github.com/basgys/goxml2json/plugins.go
generated
vendored
Executable file
161
vendor/github.com/basgys/goxml2json/plugins.go
generated
vendored
Executable file
@@ -0,0 +1,161 @@
|
||||
package xml2json
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// an plugin is added to an encoder or/and to an decoder to allow custom functionality at runtime
|
||||
plugin interface {
|
||||
AddToEncoder(*Encoder) *Encoder
|
||||
AddToDecoder(*Decoder) *Decoder
|
||||
}
|
||||
// a type converter overides the default string sanitization for encoding json
|
||||
encoderTypeConverter interface {
|
||||
Convert(string) string
|
||||
}
|
||||
// customTypeConverter converts strings to JSON types using a best guess approach, only parses the JSON types given
|
||||
// when initialized via WithTypeConverter
|
||||
customTypeConverter struct {
|
||||
parseTypes []JSType
|
||||
}
|
||||
|
||||
attrPrefixer string
|
||||
contentPrefixer string
|
||||
|
||||
excluder []string
|
||||
|
||||
nodesFormatter struct {
|
||||
list []nodeFormatter
|
||||
}
|
||||
nodeFormatter struct {
|
||||
path string
|
||||
plugin nodePlugin
|
||||
}
|
||||
|
||||
nodePlugin interface {
|
||||
AddTo(*Node)
|
||||
}
|
||||
|
||||
arrayFormatter struct{}
|
||||
)
|
||||
|
||||
// WithTypeConverter allows customized js type conversion behavior by passing in the desired JSTypes
|
||||
func WithTypeConverter(ts ...JSType) *customTypeConverter {
|
||||
return &customTypeConverter{parseTypes: ts}
|
||||
}
|
||||
|
||||
func (tc *customTypeConverter) parseAsString(t JSType) bool {
|
||||
if t == String {
|
||||
return true
|
||||
}
|
||||
for i := 0; i < len(tc.parseTypes); i++ {
|
||||
if tc.parseTypes[i] == t {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Adds the type converter to the encoder
|
||||
func (tc *customTypeConverter) AddToEncoder(e *Encoder) *Encoder {
|
||||
e.tc = tc
|
||||
return e
|
||||
}
|
||||
|
||||
func (tc *customTypeConverter) AddToDecoder(d *Decoder) *Decoder {
|
||||
return d
|
||||
}
|
||||
|
||||
func (tc *customTypeConverter) Convert(s string) string {
|
||||
// remove quotes if they exists
|
||||
if strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) {
|
||||
s = s[1 : len(s)-1]
|
||||
}
|
||||
jsType := Str2JSType(s)
|
||||
if tc.parseAsString(jsType) {
|
||||
// add the quotes removed at the start of this func
|
||||
s = `"` + s + `"`
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// WithAttrPrefix appends the given prefix to the json output of xml attribute fields to preserve namespaces
|
||||
func WithAttrPrefix(prefix string) *attrPrefixer {
|
||||
ap := attrPrefixer(prefix)
|
||||
return &ap
|
||||
}
|
||||
|
||||
func (a *attrPrefixer) AddToEncoder(e *Encoder) *Encoder {
|
||||
e.attributePrefix = string((*a))
|
||||
return e
|
||||
}
|
||||
|
||||
func (a *attrPrefixer) AddToDecoder(d *Decoder) *Decoder {
|
||||
d.attributePrefix = string((*a))
|
||||
return d
|
||||
}
|
||||
|
||||
// WithContentPrefix appends the given prefix to the json output of xml content fields to preserve namespaces
|
||||
func WithContentPrefix(prefix string) *contentPrefixer {
|
||||
c := contentPrefixer(prefix)
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *contentPrefixer) AddToEncoder(e *Encoder) *Encoder {
|
||||
e.contentPrefix = string((*c))
|
||||
return e
|
||||
}
|
||||
|
||||
func (c *contentPrefixer) AddToDecoder(d *Decoder) *Decoder {
|
||||
d.contentPrefix = string((*c))
|
||||
return d
|
||||
}
|
||||
|
||||
// ExcludeAttributes excludes some xml attributes, for example, xmlns:xsi, xsi:noNamespaceSchemaLocation
|
||||
func ExcludeAttributes(attrs []string) *excluder {
|
||||
ex := excluder(attrs)
|
||||
return &ex
|
||||
}
|
||||
|
||||
func (ex *excluder) AddToEncoder(e *Encoder) *Encoder {
|
||||
return e
|
||||
}
|
||||
|
||||
func (ex *excluder) AddToDecoder(d *Decoder) *Decoder {
|
||||
d.ExcludeAttributes([]string((*ex)))
|
||||
return d
|
||||
}
|
||||
|
||||
// WithNodes formats specific nodes
|
||||
func WithNodes(n ...nodeFormatter) *nodesFormatter {
|
||||
return &nodesFormatter{list: n}
|
||||
}
|
||||
|
||||
func (nf *nodesFormatter) AddToEncoder(e *Encoder) *Encoder {
|
||||
return e
|
||||
}
|
||||
|
||||
func (nf *nodesFormatter) AddToDecoder(d *Decoder) *Decoder {
|
||||
d.AddFormatters(nf.list)
|
||||
return d
|
||||
}
|
||||
|
||||
func NodePlugin(path string, plugin nodePlugin) nodeFormatter {
|
||||
return nodeFormatter{path: path, plugin: plugin}
|
||||
}
|
||||
|
||||
func (nf *nodeFormatter) Format(node *Node) {
|
||||
child := node.GetChild(nf.path)
|
||||
if child != nil {
|
||||
nf.plugin.AddTo(child)
|
||||
}
|
||||
}
|
||||
|
||||
func ToArray() *arrayFormatter {
|
||||
return &arrayFormatter{}
|
||||
}
|
||||
|
||||
func (af *arrayFormatter) AddTo(n *Node) {
|
||||
n.ChildrenAlwaysAsArray = true
|
||||
}
|
||||
47
vendor/github.com/basgys/goxml2json/struct.go
generated
vendored
Executable file
47
vendor/github.com/basgys/goxml2json/struct.go
generated
vendored
Executable file
@@ -0,0 +1,47 @@
|
||||
package xml2json
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Node is a data element on a tree
|
||||
type Node struct {
|
||||
Children map[string]Nodes
|
||||
Data string
|
||||
ChildrenAlwaysAsArray bool
|
||||
}
|
||||
|
||||
// Nodes is a list of nodes
|
||||
type Nodes []*Node
|
||||
|
||||
// AddChild appends a node to the list of children
|
||||
func (n *Node) AddChild(s string, c *Node) {
|
||||
// Lazy lazy
|
||||
if n.Children == nil {
|
||||
n.Children = map[string]Nodes{}
|
||||
}
|
||||
|
||||
n.Children[s] = append(n.Children[s], c)
|
||||
}
|
||||
|
||||
// IsComplex returns whether it is a complex type (has children)
|
||||
func (n *Node) IsComplex() bool {
|
||||
return len(n.Children) > 0
|
||||
}
|
||||
|
||||
// GetChild returns child by path if exists. Path looks like "grandparent.parent.child.grandchild"
|
||||
func (n *Node) GetChild(path string) *Node {
|
||||
result := n
|
||||
names := strings.Split(path, ".")
|
||||
for _, name := range names {
|
||||
children, exists := result.Children[name]
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
if len(children) == 0 {
|
||||
return nil
|
||||
}
|
||||
result = children[0]
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user