Parsing JSON files

Post your questions and problem reports here

Moderator: kfury77

Forum rules
Please try to follow these guidelines. This will help to receive faster and more accurate response.

  • Check the Support section of the corresponding product first. Chances are you will find your answer there;
  • Do not create new topics for already reported problems. Add your comments to the existing topics instead;
  • Create separate topic for each problem request. Do NOT post a number of non-related problem reports in a single topic;
  • Give your topic a meaningful title. Titles such as "A question," "Bug report" and "Help!" provide others no clue what your message is about;
  • Include the version number of the software you are using;
  • This is not an official customer support helpdesk. If you need a prompt and official response, please contact our support team directly instead. It may take a while until you receive a reply in the forum;

Parsing JSON files

Postby anderson » Fri Jun 02, 2017 8:08 am

How can I parse a JSON file via Plugin API?

Any workaround? :(
Web developer and designer. Using WeBuilder since 2014.
User avatar
anderson
 
Posts: 13
Joined: Thu Jul 02, 2015 6:48 am
Location: Venezuela

Re: Parsing JSON files

Postby Aivars » Fri Jun 02, 2017 9:11 am

I can see a few possibilities:
1) Use TChromium and parse it using the real javascript (similarly how Emmet plugin does it)
2) Write & use a command line tool for that (call it from the plugin)
3) Parse it like a string if it's a very simple plugin using pos(), copy() etc
Blumentals Software Programmer
User avatar
Aivars
Blumentals Software Developer
 
Posts: 2453
Joined: Thu Aug 22, 2002 1:40 pm
Location: Latvia

Re: Parsing JSON files

Postby pmk65 » Fri Jun 02, 2017 12:03 pm

I do it like this in one of my (unpublished) plugins:

Code: Select all
    // Parse JSON response
    SC = CreateOleObject("MSScriptControl.ScriptControl");
    SC.Language = "JScript";
    SC.AddCode("Object.prototype.getProp=function(i){return this[i]}");
    var objJson = SC.Eval("(" + xhr.responseText + ")");


Where "xhr.responseText" is the JSON data.

Then it's possible to access the result "objJson" using dot notation and the custom function "getProp" to access unnamed properties like arrays, like this:

Code: Select all
   var resObj = objJson.getProp("results");
   var len = resObj.length;

   for (var i=0;i<len;i++) {
      var item = resObj.getProp(i);
      var cdnUri = item.latest;
   }
There are 10 types of people in the world: Those who understand binary and those who don't.
User avatar
pmk65
 
Posts: 678
Joined: Sun Dec 20, 2009 9:58 pm
Location: Copenhagen, Denmark

Re: Parsing JSON files

Postby anderson » Thu Jun 08, 2017 5:20 am

Hi guys, thanks for your replies :D

I need help:

I'm writting a JSON parse library using the WeBuilder's native plugin API with the hope that It could be implemented in another plugins. Basically I have taked the first approach: parsing the JSON file with a real Javascript engine (Chromium) in a meta-json ( :mrgreen: ) , then converting it in a TStringList object, acting as an "array" (since there's no way to create custom objects in FScript, as far as I know)

The problem: apparently, there's a delay between the Chromium object and WeBuilder, so I got stranger errors:

* Sometimes the window "Parsing json file..." freezes and I have to close it manually. Even when it's programed to close automatically when the page is completely rendered.

* I can't "switch" between .json files, since only the first stays on memory, I don't know why.

* Another random errors that I can't reproduce easily
Attachments
parse_json.zip
Here's the work-in-progress plugin, with example .json files included
(4.17 KiB) Downloaded 218 times
Web developer and designer. Using WeBuilder since 2014.
User avatar
anderson
 
Posts: 13
Joined: Thu Jul 02, 2015 6:48 am
Location: Venezuela

Re: Parsing JSON files

Postby pmk65 » Thu Jun 08, 2017 9:05 am

When using WebKit/Chromium frame, there's a few things you need to be aware of.

1) It takes time opening the WebKit/Chromium frame, even if you hide it. So yo need to be sure the frame is ready before attempting to transfer data to/from Editor.
2) WebKit/Chromium frame can only transfer STRING data. So you will have to encode your data into a string format before transferring. And then decode the result when receiving.

I personally try to avoid using WebKit/Chromium frames if possible, due to these limitations. Specially after I discovered how to use "CreateOleObject()". With this you can create objects (using JScript) and then access them from FastScript. That's what the code example I posted earlier does. (You can also use "CreateOleObject()" to make XMLHttpRequest reequests etc.)

BTW: To help you with debugging of the Webkit/Chromium frame, add this function yo your WeBuilder script (Not the index.html). That will make "console.log" calls from the Webkit/Chromium frame, display the result in the WeBuilder Message window.

Code: Select all
function OnWebkitConsoleMessage(Sender, Browser, message, source, line, Res) {
   Script.Message(_t(line) + ":" + message);
}
There are 10 types of people in the world: Those who understand binary and those who don't.
User avatar
pmk65
 
Posts: 678
Joined: Sun Dec 20, 2009 9:58 pm
Location: Copenhagen, Denmark

Re: Parsing JSON files

Postby pmk65 » Fri Jun 09, 2017 11:39 am

Another way is to expose the JSON object to FastScript as described here. Like this:

Code: Select all
// load htmlfile COM object
var htmlfile = CreateOleObject("htmlfile");

// force htmlfile to load Chakra engine
htmlfile.write("<meta http-equiv='x-ua-compatible' content='IE=9' />");

// Copy htmlfile COM object's JSON object and methods into "JSON" var
var JSON = htmlfile.parentWindow.JSON;

// Unload the now unneeded COM object
htmlfile.close();

// Test string
var jsonString = "{\"foo\":\"bar\",\"arr\":[7,66,88,9,6]}";

// Parse the JSON string
var jsonObj = JSON.parse(jsonString); 

// Show value of the "foo" object
Script.Message("foo: " + _t(jsonObj.foo) );


But you can only access named objects like "foo", but not arrays like "arr" due to FastScripts has no real object support :(
jsonObj.arr.0 will fail at compiling, jsonObj.arr[0] gives an empty result as ActiveX arrays is not in same format as FastScript arrays.

Edit: Combining this with the custom getProp function from my eval method seems to work very well, and allows you to access indexed values.

Here's my ParseJson function. The JSON object is extended with two custom methods (getProp and getKeys), so keys and indexed data can be accessed from FastScript.

Code: Select all
/**
* JSON parser using "htmlfile" OLE object.
* The JSON result object is extended with two custom methods, making data fully
* accessible from FastScript. Custom methods:
*      getProp(key/index) to access properties by index or name
*      getKeys(dummy) to get list of keys
*
* @param  string   jsonStr The JSON string to parse
*
* @return mixed    variant or empty string if failure
*/
function ParseJson(jsonStr) {

   // Create htmlfile COM object
   var HFO = CreateOleObject("htmlfile"), jsonObj;

   // force htmlfile to load Chakra engine
   HFO.write("<meta http-equiv='x-ua-compatible' content='IE=9' />");

   // Add custom method to objects so data can be accessed by index and name
   HFO.write("<script type='text/javascript'>Object.prototype.getProp=function(t){return this[t]},Object.prototype.getKeys=function(){return Object.keys(this)};</script>");

   // Parse JSON string
   try jsonObj = HFO.parentWindow.JSON.parse(jsonStr);
   except jsonObj = ""; // JSON parse error

   // Unload COM object
   HFO.close();

   return jsonObj;
}


And an example function to show how to use it:
Code: Select all
function testJsonParser() {

   Script.ClearMessages;

   var jsonString = "{\"foo\":\"bar\",\"foo2\":28,\"arr\":[7,88,9,6]}";

   var jsonObj = jsonParse(jsonString);

   if (Length(jsonObj) == 0) {
      Script.Message("Parse error");
      return;
   }

   // Test of accessing keys, using custom methods getKeys and getProp
   var keys = jsonObj.getKeys(0); // Must have a dummy parameter to work.
   if (keys.length) {
      for (var r=0;r<keys.length;r++) {
         Script.Message("Key:" + keys.getProp(r));
      }
   }
   // Test of accessing data by key, using dot notation
   var foo = jsonObj.foo;
   Script.Message("foo: " + _t(foo) );

   // Test of accessing data by key, using custom getProp method
   var foo2 = jsonObj.getProp("foo2");
   Script.Message("foo2: " + _t(foo2) );

   // Test of accessing data by index, using custom getProp method
   var arr = jsonObj.getProp("arr");
   for (var k=0; k < arr.length ; k++) {
      Script.Message("arr[" + _t(k) + "]: " + _t(arr.getProp(k)) );
   }

   return;
}


You can also use this mehod as a alternative to using Webkit/Chromium frame, if you don't need the Webkit frame visible. As it is possible to run true JavaScript code through the "htmlfile" COM object.
Only requirement is that when you call the function from FastScript, the function MUST have a parameter. If not it will return the function code itself.

Example:
Code: Select all

   // Create htmlfile COM object
   var HFO = CreateOleObject("htmlfile"), res;

   // force htmlfile to load Chakra engine
   HFO.write("<meta http-equiv='x-ua-compatible' content='IE=9' />");

   // Add custom JavaScript function
   HFO.write("<script type='text/javascript'>var realJS = function(x) {return \'[\'+(x*x)+\']\';}</script>");

   // Call custom JavaScript function
   res = HFO.parentWindow.realJS(5); // Must have a parameter
   Script.Message(res);

There are 10 types of people in the world: Those who understand binary and those who don't.
User avatar
pmk65
 
Posts: 678
Joined: Sun Dec 20, 2009 9:58 pm
Location: Copenhagen, Denmark

Re: Parsing JSON files

Postby anderson » Tue Jun 13, 2017 3:00 am

Code: Select all
/**
* JSON parser using "htmlfile" OLE object.
* The JSON result object is extended with two custom methods, making data fully
* accessible from FastScript. Custom methods:
*      getProp(key/index) to access properties by index or name
*      getKeys(dummy) to get list of keys
*
* @param  string   jsonStr The JSON string to parse
*
* @return mixed    variant or empty string if failure
*/
function ParseJson(jsonStr) {

   // Create htmlfile COM object
   var HFO = CreateOleObject("htmlfile"), jsonObj;

   // force htmlfile to load Chakra engine
   HFO.write("<meta http-equiv='x-ua-compatible' content='IE=9' />");

   // Add custom method to objects so data can be accessed by index and name
   HFO.write("<script type='text/javascript'>Object.prototype.getProp=function(t){return this[t]},Object.prototype.getKeys=function(){return Object.keys(this)};</script>");

   // Parse JSON string
   try jsonObj = HFO.parentWindow.JSON.parse(jsonStr);
   except jsonObj = ""; // JSON parse error

   // Unload COM object
   HFO.close();

   return jsonObj;
}


I definitely LOVE this code because that's what I need. I think that I can even add more custom functions to the object prototype, there's a lot of possibilities :lol: , thanks a lot for sharing us this pmk!
Web developer and designer. Using WeBuilder since 2014.
User avatar
anderson
 
Posts: 13
Joined: Thu Jul 02, 2015 6:48 am
Location: Venezuela

Re: Parsing JSON files

Postby Aivars » Tue Jun 13, 2017 12:17 pm

Anderson, I think there's a bug when multiple scriptable webkits are created or subscribed to, which probably appeared when embedded Chromium was updated :( There is a workaround though, don't create the scriptable webkit every time but reuse it.

Code: Select all
if (IsNull(_jsonApiWebkitWrapper)) {
          _jsonApiWebkitWrapper = new TForm(WeBuilder);
          _jsonApiWebkitWrapper.Width    = 180;
          _jsonApiWebkitWrapper.Height   = 85;
          _jsonApiWebkitWrapper.Position = poScreenCenter;
          _jsonApiWebKit = Script.CreateScriptableWebkit(_jsonApiWebkitWrapper, Script.GetPath + "json_api/json.htm", "");
          _jsonApiWebKit.OnLoadEnd = &json_api_onload_action;
          _jsonApiWebKit.Subscribe("WebkitJsonAPI", &json_api_on_webkit_data);

          var PlaceholderLabel = new TLabel(_jsonApiWebkitWrapper);
          PlaceholderLabel.Parent = _jsonApiWebkitWrapper;
          PlaceholderLabel.Caption = "Parsing Json file...";
          PlaceholderLabel.SetBounds(15, 15, 165, 25);
        } else {
          _jsonApiWebKit.WebKit.Load(Script.GetPath + "json_api/json.htm");
        }

        _jsonApiWebkitWrapper.ShowModal;

        //delete _jsonApiWebKit;
        //delete _jsonApiWebkitWrapper;



Having said that, it's obvious that a better method to quickly fire a JavaScript function in Chromium is necessary, so I'll try to come up with something.
Blumentals Software Programmer
User avatar
Aivars
Blumentals Software Developer
 
Posts: 2453
Joined: Thu Aug 22, 2002 1:40 pm
Location: Latvia


Return to HTMLPad / Rapid CSS / Rapid PHP / WeBuilder Support

Who is online

Users browsing this forum: No registered users and 10 guests