Roku ParseJSON gives Unknow Identifier error when loading json via AJAX - json

I'm trying to write a simple Roku application.
When I load the JSON file via roURLTransfer ParseJSON function gives me BRIGHTSCRIPT: ERROR: ParseJSON: Unknown identifier.
If I load the JSON file via ReadAsciiFile("pkg:/feed/feed.json") it works.
The JSON file is the same and I'm pretty sure that my JSON is correct.
url = "http://192.168.1.36/misc/roku/ifilm/feed.json"
result = ""
timeout = 10000
ut = CreateObject("roURLTransfer")
ut.SetPort(CreateObject("roMessagePort"))
ut.SetURL(url)
if ut.AsyncGetToString()
event = wait(timeout, ut.GetPort())
if type(event) = "roUrlEvent"
result = event.GetString()
elseif event = invalid
ut.AsyncCancel()
else
print "roUrlTransfer::AsyncGetToString(): unknown event"
end if
end if
' `print result` shows the correct lintable JSON
' print result
' Next line gives me: BRIGHTSCRIPT: ERROR: ParseJSON: Unknown identifier
json = ParseJSON(result)
But putting the JSON file inside the app works:
feed = ReadAsciiFile("pkg:/feed/feed.json")
sleep(2000)
json = ParseJson(feed)
I need to load the data from the Internet and using the embedded version doesn't help me. Does anyone know what should I do to make it work?

The "Unknown identifier" error is usually because there's a character in the json string that ParseJson() does not support. The reason why ReadAsciiFile() works is likely because the function "cleans up" the json string by applying UTF-8 encoding.
A common character that's present at the beginning of some JSON responses that causes this issue is the unicode character Byte Order Mark (BOM)
If you google "byte order mark json" you'll see lots of cases where this affects other platforms as well.
You can just do a simple find and replace to get rid of that character before attempting to parse the string.
bomChar = Chr(65279)
if result.left(len(bomChar)) = bomChar ' Check if the string has the BOM char prefix
result = result.replace(bomChar, "")
end if
If that doesn't work, then your response may have some other conflicting character, in that case I would advise using ifUrlTransfer::AsyncGetToFile() instead of AsyncGetToString() and then use ReadAsciiFile() which should guarantee a properly formatted json string every time (as long as your json is valid).

Related

Calling an API returns expected JSONArray, found JSONObject

I'm calling an API from Go and trying to push json string data from another api call into it.
I can hand craft the calls using a payload like
payload := strings.NewReader('[{"value1":333, "value2":444}]'
and everything is happy.
I'm now trying to covert this to take the json string {"value1":333, "value2":444} as an input parameter of type string to a function, but when I try and use that as the payload, the api is responding with
expected type: JSONArray, found: JSONObject
I naively tried setting the input to the function as []string and appending the data to an array as the input, but then strings.NewReader complained that it was being fed an array.. which is was.
I'm at a loss to work out how to convert a string of json into a json array that the api will be happy with.
I tried just surrounding the string with [] but the compiler threw a fit about incorrect line termination.
Must have been doing something wrong with the string, surrounding the {} with [] let the function pass the data, but there must be a better way than this.
Any ideas, or am I making this harder than it should be?
You were on the right track with the brackets, but you actually need to append the characters to the string. For example:
str := `{"value1":333, "value2":444}`
str = "[" + str + "]"
// [{"value1":333, "value2":444}]
https://play.golang.org/p/rWHCLDCAngd
If you use brackets outside a string or rune literal, then it is parsed as Go language syntax.

Couchbase: using QueryAsync<string>(query) fails with "Error reading string. Unexpected token"

When using Couchbase generic QueryAsync, I was hoping to get a normal, un-parsed, string back instead of a JSON parsed string.
However, when making this call, it indeed seems that Couchbase SDK for .NET uses Newtonsoft anyways, and tries to intepret it as JSON (it is a valid JSON string by the way!):
string query = $"SELECT * FROM myCollection WHERE id = {r.Next(1, 100000)}";
await scope.QueryAsync<string>(query); // <-- fails here
Newtonsoft.Json.JsonReaderException: 'Error reading string. Unexpected
token: StartObject. Path '', line 6, position 1.'
If I instead do this, it works well and JSON is correctly parsed (all documents from myCollection are valid JSON strings):
string query = $"SELECT * FROM myCollection WHERE id = {r.Next(1, 100000)}";
await scope.QueryAsync<JObject>(query); // <-- No problem
-- EDIT --
I also tried they Keu Value operation instead:
var result = await collection.GetAsync(key);
var content = result.ContentAs<string>(); // <-- fails here with same error
Also using this approach, that I just copied from here, fails.
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered
while parsing value: {. Path '', line 1, position 1.'
The JSON is correct though, and I have verified in different parsers.
Isn't it possible to retrieve raw, unparsed, data from Couchbase?
I just found this on Couchbase forums:
When using SDK 3.x when trying to get a JSON document from Couchbase
and using var result = data.ContentAs(); It always return this
error message: “Unexpected character encountered while parsing value:
{. Path ‘’, line 1, position 1.”
The solution presented there is very convoluted and complex, and strikes me as counter-intuitive:
JMorris writes:
Hi #Brian_Davis -
The Transcoder API was redesigned in SDK3; its now much more
specialized and this type of conversion doesn’t work with the default
JsonTranscoder. Fortunately, we do have another transcoder which
mimics the sdk2 behavior called the LegacyTranscoder which should be
able to handle this for you.
And the convoluted solution seems to be to pass a Transcoder into the options of each call:
var result = await collection.GetAsync(key, options: new GetOptions().Transcoder(new LegacyTranscoder()));
var content = result.ContentAs<string>();

Why is initial JSON object parseable, but object within it not?

I'm storing a config file in version control (GitLab) which contains information to be read by my ruby app. This info is stored as an object containing objects containing objects.
(Update adding more detail and examples for clarity as requested...)
From within my app I can successfully GET the file (which returns the following JSON Object (some bits trimmed with ... for readability):
{"file_name"=>"approval_config.json", "file_path"=>"approval_config.json", "size"=>1331, "encoding"=>"base64", "content_sha256"=>"1c21cbb...fa453fe", "ref"=>"master", "blob_id"=>"de...915", "commit_id"=>"07e...4ff", "last_commit_id"=>"07e...942f", "content"=>"ogICAg...AgICB"}
I can JSON parse the above object and access the contents property on that object. The value of the contents property is a base64Encoded string containing the actual contents of my file in GitLab. I can successfully decode this and see the JSON string stored in GitLab:
"{"G000":{"1":{"max":"4000","name":"Matthew Lewis","id":"ord-matthewl","email":"matthew.lewis#companyx.com"},"2":{"max":"4000","name":"Brendan Jones","id":"ord-brendanj","email":"brendan.jones#companyx.com"},"3":{"max":"20000","name":"Henry Orson","id":"ord-henryo","email":"henry.orson#companyx.com"},"4":{"max":"10000000","name":"Chris Adams","id":"ord-chrisa","email":"chris.adams#companyx.com"}},"G15":{"1":{"max":"4000","name":"Mike Butak","id":"ord-mikebu","email":"mike.butak#companyx.com"},"2":{"max":"4000","name":"Joseph Lister","id":"ord-josephl","email":"joseph.lister#companyx.com"},"3":{"max":"20000","name":"Mike Geisler","id":"ord-mikeg","email":"mike.geisler#companyx.com"},"4":{"max":"10000000","name":"Samuel Ahn","id":"ord-samuela","email":"samuel.ahn#companyx.com"}}}"
THIS string (above), I cannot JSON parse. I get an "unexpected token at '{ (JSON::ParserError)" error.
While writing this update it occurs to me that this "un-parsable" string is simply what I put in the file to begin with. Perhaps the method I used to stringify the file's contents in the first place is the issue. I simply pasted a valid javascript object in my browser's console, JSON.stringify'd it, copied the result from the console, and pasted it in my file in GitLab. Perhaps I need to use Ruby's JSON.stringify method to stringify it?
Based on feedback from #ToddA.Jacobs, I tried the following in my ruby script:
require 'rest-client'
require 'json'
require 'base64'
data = RestClient.get 'https://gitlab.companyx.net/api/v4/projects/3895/repository/files/approval_config.json?ref=master', {'PRIVATE-TOKEN':'*********'}
# get the encoded data stored on the 'content' key:
content = JSON.parse(data)['content']
# decode it:
config = Base64.decode64(content)
# print some logs
$evm.log(:info, config)
$evm.log(:info, "config is a Hash? :" + config.is_a?(Hash).to_s) #prints false
$evm.log(:info, "config is a string? :" + config.is_a?(String).to_s) #prints true
hash = JSON.parse(config)
example = hash.dig "G000" "4" "id"
$evm.log(:info, "print exmaple on next line")
$evm.log(:info, example)
That last line prints:
The following error occurred during method evaluation: NoMethodError: undefined method 'gsub' for nil:NilClass (drbunix:///tmp/automation_engine20200903-3826-1nbuvl) /usr/local/ lib/ruby/gems/2.5.0/gems/manageiq-password-0.3.0/lib/manageiq/password.rb:89:in 'sanitize_string'
Remove Outer Quotes
Your input format is invalid: you're nesting unescaped double quotes, and somehow expecting that to work. Just leave off the outer quotes. For example:
require 'json'
json = <<~'EOF'
{"G000":{"1":{"max":"4000","name":"Matthew Lewis","id":"ord-matthewl","email":"matthew.lewis#companyx.com"},"2":{"max":"4000","name":"Brendan Jones","id":"ord-brendanj","email":"brendan.jones#companyx.com"},"3":{"max":"20000","name":"Henry Orson","id":"ord-henryo","email":"henry.orson#companyx.com"},"4":{"max":"10000000","name":"Chris Adams","id":"ord-chrisa","email":"chris.adams#companyx.com"}},"G15":{"1":{"max":"4000","name":"Mike Butak","id":"ord-mikebu","email":"mike.butak#companyx.com"},"2":{"max":"4000","name":"Joseph Lister","id":"ord-josephl","email":"joseph.lister#companyx.com"},"3":{"max":"20000","name":"Mike Geisler","id":"ord-mikeg","email":"mike.geisler#companyx.com"},"4":{"max":"10000000","name":"Samuel Ahn","id":"ord-samuela","email":"samuel.ahn#companyx.com"}}}
EOF
hash = JSON.parse(json)
hash.dig "G000", "4", "id"
#=> "ord-chrisa"
hash.dig "G15", "4", "id"
#=> "ord-samuela"
This question was answered by users on another post I opened: Why can Ruby not parse local JSON file?
Ultimately the issue was not Ruby failing to parse my JSON. Rather it was the logging function being unable to log the hash.

JSON.parse file input differ from parsing string literal

Im using nodejs to parse some JSON files and insert them into mongodb,the JSON in these files have invalid JSON characters like \n,\" etc ..
The thing that i dont understand is that if i tried to parse like :
console.log(JSON.parse('{"foo":"bar\n"}'))
i get
undefined:1
{"foo":"bar
but if i tried to parse the input from the file (The file has the same string {"foo":"bar\n"})like:
new lazy(fs.createReadStream("info.json"))
.lines
.forEach(function(line){
var line = line.toString();
console.log(JSON.parse(line));
}
);
every thing works fine , i want to know if this fine and its ok to parse the files i have, or i should replace all invalid JSON characters before i parse the files ,
and why is there a difference between the two.
Thanks
If you can read "\n" if your text file, then it's not an end of line but the \ character followed by a n.
\n in a JavaScript string literal adds an end of line and they're forbidden in JSON strings.
See json.org :
To put an end of line in a JSON string, you must escape it, which means you must escape the \ in a JavaScript string so that there's "\n" in the string received by JSON.parse :
console.log(JSON.parse('{"foo":"bar\\n"}'))
This would produce an object whose foo property value would contain an end of line :

Strange Base64 encode/decode problem

I'm using Grails 1.3.7. I have some code that uses the built-in base64Encode function and base64Decode function. It all works fine in simple test cases where I encode some binary data and then decode the resulting string and write it to a new file. In this case the files are identical.
But then I wrote a web service that took the base64 encoded data as a parameter in a POST call. Although the length of the base64 data is identical to the string I passed into the function, the contents of the base64 data are being modified. I spend DAYS debugging this and finally wrote a test controller that passed the data in base64 to post and also took the name of a local file with the correct base64 encoded data, as in:
data=AAA-base-64-data...&testFilename=/name/of/file/with/base64data
Within the test function I compared every byte in the incoming data parameter with the appropriate byte in the test file. I found that somehow every "+" character in the input data parameter had been replaced with a " " (space, ordinal ascii 32). Huh? What could have done that?
To be sure I was correct, I added a line that said:
data = data.replaceAll(' ', '+')
and sure enough the data decoded exactly right. I tried it with arbitrarily long binary files and it now works every time. But I can't figure out for the life of me what would be modifying the data parameter in the post to convert the ord(43) character to ord(32)? I know that the plus sign is one of the 2 somewhat platform dependent characters in the base64 spec, but given that I am doing the encoding and decoding on the same machine for now I am super puzzled what caused this. Sure I have a "fix" since I can make it work, but I am nervous about "fixes" that I don't understand.
The code is too big to post here, but I get the base64 encoding like so:
def inputFile = new File(inputFilename)
def rawData = inputFile.getBytes()
def encoded = rawData.encodeBase64().toString()
I then write that encoded string out to new a file so I can use it for testing later. If I load that file back in as so I get the same rawData:
def encodedFile = new File(encodedFilename)
String encoded = encodedFile.getText()
byte[] rawData = encoded.decodeBase64()
So all that is good. Now assume I take the "encoded" variable and add it to a param to a POST function like so:
String queryString = "data=$encoded"
String url = "http://localhost:8080/some_web_service"
def results = urlPost(url, queryString)
def urlPost(String urlString, String queryString) {
def url = new URL(urlString)
def connection = url.openConnection()
connection.setRequestMethod("POST")
connection.doOutput = true
def writer = new OutputStreamWriter(connection.outputStream)
writer.write(queryString)
writer.flush()
writer.close()
connection.connect()
return (connection.responseCode == 200) ? connection.content.text : "error $connection.responseCode, $connection.responseMessage"
}
on the web service side, in the controller I get the parameter like so:
String data = params?.data
println "incoming data parameter has length of ${data.size()}" //confirm right size
//unless I run the following line, the data does not decode to the same source
data = data.replaceAll(' ', '+')
//as long as I replace spaces with plus, this decodes correctly, why?
byte[] bytedata = data.decodeBase64()
Sorry for the long rant, but I'd really love to understand why I had to do the "replace space with plus sign" to get this to decode correctly. Is there some problem with the plus sign being used in a request parameter?
Whatever populates params expects the request to be a URL-encoded form (specifically, application/x-www-form-urlencoded, where "+" means space), but you didn't URL-encode it. I don't know what functions your language provides, but in pseudo code, queryString should be constructed from
concat(uri_escape("data"), "=", uri_escape(base64_encode(rawBytes)))
which simplifies to
concat("data=", uri_escape(base64_encode(rawBytes)))
The "+" characters will be replaced with "%2B".
You have to use a special base64encode which is also url-safe. The problem is that standard base64encode includes +, / and = characters which are replaced by the percent-encoded version.
http://en.wikipedia.org/wiki/Base64#URL_applications
I'm using the following code in php:
/**
* Custom base64 encoding. Replace unsafe url chars
*
* #param string $val
* #return string
*/
static function base64_url_encode($val) {
return strtr(base64_encode($val), '+/=', '-_,');
}
/**
* Custom base64 decode. Replace custom url safe values with normal
* base64 characters before decoding.
*
* #param string $val
* #return string
*/
static function base64_url_decode($val) {
return base64_decode(strtr($val, '-_,', '+/='));
}
Because it is a parameter to a POST you must URL encode the data.
See http://en.wikipedia.org/wiki/Percent-encoding
paraquote from the wikipedia link
The encoding used by default is based
on a very early version of the general
URI percent-encoding rules, with a
number of modifications such as
newline normalization and replacing
spaces with "+" instead of "%20"
another hidden pitfall everyday web developers like myself know little about