XML to json with transform - json

I have the following XML:
<ArrayOfAnyType xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<anyType xsi:type="xsd:dateTime">2016-09-14T13:58:30Z</anyType>
<anyType xsi:type="xsd:decimal">1.2</anyType>
</ArrayOfAnyType>
And I am unmarshaling it to the following structs:
type Value struct {
Data []Data `xml:"anyType"`
}
type Data struct {
Key string `xml:"http://www.w3.org/2001/XMLSchema-instance type,attr"`
Value string `xml:",chardata"`
}
I would ultimately like to marshal them to json of this structure:
{
timestamp: [the value of xsi:type="xsd:dateTime"]
value: [the value of xsi:type="xsd:decimal"]
}
I'm new to Go, so I'm not sure if this is even possible.

Field tags in Go allow specifying any number of distinct values — separated by spaces.
So in your simple case just add json:"value" after xml:"..." and then marshal
the unmarshaled value to JSON.
Note that I mean spaces inside a single tag, not a space-separated tags:
Field string `xml:"myns Xyzzy" json:"Blorb"`
In more complex cases it might be needed to have distinct types for unmarshaling
and marshaling, and shovel data with required intermediate conversions
between the values of these types.

Related

JSON Decoder cannot decode an object into an object

type MiddleMan struct {
User CompletedByUser `json:"user"`
}
type CompletedByUser struct {
DisplayName string `json:"displayName"`
Id string `json:"id"`
}
Using the following types, I run the code
shorterJsonString := `{
"user":{
"displayName":null,
"id":"a03dfee5-a754-4eb9"
}
}`
if !json.Valid([]byte(shorterJsonString)) {
log.Println("Not valid")
}
var middleMan models.MiddleMan
newReader := strings.NewReader(shorterJsonString)
json.NewDecoder(newReader).Decode(&middleMan)
log.Println(middleMan)
Unfortunately, the decoder is seemingly broken for nested objects. Rather than spitting out actual objects, the print prints out
{{ a03dfee5-a754-4eb9 }}
It seems to flatten the whole thing into the id field. What is going on here?
What did you expect to happen / get printed?
The log package (which uses the fmt package) prints structs enclosed in braces, listing field values separated by spaces.
Your MiddleMan has a single field, so it'll look like this:
{field}
Where field is another struct of type CompletedByUser, which has 2 fields, so it'll look like this:
{{field1 field2}}
Where field is of string type, being the empty string, so you'll see the value of field2 prefixed with a space:
{{ a03dfee5-a754-4eb9}}
If you print it adding field names:
log.Printf("%+v", middleMan)
You'll see an output like:
{User:{DisplayName: Id:a03dfee5-a754-4eb9}}
Using another (Go-syntax) format:
log.Printf("%#v", middleMan)
Output:
main.MiddleMan{User:main.CompletedByUser{DisplayName:"", Id:"a03dfee5-a754-4eb9"}}
Try this on the Go Playground.

Why is Golang json.Unmarshall not working with "e" and "E" properties?

Suppose we want to unmarshal the JSON string {"e": "foo", "E": 1}.
Unmarshalling using the type messageUppercaseE works like expected. When using the type message though, the error json: cannot unmarshal number into Go struct field message.e of type string is returned.
Why are we not able to unmarshal the JSON, if only the "e" struct tag is present?
How would I be able to unmarshal the JSON? (I know that I am able to do this via Jeffail/gabs, but would like to stick to the type based approach.)
type message struct {
EventType string `json:"e"`
}
type messageUppercaseE struct {
EventType string `json:"e"`
UppercaseE uint64 `json:"E"`
}
Try it yourself at https://play.golang.org/p/T6KMJRLy7TN
Quoting the docs for unmarshal:
To unmarshal JSON into a struct, Unmarshal matches incoming object keys to the keys used by Marshal (either the struct field name or its tag), preferring an exact match but also accepting a case-insensitive match.
In this case, it is the case-insensitive match that causes the trouble.

How to get data as is from MongoDB and send it to an API as JSON in Golang

I am writing a Golang API at work which when called, gets data from two different MongoDB Collections and appends it into a struct, converts it to JSON, and stringified and sends to an API (Amazon SQS)
The problem is, defining the struct of the data receiving from MongoDB, while some of the fields are defined properly, some are varying
// IncentiveRule struct defines the structure of Incentive rule from Mongo
type IncentiveRule struct {
... Other vars
Rule Rule `bson:"rule" json:"rule"`
... Other vars
}
// Rule defines the struct for Rule Object inside an incentive rule
type Rule struct {
...
Rules interface{} `bson:"rules" json:"rules"`
RuleFilter RuleFilter `bson:"rule_filter" bson:"rule_filter"`
...
}
// RuleFilter ...
type RuleFilter struct {
Condition string `bson:"condition" json:"condition"`
Rules []interface{} `bson:"rules" json:"rules"`
}
While this works, the interface{} defined inside Rule struct is varying and while getting as BSON and decoding and re-encoding to JSON, instead of encoding as "fookey":"barvalue" in JSON, it is encoded as "Key":"fookey","Value":"barvalue", how to avoid this behavior and have it as "fookey":"barvalue"
If you use interface{}, the mongo-go driver is free to choose whatever implementation it sees fits for representing the results. Often it will choose bson.D to represent documents which is an ordered list of key-value pairs where a pair is a struct having a field for Key and a field for Value , so the Go value can preserve the field order.
If field order is not required / important, you may explicitly use bson.M instead of interface{} and []bson.M instead of []interface{}. bson.M is an unordered map, but it represents fields in the form of fieldName: fieldValue, which is exactly what you want.

Unmarshal inconsistent JSON

I have JSON (that I cannot control) like this:
{
"foo1":{
"a":{
"up":10,
"down":5
}
},
"foo2":{
"a":{
"up":1,
"down":1
}
},
"bar":{
"up":11,
"down":6
}
}
"foo1" and "foo2" are dynamic.
How can I properly unmarshal this structure in go?
It would be okay if I could just tell go to not try to deserialize "bar" (the inconsistent property).
Go will by default ignore fields unspecified in the struct you unmarshal into.
In this case, your structure would be set up like this:
type NestedProp2 struct {
Up int
Down int
}
type NestedProp struct {
A NestedProp2
}
type Prop struct {
Foo1 NestedProp
Foo2 NestedProp
}
When you call the the json.Unmarshal function, the extra property will not be deserialized:
var prop Prop
err := json.Unmarshal(jsonBlob, &prop)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v", prop)
So you get the following output:
{Foo1:{A:{Up:10 Down:5}} Foo2:{A:{Up:1 Down:1}}}
You can see it in action here.
You said:
I have JSON (that I cannot control)
So to what extent you could control? Here I could provide you with some scenario, and hope some of them match your purpose :)
Remember the general rule first:
In Golang, if a JSON key failed to find a matched field in struct, it will not be unmarshalled.
This means, for a key name in a JSON struct, when unmarshalling, it will look for a field in a golang struct at the same level with the same name case-insensitively. If this search failed, this key won't be unmarshalled.
For example, a key named foo1 will look for a field name foo1 in a golang struct at the same indent level. However it also matches with Foo1 or FoO1, since this matching is case-insensitive.
Remember, you could use field tag to specify the field name as well. Please take a look at the official page.
The value of some of the JSON fields are not consistent, and they could be ignored.
This is the case #gnalck solved in his answer. According to the general rule, if those inconsistent field failed to find a match, they will not be unmarshalled. Therefore, just don't put those inconsistent fields in the struct and you will be fine.
The value of some of the JSON fields are not consistent, but they could not be ignored.
In this case, #gnalck failed since those fields could not be ignored. Now a better way is to unmarshal bar into a json.RawMessage, so that you could unmarshal later.
The keys of the JSON object is undetermined, and their value is undetermined as well.
In this case, we could unmarshal the whole JSON object into a map[string]json.RawMessage, and unmarshal each fields later. When unmarshalling to a map, you could iterate through the map to get all the fields, and unmarshal them into a proper struct later.

about the validity of the json message

I am wondering why the following is not a valid json
{ test : event}
but
{ "test" : "event" }
is a valid one?
Because in JSON, fields are declared in quotes (so it's "test" and not test), and the only data types a field can store are: number, string, boolean, array, object (that is, another JSON object), or null. event isn't any of those things, but "event" is a string, which is a valid value type. Those are just the rules of JSON.
You should read up on JSON.