How to marshal xml in Go but ignore empty fields - go

If I have a struct which I want to be able to Marhsal/Unmarshal things in and out of xml with (using encoding/xml) - how can I not print attributes which are empty?
package main
import (
"encoding/xml"
"fmt"
)
type MyThing struct {
XMLName xml.Name `xml:"body"`
Name string `xml:"name,attr"`
Street string `xml:"street,attr"`
}
func main() {
var thing *MyThing = &MyThing{Name: "Canister"}
result, _ := xml.Marshal(thing)
fmt.Println(string(result))
}
For example see http://play.golang.org/p/K9zFsuL1Cw
In the above playground I'd not want to write out my empty street attribute; how could I do that?

Use omitempty flag on street field.
From Go XML package:
a field with a tag including the "omitempty" option is omitted
if the field value is empty. The empty values are false, 0, any
nil pointer or interface value, and any array, slice, map, or
string of length zero.
In case of your example:
package main
import (
"encoding/xml"
"fmt"
)
type MyThing struct {
XMLName xml.Name `xml:"body"`
Name string `xml:"name,attr"`
Street string `xml:"street,attr,omitempty"`
}
func main() {
var thing *MyThing = &MyThing{Name: "Canister"}
result, _ := xml.Marshal(thing)
fmt.Println(string(result))
}
Playground

Related

How can i know the length of struct in golang?

I am new to Golang and I am trying to get a number of attributes from a structure
For example:
type Client struct{
name string//1
lastName string//2
age uint//3
}
func main(){
client := Client{name:"Facundo",lastName:"Veronelli",age:23}
fmt.println(client.getLengthAttibutes())//It would print "3"
}
Using the reflect package's ValueOf() function returns a value struct. This has a method called NumFields that returns the number of fields.
import (
"fmt"
"reflect"
)
type Client struct{
name string//1
lastName string//2
age uint//3
}
func main(){
client := Client{name:"Facundo",lastName:"Veronelli",age:23}
v := reflect.ValueOf(client)
fmt.Printf("Struct has %d fields", v.NumField())
}
You can use the reflect package for this:
import (
"fmt"
"reflect"
)
type Client struct {
name string //1
lastName string //2
age uint //3
}
func main() {
client := Client{name: "Facundo", lastName: "Veronelli", age: 23}
fmt.Println(reflect.TypeOf(client).NumField())
}
This is not, however, the size of that struct, only the number of fields. Use reflect.TypeOf(client).Size() to get how many bytes the struct occupies in memory.

Property name of a structure to string

I would like to know if it is possible to get the name of a property from a structure and convert it to string.
For example in the following code:
package main
import "fmt"
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
//pass any attribute of any structure
fmt.Println(castProperty(StructB.RefStructA.ValueAA))
//print the name passed but in string. Do not print the value
//expected output: "StructB.RefStructA.ValueAA"
}
func castProperty(value interface{}) string {
//some code
}
Is it possible to write a function that allows obtaining the name of the property of a structure and converted to a string? property value is not required.
That's called Reflection. I let you read the page, it lets you do what you want.
First, read the The first law of reflection: https://go.dev/blog/laws-of-reflection
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
}
https://play.golang.org/p/OuGgD1TlSMO
I am not sure exactly how do you want to give input to your function but here is an example that may help you
package main
import (
"log"
"reflect"
)
func main() {
getPropertyName(B{})
}
type A struct {
field1 string
}
type B struct {
field A
}
func getPropertyName(b interface{}) {
parentType := reflect.TypeOf(b)
val := reflect.ValueOf(b)
for i := 0; i< val.Type().NumField(); i++ {
t := val.Type().Field(i)
ty := val.Type().Field(i).Type.Name()
log.Println(parentType.Name()+"."+ t.Name+"."+ty)
}
}
you could do something like this :
package main
import (
"fmt"
)
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
x := &StructB{RefStructA: StructA{ValueAA: "something"}}
fmt.Printf("%+v", x)
}
out :
&{ValueBA: ValueBB: RefStructA:{ValueAA:something ValueAB:}}

Extract colon separated values from string

I have a Go variable of type string, when I do fmt.Println(variable) my terminal prints out
{"access_key":"AAAAAA","secret_key":"XXXXXXX"}
. How do I extract the values "AAAAAA" and "XXXXXXX"?
This is an example of working code
package main
import (
"encoding/json"
"fmt"
)
type Somestruct struct {
AccessKey string `json:"access_key"`
SecretKey string `json:"secret_key"`
}
func main() {
var output Somestruct
S := `{"access_key":"AAAAAA","secret_key":"XXXXXXX"}`
json.Unmarshal([]byte(S), &output)
fmt.Println(output.SecretKey)
}
See https://play.golang.org/p/vaPVHmo8fhR
I suggested that you learn how to work with json and structs in go.
https://golang.org/pkg/encoding/json/

Is there a good way to not expose certain struct attributes in json payloads?

I was really hoping the below code would work, but it doesn't so currently I have to manually set values from one struct to another.
https://play.golang.org/p/yfcsaNJm9M
package main
import "fmt"
import "encoding/json"
type A struct {
Name string `json:"name"`
Password string `json:"password"`
}
type B struct {
A
Password string `json:"-"`
Locale string `json:"locale"`
}
func main() {
a := A{"Jim", "some_secret_password"}
b := B{A: a, Locale: "en"}
data, _ := json.Marshal(&b)
fmt.Printf("%v", string(data))
}
Output...I don't want to show the secret field
{"name":"Jim","password":"some_secret_password","locale":"en"}
Struct values encode as JSON objects. Each exported struct field
becomes a member of the object unless
- the field's tag is "-", or
- the field is empty and its tag specifies the "omitempty" option.
The empty values are false, 0, any nil pointer or interface value, and
any array, slice, map, or string of length zero. The object's default
key string is the struct field name but can be specified in the struct
field's tag value. The "json" key in the struct field's tag value is
the key name, followed by an optional comma and options. Examples:
// Field is ignored by this package.
Field int `json:"-"`
// Field appears in JSON as key "myName".
Field int `json:"myName"`
// Field appears in JSON as key "myName" and
// the field is omitted from the object if its value is empty,
// as defined above.
Field int `json:"myName,omitempty"`
// Field appears in JSON as key "Field" (the default), but
// the field is skipped if empty.
// Note the leading comma.
Field int `json:",omitempty"`
So your code should be:
package main
import "fmt"
import "encoding/json"
type A struct {
Name string `json:"name"`
Password string `json:"password"`
}
type B struct {
A
Password string `json:"password,omitempty"`
Locale string `json:"locale"`
}
func main() {
a := A{"Jim", "some_secret_password"}
b := B{A: a, Locale: "en"}
data, _ := json.Marshal(&b)
fmt.Printf("%v", string(data))
}
https://play.golang.org/p/HdwIssr-oC

Accessing JSON properties when not using struct

I have some JSON and I need to be able to access the properties. As the JSON properties can vary I can't create a struct to unmarshal into.
Example
The JSON could be this:
{"name" : "John Doe", "email" : "john#doe.com"}
or this:
{"town" : "Somewhere", "email" : "john#doe.com"}
or anything else.
How can I access each of the properties?
You can unmarshal it into an interface{}. If you do that, json.Unmarshal will unmarshal a JSON object into a Go map.
For example:
var untypedResult interface{}
err := json.Unmarshal(..., &untypedResult)
result := untypedResult.(map[string]interface{})
// ... now you can iterate over the keys and values of result ...
See <http://blog.golang.org/json-and-go#TOC_5.> for a complete example.
If you just happen to have fields that may not be specified, you can unmarshal your input into a struct with pointer. If the field isn't present, the pointer will be nil.
package main
import (
"encoding/json"
"fmt"
)
type Foo struct {
A *string
B *string
C *int
}
func main() {
var input string = `{"A": "a","C": 3}`
var foo Foo
json.Unmarshal([]byte(input), &foo)
fmt.Printf("%#v\n", foo)
}
Playground
If you really want something more flexible, you can also unmarshal your input into a map[string]interface{}.
package main
import (
"encoding/json"
"fmt"
)
func main() {
var input string = `{"A": "a","C": 3}`
var foo map[string]interface{} = make(map[string]interface{})
json.Unmarshal([]byte(input), &foo)
fmt.Printf("%#v\n", foo)
}
Playground
When unmarshalling a JSON document, not all properties that are defined in the struct need to be present in the JSON document. In your example, you could define the following struct:
type MyJson struct {
Name string `json:"name"`
Town string `json:"town"`
Email string `json:"email"`
}
When your use this struct to unmarshal a JSON document that has one or more of these properties missing, they will be initialized with the respective type's null value (an empty string for string properties).
Alternatively, you can use the generic interface{} type for unmarshalling and then use type assertions. This is documented in-depth in the blog post "JSON and GO":
var jsonDocument interface{}
err := json.Unmarshal(jsonString, &jsonDocument)
map := jsonDocument.(map[string]interface{})
town := map["town"].(string);

Resources