Parse a JSON with an empty string field [closed] - json

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I need to parse a JSON into Go struct. Following is the struct
type Replacement struct {
Find string `json:"find"`
ReplaceWith string `json:"replaceWith"`
}
Following is an example json:
{
"find":"TestValue",
"replaceWith":""
}
The input json can have empty values for some field. Go's encoding/json library by default takes nil value for any empty string provided in JSON.
I've a downstream service, which finds and replaces the replaceWith values in configurations. This is causing issues with my downstream service as it doesn't accept nil for the replaceWith parameter. I have a workaround where I'm replacing nil values by "''" but this can cause an issue where some value is replaced with ''. Is there a way for json to not parse empty string as nil and just ""
Here is a link to the code: https://play.golang.org/p/SprPz7mnWR6

In Go string type cannot hold nil value which is zero value for pointers, interfaces, maps, slices, channels and function types, representing an uninitialized value.
When unmarshalling JSON data to struct as you do in your example ReplaceWith field will indeed be an empty string ("") - which is exactly what you are asking for.
type Replacement struct {
Find string `json:"find"`
ReplaceWith string `json:"replaceWith"`
}
func main() {
data := []byte(`
{
"find":"TestValue",
"replaceWith":""
}`)
var marshaledData Replacement
err := json.Unmarshal(data, &marshaledData)
if err != nil {
fmt.Println(err)
}
if marshaledData.ReplaceWith == "" {
fmt.Println("ReplaceWith equals to an empty string")
}
}

You can use Pointer in string and if the value is missing in JSON then it would be nil. I have done the same in past but currently I don't have code with me.

Related

Go sum type in json [duplicate]

This question already has answers here:
How can we read a json file as json object in golang
(2 answers)
Closed 7 months ago.
What I want to achieve
I'm parsing IAM Policies in Go. In IAM Policies, most of the fields can be either a string or an array of strings. It's hard to think these decision trees in my head what I want is kind of exhaustive pattern matching.
What I did
I loeded a policy with json.Unmarshal
type Policy struct {
Version string `json:"Version"`
Id string `json:"ID,omitempty"`
Statements []Statement `json:"Statement"`
}
type Statement struct {
// ...
Action interface{} `json:"Action"` // string or array
// ...
}
And iterating over statements.
switch ele := st.Action.(type) {
case string:
action, _ := expandAction(ele, data)
actions = append(actions, action...)
setter(i, actions)
case []string:
for _, a := range ele {
if strings.Contains(a, "*") {
exps, _ := expandAction(a, data)
actions = append(actions, exps...)
} else {
actions = append(actions, a)
}
setter(i, actions)
fmt.Println(actions)
}
default:
// interface{}
}
The Problem
It always goes to the default case.
Can use reflection, but don't think I really should, since runtime could know types when json.Unnarshal is called.
As you can see from the official document the type for JSON array is []interface. If you update []string to []interface then you can run the related case block. However, if you have to sure that is array of string, reflection can provide it.

json.NewDecoder(r.Body).Decode(&admin) returns empty struct [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I know there are a lots of people that has run into the same issue but still here I am. I'm pretty sure my code is correct and still the resulting struct is empty.
Function :
func PostAdminHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-type", "application/json")
var admin admin.Admin
json.NewDecoder(r.Body).Decode(&admin)
fmt.Println(admin)
_, err := PostAdmin(admin)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
Console print :
{ ObjectID("000000000000000000000000")}
Structure :
package entity
import "go.mongodb.org/mongo-driver/bson/primitive"
type Admin struct {
FirstName string
LastName string
Email string
Password string
Role string
Campus primitive.ObjectID
}
Route :
adminRoute.HandleFunc("/admin", admin.PostAdminHandler).Methods("POST")
Json data I'm sending through Insomnia :
{
"FirstName": "Jeanne",
"LastName": "Darc",
"Email": "jeanne.darc#rouen.fr",
"Password": "JeanneDarc2022",
"Role": "admin",
"Campus": "60d5a25ff4d722d3b77d1929",
}
Error i'm getting from decoder :
invalid character '}' looking for beginning of object key string
This RFC:
https://datatracker.ietf.org/doc/html/rfc7159
specifies the JSON object format as:
An object structure is represented as a pair of curly brackets
surrounding zero or more name/value pairs (or members). A name is a
string. A single colon comes after each name, separating the name
from the value. A single comma separates a value from a following
name. The names within an object SHOULD be unique.
object = begin-object [ member *( value-separator member ) ]
end-object
member = string name-separator value
So, no trailing commas.
Remove the last comma in the input.

Parsing json over XML [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I really don't understand how to parse this response from the Api using Go since I see XML first and then Json:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://www.zzap.ru/">{"error":"","class_man":"MITSUBISHI","logopath":"https://koj.blob.core.windows.net/zzap-upload/upload/logos/se12d7724469c1dbbe07e303ac6e91b48.png","partnumber":"MR245368","class_cat":"windscreen washer motor","imagepath":"","code_cat":1116901944,"class_cur":"р.","price_count_instock":24,"price_min_instock":200.0,"price_avg_instock":810.0,"price_max_instock":1380.0,"price_count_order":457,"price_min_order":201.0,"price_avg_order":1079.0,"price_max_order":8004.0,"imagepathV2":[""],"code_man":3113}</string>
The following code will unmarshal the xml first and then unmarshal the json in the Text field of the struct the xml was unmarshalled to. Below is a link to the playground where you can run the example and play with it.
package main
import (
"encoding/json"
"encoding/xml"
"fmt"
"log"
)
type xmlStructure struct {
XMLName xml.Name `xml:"string"`
Text string `xml:",chardata"`
XMLNS string `xml:"xmlns,attr"`
}
type jsonStructure struct {
Error string `json:"error"`
ClassMan string `json:"class_man"`
LogoPath string `json:"logo_path"`
PartNumber string `json:"part_number"`
ClassCat string `json:"class_cat"`
// etc.
}
func main() {
var input = `<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://www.zzap.ru/">{"error":"","class_man":"MITSUBISHI","logopath":"https://koj.blob.core.windows.net/zzap-upload/upload/logos/se12d7724469c1dbbe07e303ac6e91b48.png","partnumber":"MR245368","class_cat":"windscreen washer motor","imagepath":"","code_cat":1116901944,"class_cur":"р.","price_count_instock":24,"price_min_instock":200.0,"price_avg_instock":810.0,"price_max_instock":1380.0,"price_count_order":457,"price_min_order":201.0,"price_avg_order":1079.0,"price_max_order":8004.0,"imagepathV2":[""],"code_man":3113}</string>`
var in xmlStructure
if err := xml.Unmarshal([]byte(input), &in); err != nil {
log.Fatal(err)
}
var msg jsonStructure
if err := json.Unmarshal([]byte(in.Text), &msg); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v", msg)
}
Go playground
Note: The jsonStructure type is still missing some fields which where in your example.
Note2: Since you are new to Go:
The key to the problem is the xml and json tags behind the struct fields. They must match the field names of the xml/json input you get. For xml there are some special cases like the xml.Name type that is needed to match a struct to an xml tag. (By this the entire xmlStructure struct is matched to the string tag from the input.) Also the xml:"xmlns,attr" behind the XMLNS field tells the xml package to look for an attribute called xmlns in the string tag. The missing name in xml:",chardata" tells xml to select the content of the string tag.
The json tags are simpler, only stating the matching name in the input.
Also note, that the fields themselves of the structs must be exported, otherwise they are not accessible to the xml/json packages and cannot be filled.

golang function returning value in incoming parameter [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I'm a bit new to golang coming from a nodejs background. I'm a bit confused as to why certain functions have a function signature in the following format
function readContents(var1 type, var2 *type)
If we consider the above function, readContents, reads contents into a pointer of var2. Is this a standard practice in the go language where you pass parameters in and expect them to have return values. A practical example is here https://github.com/vmihailenco/msgpack. If you look at the quickstart it has the following code
err = msgpack.Unmarshal(b, &item)
I would normally expect it to return the value rather than modify the incoming value in &item.
Return values are generally preferred.
The caller must specify the type of the target value to msgpack.Unmarshal. The Unmarshal function can be restructured to use a return value like this:
func Unmarshal(p []data, exampleValueOfType interface{}) (interface{}, error)
The calling code will look something like this:
v, err := msgpack.Unmarshal(b, (*X)(nil))
if err != nil {
// handle error
}
x := v.(*X)
It's simpler for the caller to pass to pass a target value. This avoids the type assertion and mentioning the type twice in the code:
var x X
if err := msgpack.Unmarshal(b, &x) {
// handle error
}

[Go]: Parsing JSON [duplicate]

This question already has answers here:
Lowercase JSON key names with JSON Marshal in Go
(4 answers)
Closed 5 years ago.
What I am trying to do
I am parsing a JSON HTTP response based on this answer to a similar question. My code is able to parse the JSON without any error but is unable to read the values and store them in the provided variable.
This has been puzzling me for the last 2 hours and it might be due to a trivial reason that I am overlooking here.
CODE
type ImporterResponse struct {
results []packagemeta `json:"results"`
}
type packagemeta struct {
path string `json:"path"`
synopsis string `json:"synopsis,omitempty"`
count int `json:"import_count,omitempty`
}
func main() {
res := []byte(`{"results":[{"path":"4d63.com/randstr/lib/randstr","import_count":0,"synopsis":"Package randstr generates random strings (e.g."},{"path":"bitbucket.org/pcas/tool/mathutil","import_count":0}]}`)
fmt.Println("Decoding the JSON")
r := bytes.NewReader(res)
decoder := json.NewDecoder(r)
packageimporters := &ImporterResponse{}
err := decoder.Decode(packageimporters)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Packageimporters: %+v", packageimporters)
fmt.Println(len(packageimporters.results))
}
Link to Playground: https://play.golang.org/p/NzLl7Ujo2IJ
What I want:
How to fix this?
Why is no error message raised if JSON is not parsed properly?
P.S: I understand that this question has been asked before and there are possible solutions available but none of them work for me. Hence, I have made this post.
You need to make your struct fields exported, otherwise the json package cannot access them.
Please read JSON and go for more details, specifically this paragraph:
The json package only accesses the exported fields of struct types
(those that begin with an uppercase letter). Therefore only the the
exported fields of a struct will be present in the JSON output.
And this one for more details:
How does Unmarshal identify the fields in which to store the decoded
data? For a given JSON key "Foo", Unmarshal will look through the
destination struct's fields to find (in order of preference):
An exported field with a tag of "Foo" (see the Go spec for more on
struct tags),
An exported field named "Foo", or
An exported field
named "FOO" or "FoO" or some other case-insensitive match of "Foo".
So your struct should really be:
type Packagemeta struct {
Path string `json:"path"`
Synopsis string `json:"synopsis,omitempty"`
Count int `json:"import_count,omitempty`
}