forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/brianvoe/gofakeit/v6/xml.go

576 lines
8.7 KiB
Go
Raw Normal View History

2024-04-26 19:30:35 +00:00
package gofakeit
import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"math/rand"
"reflect"
)
// XMLOptions defines values needed for json generation
2024-04-26 19:30:35 +00:00
type XMLOptions struct {
Type string `json:"type" xml:"type" fake:"{randomstring:[array,single]}"` // single or array
RootElement string `json:"root_element" xml:"root_element"`
RecordElement string `json:"record_element" xml:"record_element"`
RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"`
Indent bool `json:"indent" xml:"indent"`
Fields []Field `json:"fields" xml:"fields" fake:"{fields}"`
2024-04-26 19:30:35 +00:00
}
type xmlArray struct {
XMLName xml.Name
Array []xmlMap
2024-04-26 19:30:35 +00:00
}
type xmlMap struct {
XMLName xml.Name
2024-04-26 19:30:35 +00:00
KeyOrder []string
Map map[string]any `xml:",chardata"`
2024-04-26 19:30:35 +00:00
}
type xmlEntry struct {
XMLName xml.Name
Value any `xml:",chardata"`
2024-04-26 19:30:35 +00:00
}
func (m xmlMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
2024-04-26 19:30:35 +00:00
if len(m.Map) == 0 {
2024-04-26 19:30:35 +00:00
return nil
2024-04-26 19:30:35 +00:00
}
start.Name = m.XMLName
err := e.EncodeToken(start)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
err = xmlMapLoop(e, &m)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
return e.EncodeToken(start.End())
2024-04-26 19:30:35 +00:00
}
func xmlMapLoop(e *xml.Encoder, m *xmlMap) error {
2024-04-26 19:30:35 +00:00
var err error
// Check if xmlmap has key order if not create it
2024-04-26 19:30:35 +00:00
// Get key order by order of fields array
2024-04-26 19:30:35 +00:00
if m.KeyOrder == nil {
2024-04-26 19:30:35 +00:00
m.KeyOrder = make([]string, len(m.Map))
2024-04-26 19:30:35 +00:00
for k := range m.Map {
2024-04-26 19:30:35 +00:00
m.KeyOrder = append(m.KeyOrder, k)
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
for _, key := range m.KeyOrder {
2024-04-26 19:30:35 +00:00
v := reflect.ValueOf(m.Map[key])
// Always get underlyning Value of value
2024-04-26 19:30:35 +00:00
if v.Kind() == reflect.Ptr {
2024-04-26 19:30:35 +00:00
v = reflect.Indirect(v)
2024-04-26 19:30:35 +00:00
}
switch v.Kind() {
2024-04-26 19:30:35 +00:00
case reflect.Bool,
2024-04-26 19:30:35 +00:00
reflect.String,
2024-04-26 19:30:35 +00:00
reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64,
2024-04-26 19:30:35 +00:00
reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint64,
2024-04-26 19:30:35 +00:00
reflect.Float32, reflect.Float64:
2024-04-26 19:30:35 +00:00
err = e.Encode(xmlEntry{XMLName: xml.Name{Local: key}, Value: m.Map[key]})
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
case reflect.Slice:
2024-04-26 19:30:35 +00:00
e.EncodeToken(xml.StartElement{Name: xml.Name{Local: key}})
2024-04-26 19:30:35 +00:00
for i := 0; i < v.Len(); i++ {
2024-04-26 19:30:35 +00:00
err = e.Encode(xmlEntry{XMLName: xml.Name{Local: "value"}, Value: v.Index(i).String()})
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
e.EncodeToken(xml.EndElement{Name: xml.Name{Local: key}})
2024-04-26 19:30:35 +00:00
case reflect.Map:
2024-04-26 19:30:35 +00:00
err = e.Encode(xmlMap{
2024-04-26 19:30:35 +00:00
XMLName: xml.Name{Local: key},
Map: m.Map[key].(map[string]any),
2024-04-26 19:30:35 +00:00
})
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
case reflect.Struct:
2024-04-26 19:30:35 +00:00
// Convert struct to map[string]any
2024-04-26 19:30:35 +00:00
// So we can rewrap element
2024-04-26 19:30:35 +00:00
var inInterface map[string]any
2024-04-26 19:30:35 +00:00
inrec, _ := json.Marshal(m.Map[key])
2024-04-26 19:30:35 +00:00
json.Unmarshal(inrec, &inInterface)
err = e.Encode(xmlMap{
2024-04-26 19:30:35 +00:00
XMLName: xml.Name{Local: key},
Map: inInterface,
2024-04-26 19:30:35 +00:00
})
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
default:
2024-04-26 19:30:35 +00:00
err = e.Encode(m.Map[key])
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
return nil
2024-04-26 19:30:35 +00:00
}
// XML generates an object or an array of objects in json format
2024-04-26 19:30:35 +00:00
// A nil XMLOptions returns a randomly structured XML.
2024-04-26 19:30:35 +00:00
func XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(globalFaker, xo) }
// XML generates an object or an array of objects in json format
2024-04-26 19:30:35 +00:00
// A nil XMLOptions returns a randomly structured XML.
2024-04-26 19:30:35 +00:00
func (f *Faker) XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(f, xo) }
func xmlFunc(f *Faker, xo *XMLOptions) ([]byte, error) {
2024-04-26 19:30:35 +00:00
if xo == nil {
2024-04-26 19:30:35 +00:00
// We didn't get a XMLOptions, so create a new random one
2024-04-26 19:30:35 +00:00
err := f.Struct(&xo)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
// Check to make sure they passed in a type
2024-04-26 19:30:35 +00:00
if xo.Type != "single" && xo.Type != "array" {
2024-04-26 19:30:35 +00:00
return nil, errors.New("invalid type, must be array or object")
2024-04-26 19:30:35 +00:00
}
// Check fields length
2024-04-26 19:30:35 +00:00
if xo.Fields == nil || len(xo.Fields) <= 0 {
2024-04-26 19:30:35 +00:00
return nil, errors.New("must pass fields in order to build json object(s)")
2024-04-26 19:30:35 +00:00
}
// Check root element string
2024-04-26 19:30:35 +00:00
if xo.RootElement == "" {
2024-04-26 19:30:35 +00:00
xo.RecordElement = "xml"
2024-04-26 19:30:35 +00:00
}
// Check record element string
2024-04-26 19:30:35 +00:00
if xo.RecordElement == "" {
2024-04-26 19:30:35 +00:00
xo.RecordElement = "record"
2024-04-26 19:30:35 +00:00
}
// Get key order by order of fields array
2024-04-26 19:30:35 +00:00
keyOrder := make([]string, len(xo.Fields))
2024-04-26 19:30:35 +00:00
for _, f := range xo.Fields {
2024-04-26 19:30:35 +00:00
keyOrder = append(keyOrder, f.Name)
2024-04-26 19:30:35 +00:00
}
if xo.Type == "single" {
2024-04-26 19:30:35 +00:00
v := xmlMap{
XMLName: xml.Name{Local: xo.RootElement},
2024-04-26 19:30:35 +00:00
KeyOrder: keyOrder,
Map: make(map[string]any),
2024-04-26 19:30:35 +00:00
}
// Loop through fields and add to them to map[string]any
2024-04-26 19:30:35 +00:00
for _, field := range xo.Fields {
2024-04-26 19:30:35 +00:00
// Get function info
2024-04-26 19:30:35 +00:00
funcInfo := GetFuncLookup(field.Function)
2024-04-26 19:30:35 +00:00
if funcInfo == nil {
2024-04-26 19:30:35 +00:00
return nil, errors.New("invalid function, " + field.Function + " does not exist")
2024-04-26 19:30:35 +00:00
}
value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
v.Map[field.Name] = value
2024-04-26 19:30:35 +00:00
}
// Marshal into bytes
2024-04-26 19:30:35 +00:00
var b bytes.Buffer
2024-04-26 19:30:35 +00:00
x := xml.NewEncoder(&b)
2024-04-26 19:30:35 +00:00
if xo.Indent {
2024-04-26 19:30:35 +00:00
x.Indent("", " ")
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
err := x.Encode(v)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
return b.Bytes(), nil
2024-04-26 19:30:35 +00:00
}
if xo.Type == "array" {
2024-04-26 19:30:35 +00:00
// Make sure you set a row count
2024-04-26 19:30:35 +00:00
if xo.RowCount <= 0 {
2024-04-26 19:30:35 +00:00
return nil, errors.New("must have row count")
2024-04-26 19:30:35 +00:00
}
xa := xmlArray{
2024-04-26 19:30:35 +00:00
XMLName: xml.Name{Local: xo.RootElement},
Array: make([]xmlMap, xo.RowCount),
2024-04-26 19:30:35 +00:00
}
for i := 1; i <= int(xo.RowCount); i++ {
2024-04-26 19:30:35 +00:00
v := xmlMap{
XMLName: xml.Name{Local: xo.RecordElement},
2024-04-26 19:30:35 +00:00
KeyOrder: keyOrder,
Map: make(map[string]any),
2024-04-26 19:30:35 +00:00
}
// Loop through fields and add to them to map[string]any
2024-04-26 19:30:35 +00:00
for _, field := range xo.Fields {
2024-04-26 19:30:35 +00:00
if field.Function == "autoincrement" {
2024-04-26 19:30:35 +00:00
v.Map[field.Name] = i
2024-04-26 19:30:35 +00:00
continue
2024-04-26 19:30:35 +00:00
}
// Get function info
2024-04-26 19:30:35 +00:00
funcInfo := GetFuncLookup(field.Function)
2024-04-26 19:30:35 +00:00
if funcInfo == nil {
2024-04-26 19:30:35 +00:00
return nil, errors.New("invalid function, " + field.Function + " does not exist")
2024-04-26 19:30:35 +00:00
}
value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
v.Map[field.Name] = value
2024-04-26 19:30:35 +00:00
}
xa.Array = append(xa.Array, v)
2024-04-26 19:30:35 +00:00
}
// Marshal into bytes
2024-04-26 19:30:35 +00:00
var b bytes.Buffer
2024-04-26 19:30:35 +00:00
x := xml.NewEncoder(&b)
2024-04-26 19:30:35 +00:00
if xo.Indent {
2024-04-26 19:30:35 +00:00
x.Indent("", " ")
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
err := x.Encode(xa)
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
return b.Bytes(), nil
2024-04-26 19:30:35 +00:00
}
return nil, errors.New("invalid type, must be array or object")
2024-04-26 19:30:35 +00:00
}
func addFileXMLLookup() {
2024-04-26 19:30:35 +00:00
AddFuncLookup("xml", Info{
Display: "XML",
Category: "file",
2024-04-26 19:30:35 +00:00
Description: "Generates an single or an array of elements in xml format",
2024-04-26 19:30:35 +00:00
Example: `<xml>
2024-04-26 19:30:35 +00:00
<record>
2024-04-26 19:30:35 +00:00
<first_name>Markus</first_name>
2024-04-26 19:30:35 +00:00
<last_name>Moen</last_name>
2024-04-26 19:30:35 +00:00
<password>Dc0VYXjkWABx</password>
2024-04-26 19:30:35 +00:00
</record>
2024-04-26 19:30:35 +00:00
<record>
2024-04-26 19:30:35 +00:00
<first_name>Osborne</first_name>
2024-04-26 19:30:35 +00:00
<last_name>Hilll</last_name>
2024-04-26 19:30:35 +00:00
<password>XPJ9OVNbs5lm</password>
2024-04-26 19:30:35 +00:00
</record>
2024-04-26 19:30:35 +00:00
</xml>`,
Output: "[]byte",
2024-04-26 19:30:35 +00:00
ContentType: "application/xml",
2024-04-26 19:30:35 +00:00
Params: []Param{
2024-04-26 19:30:35 +00:00
{Field: "type", Display: "Type", Type: "string", Default: "single", Options: []string{"single", "array"}, Description: "Type of XML, single or array"},
2024-04-26 19:30:35 +00:00
{Field: "rootelement", Display: "Root Element", Type: "string", Default: "xml", Description: "Root element wrapper name"},
2024-04-26 19:30:35 +00:00
{Field: "recordelement", Display: "Record Element", Type: "string", Default: "record", Description: "Record element for each record row"},
2024-04-26 19:30:35 +00:00
{Field: "rowcount", Display: "Row Count", Type: "int", Default: "100", Description: "Number of rows in JSON array"},
2024-04-26 19:30:35 +00:00
{Field: "indent", Display: "Indent", Type: "bool", Default: "false", Description: "Whether or not to add indents and newlines"},
2024-04-26 19:30:35 +00:00
{Field: "fields", Display: "Fields", Type: "[]Field", Description: "Fields containing key name and function to run in json format"},
},
2024-04-26 19:30:35 +00:00
Generate: func(r *rand.Rand, m *MapParams, info *Info) (any, error) {
2024-04-26 19:30:35 +00:00
xo := XMLOptions{}
typ, err := info.GetString(m, "type")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
xo.Type = typ
rootElement, err := info.GetString(m, "rootelement")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
xo.RootElement = rootElement
recordElement, err := info.GetString(m, "recordelement")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
xo.RecordElement = recordElement
rowcount, err := info.GetInt(m, "rowcount")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
xo.RowCount = rowcount
fieldsStr, err := info.GetStringArray(m, "fields")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
indent, err := info.GetBool(m, "indent")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
xo.Indent = indent
// Check to make sure fields has length
2024-04-26 19:30:35 +00:00
if len(fieldsStr) > 0 {
2024-04-26 19:30:35 +00:00
xo.Fields = make([]Field, len(fieldsStr))
for i, f := range fieldsStr {
2024-04-26 19:30:35 +00:00
// Unmarshal fields string into fields array
2024-04-26 19:30:35 +00:00
err = json.Unmarshal([]byte(f), &xo.Fields[i])
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, errors.New("unable to decode json string")
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
f := &Faker{Rand: r}
2024-04-26 19:30:35 +00:00
return xmlFunc(f, &xo)
2024-04-26 19:30:35 +00:00
},
})
2024-04-26 19:30:35 +00:00
}