Parsing JSON stream - javascript

I have an application that is using chrome.sockets. JSON is being passed to and from the socket which does not have a delimiter and is not prefixed with the length of the string.
Now the way sockets are read in chrome.sockets is by passing a max buffer length and it will read all available bytes until the buffer is full. The documentation for the socket.read can be found here
Short of writing/porting a parser, is there a JavaScript JSON parser where I can simply pipe in the response from socket.read?

Have you seen https://github.com/creationix/jsonparse? Looks like it assumes a Node.js environment, but it doesn't like it would be hard to tweak the API to meet your needs.

Update: As you need to check that the JS is valid, you could use JSON.parse to check if it's valid JSON, this should always be available in Chrome. You can convert your arraybuffer to a string and append it on to an accumulator string and after each iteration perform the following check on that string.
function isValidJSON(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
};
// assuming 16bit uint unicode chars
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
Below is an example callback function you could use:
jsonData = "";
function readJSONFromSocket(object readInfo) {
// Arraybuffer to string
partialJSONData = ab2str(readInfo.data);
// Loop through the chars until we get a valid JSON object
for (var x = 0; x < partialJSONData.length; x++) {
// Build up the JSON character by character
jsonData += partialJSONData.charAt(x);
if (isValidJSON(jsonData)) {
console.log(jsonData);
// Do something here
jsonData = "";
}
}
};

I know this question was posted a while ago but here is a good way to handle this.
Install Node JS, install NPM (Node Package Manager)
npm install -g browserify
npm install -g JSONStream
echo "window.JSONStream = require('JSONStream');" > script.js
browserify script.js jsonstream.js
in your webpage
var parseStream = new JSONStream('*');
while (var buffer = socket.read()) {
parseStream.write(buffer);
}
parseStream.on('data', function (obj) {
// obj is a parsed obj
})
Now if you want pipe methodology because your a fan of unix. then add
npm install shoe
shoe('./socketName').pipe(parseStream);

Related

Convert string with '=' to JSON format

I am trying to convert a string i receive back from an API into a JSON object in Angular.
The issue is that the string is not normalized to be parsed into JSON easily.
This is the string im working with:
"{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
When trying to do JSON.parse(myStr) it throws an error due to invalid string format.
Is there an easy way to convert the listed string into a more correct JSON format, getting rid of the '=' and replacing them with ':' instead.
There is more to it than just .replace(/['"]+/g, ''), as even with that the string is not ready to be turned into JSON yet.
Hoping someone more versed in Javascript knows a trick i dont.
You just need to manipulate the string before parsing it remove unecessary string that can cause error to the object like "{" and "}" and split it by "," example is in below.
var obj = {}, str = "{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
str.split(",").forEach((st, i) => {
pair = st.split("=")
if(pair.length > 1) {
obj[pair[0].replace("{",'').replace("}", '').trim()] = pair[1]
} else {
obj[i] = pair
}
})
console.log(obj)
As commenters have posted, unless you control the API or at least have documentation that output will always follow a specific format, then you are limited in what you can do. With your current example, however you can trim off the extraneous bits to get the actual data... (remove braces, split on comma, split on equals) to get your key:value pairs... then build a javascript object from scratch with the data... if you need json string at that point can just JSON.stringify()
var initialString = "{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
var trimmedString = initialString.substr(1, initialString.length - 2);
var pairArray = trimmedString.split(',');
var objArray = [];
pairArray.forEach(pair => {
var elementArray = pair.split('=');
var obj = {
key: elementArray[0].trim(),
value: elementArray[1].trim()
};
objArray.push(obj);
});
var returnObj = {};
objArray.forEach(element => {
returnObj[element.key] = element.value;
});
console.log(JSON.stringify(returnObj));

in javascript how to call powershell script

I have a powershell script and I run on powershell like :
.\download-packages-license.ps1
But I want to call the javascript file before these lines.
var json =fs.readFileSync('../../dev/licenses/AllLicenses.json', 'utf8');
var options = {compact: true, ignoreComment: true, spaces: 4};
var result = convert.json2xml(json, options);
I could not anything in stackoverflow except : How to run a powershell script from javascript?
So pls help thanks
I think this will work for you -
var spawn = require("child_process").spawn;
spawn("powershell.exe",[".\download-packages-license.ps1"]);
You can work with : Node-Powershell
Code Snippet :
const Shell = require('node-powershell');
const ps = new Shell({
executionPolicy: 'Bypass',
noProfile: true
});
ps.addCommand('echo node-powershell');
ps.invoke()
.then(output => {
console.log(output);
})
.catch(err => {
console.log(err);
});
JScript
Simple way.
Works great. Suitable for simple operations, but loses some data when receiving line feeds as a single \n instead of the expected \r\n. Split by \r\n misinterprets the array which leads to the need to reformat the array of strings. Basically, I just wrote this, so there may be other problems.
var codepage='windows-1251';/*US-Europe-1252 and Js file in that codepage*/
var toPStext='Hello.\nПроверка русских буковок.';
var shell=new ActiveXObject('WScript.Shell');
var std=shell.Exec("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy Bypass -command \
$OutputEncoding = [Console]::outputEncoding = [System.Text.Encoding]::GetEncoding('"+codepage+"'); \
Write-Output '"+toPStext+"'");
var output = std.StdOut.ReadAll().split('\r\n');// split('\n') - leads to the loss of some data
if (output.length>0){WScript.echo(output)}
//var x=WScript.StdIn.ReadLine();
Line by line.
Unfortunately, powershell does not accept external data as sequences of lines, unlike cmd.exe with /q /k options, which simplifies this code, but will turn around problems with multiline output code. Of course, if necessary, you can transfer the code as a base64 string to powershell
var codepage='windows-1251';/*US-Europe-1252 and Js file in that codepage*/
var toPStext='Hello.\nПроверка русских буковок.';
var shell=new ActiveXObject('WScript.Shell');
var output=[],errors=[],WshRunning=0,WshFinished=1,WshFailed=2,i=0,tryCount=0;
var std=shell.Exec("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy Bypass -command \
$OutputEncoding = [Console]::outputEncoding = [System.Text.Encoding]::GetEncoding('"+codepage+"'); \
Write-Output '"+toPStext+"'");
do{
if (std.Status==WshFailed){
errors.push('String '+i+' data read error: \n '+std.StdErr.ReadLine());
tryCount++
}
else if(std.Status==WshRunning){
output.push(std.StdOut.ReadLine());
tryCount=0;
WScript.Echo('Running ...')
}
else if(std.Status==WshFinished){
var last=std.StdOut.ReadLine();
if(last.length>0){output.push(last)};last=undefined;
tryCount=21;
WScript.Echo('Finished ...')
}i++;
}while(tryCount<21);
if (output.length>0){WScript.echo(output)}
if (errors.length>0){WScript.echo(errors)}
var x=WScript.StdIn.ReadLine();

using a dll with node-ffi

I'm using node-ffi to access a dll supplied by a custom hardware i bought, the dll uses device driver to do things, they don't supply dll docs but they have a sample app in c#, the dll is used in c# like this:
[DllImport("POS_CIDR.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr CIDR_Info();
...
result = Marshal.PtrToStringUni(CIDR.CIDR_Info());
...
now i try to access CIDR_Info function of dll with following node code:
var ffi = require('ffi')
var ref = require('ref')
var int = ref.types.int;
var libprime = ffi.Library('POS_CIDR.dll', {
'CIDR_Info': [ int ,[]],
});
console.log(libprime.CIDR_Info()); // 73402156
now from what i understad the function returns an integer containing the address of a string, how can i dereference that integer to string in node?
i couldnt find any way to set address of a buffer in node.
update
ok i found how to read that string with this code :
var ffi = require('ffi')
var ref = require('ref')
var stringPtr = ref.refType(ref.types.CString);
var int = ref.types.int
var libprime = ffi.Library('POS_CIDR.dll', {
'CIDR_Info': [ stringPtr ,[]],
});
buf = new Buffer(255);
buf=libprime.CIDR_Info();
console.log(ref.readCString(buf, 0));
now the console outputs p which is the first char of string, if i set the offset to 2 it gives o which is the second char, i think there is a problem with encoding that readCString sees a null char after each char.
any idea how to fix that?

Parse string into command and args in JavaScript

I need to parse strings intended for cross-spawn
From the following strings:
cmd foo bar
cmd "foo bar" --baz boom
cmd "baz \"boo\" bam"
cmd "foo 'bar bud' jim" jam
FOO=bar cmd baz
To an object:
{command: 'cmd', args: ['foo', 'bar']}
{command: 'cmd', args: ['foo bar', '--baz', 'boom']}
{command: 'cmd', args: ['baz "boo" bam']}
{command: 'cmd', args: ['foo \'bar bud\' jim', 'jam']}
{command: 'cmd', args: ['baz'], env: {FOO: 'bar'}}
I'm thinking a regex would be possible, but I'd love to avoid writing something custom. Anyone know of anything existing that could do this?
Edit
The question and answers are still valuable, but for my specific use-case I no longer need to do this. I'll use spawn-command instead (more accurately, I'll use spawn-command-with-kill) which doesn't require the command and args to be separate. This will make life much easier for me. Thanks!
You could roll your own with regex, but I'd strongly recommend looking at either:
minimist by Substack, or
yargs which is a more comprehensive implementation of argument parsing for node
Both are battle-hardened and well supported; minimist gets about 30 million downloads a month while yargs gets nearly half that.
It's very likely you can find a way to use one or the other to get the CLI syntax you want, with the exception of env support which IMO should be handled separately (I can't imagine why you'd want to be opinionated about environment variables being set as part of the command)
While you could use raw regular expressions, but what you're building is called a tokenizer. The reason you'd want a tokenizer is to handle certain contexts such as strings that contain spaces, which you don't want to split on.
There are existing generic libraries out there specifically designed for doing parsing and tokenization and can handle cases like strings, blocks, etc.
https://www.npmjs.com/package/js-parse
Additionally, most of these command line formats and config file formats already have parsers/tokenizers. You might want to leverage those and then normalize the results from each into your object structure.
A regular expression could match your command line...
^\s*(?:((?:(?:"(?:\\.|[^"])*")|(?:'[^']*')|(?:\\.)|\S)+)\s*)$
... but you wouldn't be able to extract individual words. Instead, you need to match the next word and accumulate it into a command line.
function parse_cmdline(cmdline) {
var re_next_arg = /^\s*((?:(?:"(?:\\.|[^"])*")|(?:'[^']*')|\\.|\S)+)\s*(.*)$/;
var next_arg = ['', '', cmdline];
var args = [];
while (next_arg = re_next_arg.exec(next_arg[2])) {
var quoted_arg = next_arg[1];
var unquoted_arg = "";
while (quoted_arg.length > 0) {
if (/^"/.test(quoted_arg)) {
var quoted_part = /^"((?:\\.|[^"])*)"(.*)$/.exec(quoted_arg);
unquoted_arg += quoted_part[1].replace(/\\(.)/g, "$1");
quoted_arg = quoted_part[2];
} else if (/^'/.test(quoted_arg)) {
var quoted_part = /^'([^']*)'(.*)$/.exec(quoted_arg);
unquoted_arg += quoted_part[1];
quoted_arg = quoted_part[2];
} else if (/^\\/.test(quoted_arg)) {
unquoted_arg += quoted_arg[1];
quoted_arg = quoted_arg.substring(2);
} else {
unquoted_arg += quoted_arg[0];
quoted_arg = quoted_arg.substring(1);
}
}
args[args.length] = unquoted_arg;
}
return args;
}

Convert ObjectID (Mongodb) to String in JavaScript

I want to convert ObjectID (Mongodb) to String in JavaScript.
When I get a Object form MongoDB. it like as a object has: timestamp, second, inc, machine.
I can't convert to string.
Try this:
objectId.str
See the doc.
ObjectId() has the following attribute and methods:
[...]
str - Returns the hexadecimal string representation of the object.
in the shell
ObjectId("507f191e810c19729de860ea").str
in js using the native driver for node
objectId.toHexString()
Here is a working example of converting the ObjectId in to a string
> a=db.dfgfdgdfg.findOne()
{ "_id" : ObjectId("518cbb1389da79d3a25453f9"), "d" : 1 }
> a['_id']
ObjectId("518cbb1389da79d3a25453f9")
> a['_id'].toString // This line shows you what the prototype does
function () {
return "ObjectId(" + tojson(this.str) + ")";
}
> a['_id'].str // Access the property directly
518cbb1389da79d3a25453f9
> a['_id'].toString()
ObjectId("518cbb1389da79d3a25453f9") // Shows the object syntax in string form
> ""+a['_id']
518cbb1389da79d3a25453f9 // Gives the hex string
Did try various other functions like toHexString() with no success.
You can use $toString aggregation introduced in mongodb version 4.0 which converts the ObjectId to string
db.collection.aggregate([
{ "$project": {
"_id": { "$toString": "$your_objectId_field" }
}}
])
Use toString:
var stringId = objectId.toString()
Works with the latest Node MongoDB Native driver (v3.0+):
http://mongodb.github.io/node-mongodb-native/3.0/
Acturally, you can try this:
> a['_id']
ObjectId("518cbb1389da79d3a25453f9")
> a['_id'] + ''
"518cbb1389da79d3a25453f9"
ObjectId object + String will convert to String object.
If someone use in Meteorjs, can try:
In server: ObjectId(507f191e810c19729de860ea)._str.
In template: {{ collectionItem._id._str }}.
Assuming the OP wants to get the hexadecimal string value of the ObjectId, using Mongo 2.2 or above, the valueOf() method returns the representation of the object as a hexadecimal string. This is also achieved with the str property.
The link on anubiskong's post gives all the details, the danger here is to use a technique which has changed from older versions e.g. toString().
In Javascript, String() make it easy
const id = String(ObjectID)
this works, You have mongodb object: ObjectId(507f191e810c19729de860ea),
to get string value of _id, you just say
ObjectId(507f191e810c19729de860ea).valueOf();
In Js do simply: _id.toString()
For example:
const myMongoDbObjId = ObjectID('someId');
const strId = myMongoDbObjId.toString();
console.log(typeof strId); // string
You can use string formatting.
const stringId = `${objectId}`;
toString() method gives you hex String which is kind of ascii code but in base 16 number system.
Converts the id into a 24 character hex string for printing
For example in this system:
"a" -> 61
"b" -> 62
"c" -> 63
So if you pass "abc..." to get objectId you will get "616263...".
As a result if you want to get readable string(char string) from objectId you have to convert it(hexCode to char).
To do this I wrote an utility function hexStringToCharString()
function hexStringToCharString(hexString) {
const hexCodeArray = [];
for (let i = 0; i < hexString.length - 1; i += 2) {
hexCodeArray.push(hexString.slice(i, i + 2));
}
const decimalCodeArray = hexCodeArray.map((hex) => parseInt(hex, 16));
return String.fromCharCode(...decimalCodeArray);
}
and there is usage of the function
import { ObjectId } from "mongodb";
const myId = "user-0000001"; // must contains 12 character for "mongodb": 4.3.0
const myObjectId = new ObjectId(myId); // create ObjectId from string
console.log(myObjectId.toString()); // hex string >> 757365722d30303030303031
console.log(myObjectId.toHexString()); // hex string >> 757365722d30303030303031
const convertedFromToHexString = hexStringToCharString(
myObjectId.toHexString(),
);
const convertedFromToString = hexStringToCharString(myObjectId.toString());
console.log(`convertedFromToHexString:`, convertedFromToHexString);
//convertedFromToHexString: user-0000001
console.log(`convertedFromToString:`, convertedFromToString);
//convertedFromToHexString: user-0000001
And there is also TypeScript version of hexStringToCharString() function
function hexStringToCharString(hexString: string): string {
const hexCodeArray: string[] = [];
for (let i = 0; i < hexString.length - 1; i += 2) {
hexCodeArray.push(hexString.slice(i, i + 2));
}
const decimalCodeArray: number[] = hexCodeArray.map((hex) =>
parseInt(hex, 16),
);
return String.fromCharCode(...decimalCodeArray);
}
Just use this : _id.$oid
And you get the ObjectId string. This come with the object.
Found this really funny but it worked for me:
db.my_collection.find({}).forEach((elm)=>{
let value = new String(elm.USERid);//gets the string version of the ObjectId which in turn changes the datatype to a string.
let result = value.split("(")[1].split(")")[0].replace(/^"(.*)"$/, '$1');//this removes the objectid completely and the quote
delete elm["USERid"]
elm.USERid = result
db.my_collection.save(elm)
})
On aggregation use $addFields
$addFields: {
convertedZipCode: { $toString: "$zipcode" }
}
Documentation of v4 (right now it's latest version) MongoDB NodeJS Driver says: Method toHexString() of ObjectId returns the ObjectId id as a 24 character hex string representation.
In Mongoose, you can use toString() method on ObjectId to get a 24-character hexadecimal string.
Mongoose documentation
Below three methods can be used to get the string version of id.
(Here newUser is an object containing the data to be stored in the mongodb document)
newUser.save((err, result) => {
if (err) console.log(err)
else {
console.log(result._id.toString()) //Output - 23f89k46546546453bf91
console.log(String(result._id)) //Output - 23f89k46546546453bf91
console.log(result._id+"") //Output - 23f89k46546546453bf91
}
});
Use this simple trick, your-object.$id
I am getting an array of mongo Ids, here is what I did.
jquery:
...
success: function (res) {
console.log('without json res',res);
//without json res {"success":true,"message":" Record updated.","content":[{"$id":"58f47254b06b24004338ffba"},{"$id":"58f47254b06b24004338ffbb"}],"dbResponse":"ok"}
var obj = $.parseJSON(res);
if(obj.content !==null){
$.each(obj.content, function(i,v){
console.log('Id==>', v.$id);
});
}
...
You could use String
String(a['_id'])
If you're using Mongoose along with MongoDB, it has a built-in method for getting the string value of the ObjectID. I used it successfully to do an if statement that used === to compare strings.
From the documentation:
Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an id getter added to your schema, you may disable it by passing this option at schema construction time.

Categories

Resources