How to pass multiple data objects to HTML templates in Golang - parsing

I am returing all rows of a table as json to the variable pdata and unmarshaling it into an interface object.
I have an instance of the user struct which I would like to pass along with the unmarshalled json data to the render function and access it using field arguments {{.fieldname}} in the html template.
if uuid != "" {
pdata, err := getProduct()
if err != nil {
fmt.Println(err)
}
type Prdata struct {
Puid string `json:"puid"`
Pname string `json:"pname"`
Quantity string `json:"quantity"`
Price string `json:"price"`
Image string `json:"image"`
}
// Obj:= make(map[Prdata]string)
var Pr Prdata
err = json.Unmarshal(pdata , &Pr)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(pdata))
fmt.Println(Pr)
fmt.Println(u)
render(w, "internal", Pr)
}
fmt.Println(string(pdata)) gives this output
[{"image":"1Appleiphone7.jpeg","pname":"iphone7","price":"70000","puid":"d6742e4e-2ad6-43c5-97f4-e8a7b00684e2","quantity":"100"}]
I have only been successful to unmarshal the data into an interface{} object. Trying to make maps with keys of the type interface{} and values of type string but it throws the error:
"json: cannot unmarshal array into Go value of type map[interface {}]string"
The render function takes an argument of the type interface{}
func render(w http.ResponseWriter, name string, data interface{})
fmt.Println(Pr) gives this output:
[map[quantity:100 image:1Appleiphone7.jpeg pname:iphone7 price:70000 puid:d6742e4e-2ad6-43c5-97f4-e8a7b00684e2]]
u is an instance of struct User
var u = &User{}
type User struct {
Uuid string
Username string
Password string
Fname string
Email string
}
I can see the output on the html page using the pipeline {{.}}. However I am not able to access any data using the fieldname.
There must be a way of doing this. But I am not sure how?
When I pass of a json of the type below, I am able to pass it to the struct type and reference it by the key values using pipelines in my template.
str := `{
"image": "1Appleiphone7.jpeg",
"pname": "iphone7",
"price": "70000",
"puid": "d6742e4e-2ad6-43c5-97f4-e8a7b00684e2",
"quantity": "100"
}`
unmarshal function
err = json.Unmarshal([]byte(str), &Pr)
The difference in the json data of the DB record pdata and the one above str is in the use of backticks "`". It seems that though the json data shows key value pairs, it is actually a json array and not a json object. Is there a way to get around this?

You don't need a map[interface{}]string to unmarshal the json obj. Your json is equivalent to slice of maps:
[
{
"image":"1Appleiphone7.jpeg",
"pname":"iphone7",
"price":"70000",
"puid":"d6742e4e-2ad6-43c5-97f4-e8a7b00684e2",
"quantity":"100"
}
]
The object to unmarshal should be a slice of maps with string keys and values:
var Pr []map[string]string
Playground
BTW, I believe misunderstanding is hidden there:
The render function takes an argument of the type interface{}
I means not that you must pass a variable of interface{} type there but it means you CAN pass a variable of any type to render function.

I am posting a working example of unmarshalling json as bytes into a struct type which then can be referenced using the {{.}} in the template.
package main
import (
"encoding/json"
"fmt"
)
type Usrdata struct {
Uuid string
Fname string
}
type Prdata struct {
Puid string `json:"puid"`
Pname string `json:"pname"`
Quantity string `json:"quantity"`
Price string `json:"price"`
Image string `json:"image"`
}
type Data struct {
U Usrdata
P []Prdata
}
func main() {
Ur := Usrdata{Uuid: "xyz", Fname: "Somename"}
Pr := make([]Prdata, 0)
var Dt Data
Dt.U = Ur
pdata := `[{"image":"1Appleiphone7.jpeg","pname":"iphone7","price":"70000","puid":"d6742e4e-2ad6-43c5-97f4-e8a7b00684e2","quantity":"100"}]`
err := json.Unmarshal([]byte(pdata), &Pr)
if err != nil {
fmt.Println(err)
}
Dt.P = Pr
fmt.Println(Pr[0].Pname)
fmt.Println(Pr)
fmt.Println(Dt)
}

Related

convert value of type 'String' to expected argument type 'Int'

I have a dictionary of data passed from another viewController, and when I tried to fetch the id from the dictionary it gives me conversion error!
var comments = [JSON]()
#IBAction func AddCommentBTN(_ sender: Any) {
let commentTXT = CommentTXTField.text
let name = self.accountDetails["name"]
let email = self.accountDetails["email"]
let articleId = self.comments["id"].string! ----> error is here
API.AddComment(articleId: "", name: name!, email: email!, message: commentTXT!) { (error: Error?, success: Bool) in
if success {
self.CommentTableView.reloadData()
print("Registerd Successfuly")
} else {
print("Faile To Comment")
}
}
}
Firstly, self.comments is an array of JSON object. So before getting value from the JSON you need to get the object first from the array. Before getting the 0 index value make sure the array contains value.
Seems like you are using SwiftyJSON to parse the value. So by using .intValue you can get the Int value. .intValue will return a Int type value. If the key not present there then this will return you the 0 value. .intValue not an Optional type.
Try this
let articleId = self.comments[0]["id"].intValue
instead of
let articleId = self.comments["id"].string!
You are converting a String to Int which is not as straightforward as you may think. The String can contain characters that is not a number like "Forest". To convert a String to Int you can use:
if let myInt = Int(self.comments["id"]) {
let articleId = myInt
}
It will check if the string is a correct Int and return an Optional value. You can also use a fallback to define a default value if the String is not correct Int
let myInt = Int(self.comments["id"]) ?? 0
That means “attempt to convert self.comments["id"] to an integer, but if the conversion failed because it contained something invalid then use 0 instead.”
The values of a json are optional and might be on any allowed type. A way parsing this save would be getting the value for "id", which will be an optional, and try to convert this optional to an Int. The Int itself is optional as well. (Short, it might be there or not)
guard let value = self.comments["id"], let articleId = Int64(value) else {
// Not valid
return
}
print(articleId)
A better way would be parsing your json data to an object in the first place. Your controller would not need to deal with the parsing of optional data, but instead just get the right data from the object.

Use JSONAssert on part of JSON with RESTAssured

I am able to retrieve JSON from a service using RESTAssured.
I would like to use the JSONPath capability to extract JSON and then compare it using JSONAssert.
Here's my example:
#Test
public void doAPITestExample() throws JSONException {
// retrieve JSON from service
Response response = RestAssured.given().get("http://localhost:8081/mockservice");
response.then().assertThat().statusCode(200);
String body = response.getBody().asString();
System.out.println("Body:" + body);
/*
{"datetime": "2018-06-21 17:48:07.488384", "data": [{"foo": "bar"}, {"test": "this is test data"}]}
*/
// able to compare entire body with JSONAssert, strict=false
Object data = response.then().extract().path("data");
System.out.println("Response data:");
System.out.println(data.getClass()); // class java.util.ArrayList
System.out.println(data.toString());
// JSONAssert data with strict=false
String expectedJSON = "{\"data\":[{\"foo\": \"bar\"}, {\"test\": \"this is test data\"}]}";
JSONAssert.assertEquals(expectedJSON, response.getBody().asString(), false);
// How do I extract JSON with JSONPath, use JSONAssert together?
}
Approach 1 - using JSONPath to get JSONObject
How do I get JSONPath to return a JSONObject that can be used by JSONAssert?
In the code example:
Object data = response.then().extract().path("data");
This returns a java.util.ArrayList. How can this be used with JSONAssert to compare to expected JSON?
Approach 2 - parse extracted data with JSONParser
If I do data.toString(), this returns a string that cannot be parsed due to lack of quote handling for string values with spaces strings:
String dataString = response.then().extract().path("data").toString();
JSONArray dataArray = (JSONArray) JSONParser.parseJSON(dataString);
Result:
org.json.JSONException: Unterminated object at character 24 of [{foo=bar}, {test=this is test data}]
Approach 3 - Using JSON schema validation
Is is possible to extract just the data property from the JSON and run that against JSON Schema on just that part?
Note: the entire JSON that is returned is quite large. I just want to validate the data property from it.
What would an example of doing a JSON schema validation look for just the data property from the JSON?
Thanks;
You can use the method jsonPath in your response object.
Example:
// this will return bar as per your example response.
String foo = response.jsonPath ().getString ("data[0].foo");
For more info about JSon path check here.

Contextual type 'String' cannot be used with array literal

I am getting an error while converting my code to Swift 3.0. My sample code is below:
func hexRepresentation()->String {
let dataLength:Int = self.count
let string = NSMutableString(capacity: dataLength*2)
let dataBytes:UnsafeRawPointer = (self as NSData).bytes
for idx in 0..<dataLength {
string.appendFormat("%02x", [UInt(dataBytes[idx])] as String )
}
return string as String
}
What does this line do:
string.appendFormat("%02x", [UInt(dataBytes[idx])] as String )
First of all, it takes the byte at index idx in dataBytes and wraps it in an array. This is the array literal referred to in the error message.
Next it tries to cast the array as a String - not convert: cast. This the compiler knows to be impossible, hence the error message.
Fortunately, you don't want to convert the argument to a string because your format specifier asks for a UInt (%x), so what you really want here is just
string.appendFormat("%02x", UInt(dataBytes[idx]))
As for getting the bytes, the Swift type Data has a function foreach which is handy for iterating the bytes:
self.forEach { string.appendFormat("%02x", UInt($0)) }

Chaincode shim: more values for a key or allowing non-integer in the value

During the chaincode init, One can deploy key-value pair such as: ["a","100", "b", "200"]
However, I would like to deploy key-value pairs such as: ["a", "100, v1, v2"]
Such that 100, v1, v2 are values of a. Two notes:
1. The values are non-integer
2. The values are separated by comma ","
Is this possible?
I check the chaincode shim: /home/standards/go/src/github.com/hyperledger/fabric/core/chaincode/shim/chaincode.go
The function:
// PutState writes the specified `value` and `key` into the ledger.
func (stub *ChaincodeStub) PutState(key string, value []byte) error {
return handler.handlePutState(key, value, stub.UUID)
Which invokes handlePutState (key, value, stub.UUID). Any lights on how to modify it so it works as desired? Thanks,
In the chaincode, each state can have only a single value associated with it. However multiple values can be simulated by making that "one value" a list. So you could do something like this
stub.PutState("a",[]byte("100,v1,v2"))
The state for "a" is now a comma separated list. When you want to retrieve these values, do the following:
Avals, err := stub.GetState("a")
AvalsString := string(Avals)
fmt.Println(AvalsString)
which should print the following string
100,v1,v2
If you need the individual arguments from there, just split the string on the commas, and convert to appropriate types. Bam, you can store and retrieve elements now.
Alternatively, if you data structure is more complicated than that, it might be worth it to put your data into a json object. You can then use marshaling and unmarshaling to convert back and forth from []byte (which can be stored in the state directly) and object (which is likely easier to use).
Example with Json, using init method because it's the one you mentioned
type SomeStruct struct {
AVal string `json:"Aval"`
BVal []string `json:"Bval"`
}
func (t *MyChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
//recieve args ["someStringA","BVal1","Bval2","Bval3"]
//constructing and storing json object
myStruct := SomeStruct{
AVal: args[0],
BVal: []string{args[1],args[2],args[3]},
}
myStructBytes, err := json.Marshal(myStruct)
_ = err //ignore errors for example
stub.PutState("myStructKey",myStructBytes)
//get state back to object
var retrievedStruct SomeStruct
retrievedBytes, err := stub.GetState("myStructKey")
json.Unmarshal(retrievedBytes,retrievedStruct)
//congratulations, retrievedStruct now contains the data you stored earlier
return nil,nil
}

Transform data when parsing a JSON string using Dart

I'm using the parse() function provided in dart:json. Is there a way to transform the parsed data using parse()? I'm thinking of something similar to the reviver argument when parsing JSON using JavaScript:
JSON.parse(text[, reviver])
The parse() function in dart:json takes a callback as an arg that you can use to transform the parsed data. For example, you may prefer to express a date field as a DateTime object, and not as a list of numbers representing the year, month and day. Specify a ‘reviver’ function as a second argument to parse.
This function is called once for each object or list property parsed, and the return value of the reviver function is used instead of the parsed value:
import 'dart:json' as json;
void main() {
var jsonPerson = '{"name" : "joe", "date" : [2013, 10, 3]}';
var person = json.parse(jsonPerson, (key, value) {
if (key == "date") {
return new DateTime(value[0], value[1], value[2]);
}
return value;
});
person['name']; // 'joe'
person['date'] is DateTime; // true
}

Resources