Jump to content
ozmike

OO_JSON.UDF, JSON/path, OO, using javascript in Auto IT

Recommended Posts

ozmike

Hi

 

This UDF is for anyone who

- Object Orientated Programing ie properties and methods in autoIT

- needs standards compliant JSON,, 

- JSON.parse (read) and JSON.stringify (to text )

- Now JSONPath

wants to use dot syntax in AutoIT like you would in Javascript 

- dosen't like AutoIt arrays - full javascript arrays and objects in AutoIT! 

- knows javascript or would like to learn autoIT or vice versa.

- call javascript functions like EncodeURI

- run any javascript from autoIT !

 
Tested  IE8 - IE11.
 
v7 JSON_OO v7.zip - IE free version. ( hey microsoft ditched IE now too!) .
- No IE dependencies
- Added arrayAdd and arrayDel
- JSONPath! for searching.
- Added Keys Function - to list properties of a JSON object.
- Secure JSON parse
- Native Pure JS implementaion not a port.

Credits to Douglas Crockford's for JSON2 code and stefan.goessner for JSONPath code.

(see example file).  

 

v4  - json_oo_v4.zip.  -  use v7 (v4 may not work because of  windows updates on dec-2014. ).

v4 uses IEs JSON ,  so no ported external libraries
v4 also includes a Non - IE version of JSON no include files but no stringify and uses javascript EVal (not secure). use v7.
eg valid JSON  '{ "hello" : "world" }' invalid "{ 'hello' : 'world' }"
v4 does not have JSONPath , arrayAdd, arrayDel or keys (properties) methods - use v7

 

 

 

- enjoy

...the brakes come off Autoit . This is the smallest OO extensions for AutoIT

Object Oriented JSON 

--- using JSON to Build Objects in Native AutoIT
-- Using JSON to create objects

$oJSON = _OO_JSON_Init ( )
$jsObj = $oJSON.parse('{ "hello": "world" }')
$jsObj.hello;-> world
$oJSON.stringify( $jsObj );-> {"hello":"world"}
$jsObj.stringify();-> {"hello":"world"}

 

ARRAYS - goodbye Auto it arrays hooray

The real magic in this script is that it lets you access JSON array items by index number through dot syntax

without the need for a for-each loop. eg you can go $obj.arr.item(n) 

It does this by making javascript objects  syntax friendly to Autoit.

Also you can go $obj.arr.item("property").and   $obj.arr.property & Also $obj.arr.length (see below)  

-- Using JSON to create one dimentional array
$sJSON=[ "h1", "h2", "h3" ]
$oResult.length= 3
$oResult.item(0);-> h1

-- Using JSON to create 2 dimentional array;  

$sJSON=[[1,2],[3,4],[5,6]]
$oResult.length= 3
$oResult.item(0);-> 
$oResult.item(0).stringify();-> [1,2]
$oResult.item(2).item(1);-> 6
$oResult.item(2).length;-> 2

-- Using JSON to create an object array 

$sJSON= [ { "card":"ace" }, {"card":"king" }]  
$oResult.length= 2
$oResult.item(0).card;-> ace

-- Using JSON to create key values   

$sJSON= { "name":"Jon" , "surname":"who" }  
$oResult.item("surname");-> who
$oResult.surname ;-> who
 

Many other benefits such as building objects using JSON text just like you would in JavaScript 

 

 

Basic OO - Properties and methods

-- Add properties to objects in AutoIT  
$jsObj.propAdd("myProp", "'x'")
$jsObj.myProp ;-> x
$jsObj.propAdd("myProp", '{ "hello": "world" }')
$jsObj.myProp.hello ;-> world

-- User Defined methods - using javascript -CASE SENSITIVE
$jsObj.methAdd("myMethod", " Function('y','return y*5') " )
$jsObj.myMethod(5) ;-> 25

 

Some people have problems on 64 bit autoIT windows with the script control...here is the work around..

'?do=embed' frameborder='0' data-embedContent>>

You will most likely have the script control ..but here it is..

 

http://www.microsoft.com/en-us/download/details.aspx?id=1949

 
--- using JSON to Build Objects in Native AutoIT  

-- Using JSON to create objects 
$oJSON = _OO_JSON_Init (  )
$jsObj = $oJSON.parse('{ "hello": "world" }')

-- Accessing Items 
$jsObj.hello;-> world
$jsObj.item("hello");-> world

-- Using Any Object to create objects 
$jsObj.stringify();-> {"hello":"world"}
$jsObj = $jsObj.parse('{ "goodbye": "world" }')
$jsObj.goodbye;-> world

-- Read JSON from a file (PC only) - untested 
$var = _OO_JSON_Read_File("jsondata.txt")
$obj = $oJSON.parse($var)

> BASIC OO (Object Oriented) programming in Auto it 

-- Compound Syntax 
$oJSON.parse( '{ "hello":"world" }' ).hello;-> world

-- assigning propeprties 
$jsObj.parse (  '{ "goodbye": "world" }')
$jsObj.goodbye ;-> world
$jsObj.goodbye = "hello" 
$jsObj.goodbye;-> hello

> OO Adding Methods and Properties in Auto it 

-- Add properties to objects in AutoIT  
$jsObj.propAdd("myProp", "'x'")
$jsObj.myProp ;-> x
$jsObj.propAdd("myProp", '{ "hello": "world" }')
$jsObj.myProp.hello ;-> world

-- User Defined methods - using javascript -CASE SENSITIVE
$jsObj.methAdd("myMethod", " Function('y','return y*5') " )
$jsObj.myMethod(5) ;-> 25

> Querying Objects 
$jsObj = $oJSON.parse('{ "hello": "world" , "Goodbye" : "World" } ')
$jsObj.type($jsObj)  ->object
$jsObj.isArray()  ->False

-- List object properties or "keys"  
$jsObj.keys($jsObj).stringify()  ->["hello","Goodbye"]

-- Querying Objects 
$jsObj = $jsObj.parse({ "hello" : "world" , "myarray" : [ "item0", 2 ,  { "jon" : "who"} ] })

> JSON path - always returns an array of matches 
$jsObj.jsonPath( "$.*").stringify() -> ["world",["item0",2,{"jon":"who"}]]
$jsObj.jsonPath( "$..hello").stringify() -> ["world"]
$jsObj.jsonPath( "$..myarray").stringify() ->[["item0",2,{"jon":"who"}]]
$jsObj.jsonPath( "$..myarray[?(@.jon)]").stringify() ->[{"jon":"who"}]
$jsObj.jsonPath( "$..myarray[?(@.jon)]").item(0).stringify() ->{"jon":"who"}

> Basic Arrays using JSON  

-- Querying Arrays 
$jsObj.myarray.stringify()           ->["item0",2,{"jon":"who"}]
$jsObj.type($jsObj.myarray)          ->object
$jsObj.myarray.isArray()             ->True
$jsObj.myarray.length                ->3
$jsObj.type($jsObj.myarray.item(0))  ->string
$jsObj.type($jsObj.myarray.item(1))  ->number
$jsObj.type($jsObj.myarray.item(2))  ->object

> Modifying Arrays using OO  

-- Empty array;  
$jsObj = $oJSON.parse('[]') 
$jsObj.stringify()  ->[]
$jsObj.isArray(  ) ->True

-- Add items;  
$jsObj.arrayAdd( 0, "test0") 
$jsObj.arrayAdd( 1, "test1")
$jsObj2 = $oJSON.parse( '{ "hello" : "world" }')
$jsObj.arrayAdd( 2, $jsObj2)
$jsObj.stringify()  ->["test0","test1",{"hello":"world"}]

-- Delete items;  
$jsObj.arrayDel( 0) 
$jsObj.stringify()  ->["test1",{"hello":"world"}]

-- Using JSON to create one dimentional array 

$sJSON=[ "h1", "h2", "h3" ]
$oResult.length= 3
$oResult.item(0);-> h1

-- Using JSON to create 2 dimentional array;  

$sJSON=[[1,2],[3,4],[5,6]]
$oResult.length= 3
$oResult.item(0);-> 
$oResult.item(0).stringify();-> [1,2]
$oResult.item(2).item(1);-> 6
$oResult.item(2).length;-> 2

-- Using JSON to create an object array 

$sJSON= [ { "card":"ace" }, {"card":"king" }]  
$oResult.length= 2
$oResult.item(0).card;-> ace

-- Using JSON to create key values   

$sJSON= { "name":"Jon" , "surname":"who" }  
$oResult.item("surname");-> who
$oResult.surname ;-> who

> Working with OO Objects 

-- assigning JSON objects in AutoIT  
$jsObj = $oJSON.parse( '{ "hello" : "world" }')
$jsObj2 = $oJSON.parse( '{}' )
$jsObj2 = $jsObj
$jsObj.hello;-> world
$jsObj2.hello;-> world

-- Assign an JSON object to a property
$jsObj = $oJSON.parse( '{ "hello" : "world" }')
$jsObj.hello ;-> world
$jsObj2.propAdd("myProp")
$jsObj2.myProp = $jsObj 
$jsObj2.myProp ;-> 
$jsObj2.myProp.stringify() ;-> {"hello":"world"}
$jsObj2.myProp.hello ;-> world

-- Using Existing JS Objects , Object must exist in the scripting object (not IE) 
$oJSON2 =$jsObj.objGet('JSON')  ; objGet is javascript eval 
$oResult = $oJSON2.parse('{ "hello":"world" }') 
$oResult.hello;-> world

> Using Javascript functions extending UDF 

-- Calling javascript standard functions 
$jsObj.jsFunAdd( "encodeURI")
$jsObj.encodeURI( 'te st'  );-> te%20st
$jsObj.protoAdd("encodeURI", " function (s) { return encodeURI(s); } " 
$jsObj.encodeURI( 'te st'  );-> te%20st

-- Calling javascript literal methods 
$str_obj = $jsObj.toObj("my string")
$str_obj.jsMethAdd( "charAt")
$str_obj.charAt( 0 );-> m
$jsObj.toObj('\"my string').charAt(0) ;-> \
$str_obj.jsFunAdd( "charAt")
$str_obj.charAt( 0 );-> m
$jsObj.jsMethAdd("toFixed" )
$jsObj.toObj(5.56789).toFixed(2) ;-> 5.57
$jsObj.jsMethAdd("concat" , 3 )
$jsObj.toObj('hello').concat( ' world', ' again ', ' and again '  ) ;-> hello world again  and again 
$jsObj.dot("\""'my string", "charAt(0)" );-> \

> depreciated syntax  

-- depreciated syntax - previous UDFs 
$jsObj = _JS_obj_create (  '{ "hello": "world" }') ; invalid "{ 'hello':'world'}" 
$jsObj.hello ;-> world
$jsObj.objToString();-> {"hello":"world"}
$jsObj.strToObject  (  '{ "goodbye": "world" }')
$jsObj.goodbye ;-> world

-- Close IE explorer.exe instance - not required anymore 
_OO_JSON_Quit (  )

-- Objects still usable after _OO_JSON_Quit closes 
$jsObj.goodbye ;-> world
 

Example script output; see example file

;  

enjoy

Edited by ozmike
  • Like 4

Share this post


Link to post
Share on other sites
ozmike

Thx dwalf 

Sorry i didn;t get back to you,  glad someone using my udf on christmas day!

 

Silly mistake on my part - must have left a duplicate  init call in during testing..it would start up 2 IEs - da!

The new version should fix this issue - i also included the IEWait as you suggested..shouldn't hurt. 

 

On finding what the 'path' to an element  - search GOOGLE for a online JSON viewer   it should let you explore your JSON.

I have now added JSOn path support..

cheers

mike

Edited by ozmike

Share this post


Link to post
Share on other sites
Shane0000

I had been using this script successfully until it just stopped working last week. Do you know what may have happened to stop your script from working for me?

When calling _OO_JSON_Init () the below line never returns.

 _IEDocWriteHTML($g_OO_JSON_oIE, $g_JS_HTML )

I grabbed the variable data for $g_JS_HTML (below) and saved it as a .html file. While loading this file in Internet Explorer I got a display from Internet Explorer 

" Internet Explorer restricted this webpage from running scripts and ActiveX controls.     [Allow blocked content] "

Also, allowing IECreate to return visible shows only a blank page, the 'allow blocked content' message never appears. Viewing the source shows the variable data of $g_JS_HTML.

IELoadWait's (inside _IEDocWriteHTML func [iE.au3]) internal timeout (5min) seems to not be in effect also. 

Further digging shows that I am stuck within a loop of IELoadWait [under Case __IEIsObjType($oObject, "document") ] where as $oTemp.document.readyState = '' indefinitely  

$iError is set to 1 in this loop and thus never hits the timeout ElseIf statement ....

 

 Internet Explorer version 11.09600.17501

Update Versions: 11.0.15 (KB3008923)

<!DOCTYPE html>   <script> Object.prototype.propAdd =function(prop, val ) { eval('this.' + prop + '=' + val )   } ;  Object.prototype.methAdd =function(meth, def ) { eval('this.' + meth + '= new ' + def )   } ;  Object.prototype.jsFunAdd =function( funname , numParams , objectTypeName ) {  var x = buildParamlist (numParams)  ;  objectTypeName = objectTypeName || 'Object';  return eval(objectTypeName + '.prototype.' + funname + ' = function(' + x + ') { return ' + funname + '(' + x + '); }'  )  } ;  function buildParamlist (numParams)   {  var x = ' p0' ; numParams = numParams || 1 ;   for (var i=1; i< numParams; i++) { x=  x + ' , ' + 'p'  + i ;  } ;  return x; } ; Object.prototype.protoAdd         =function( methName, jsFunction , objectTypeName) { objectTypeName = objectTypeName || 'Object'; eval( objectTypeName + '.prototype.' +  methName + '=' + jsFunction )};  Object.prototype.objGet       =function( s ) { return eval(s) }                ;  REM = "To get an obj $obj.objGet('JSON')  ";  Object.prototype.objToString    =function(   ) { return JSON.stringify(this) }   ;  REM = "Print out an object  ";  Object.prototype.strToObject    =function( s ) { return JSON.parse(s) }          ;  REM = "JSON String to object  ";  Object.prototype.stringify      =function(   ) { return JSON.stringify(this) }   ;  REM = "Print out an object  ";  Object.prototype.parse          =function( s ) { return JSON.parse(s) }          ;  REM = "JSON String to object  ";  Array.prototype.item            =function( i ) { return this[i] }                ;  REM = ' so that arrays can work in AutoIT obj.item(0)' ;  Object.prototype.item           =function( i ) { return this[i] }                ;  REM = "so that dynamic key values be obtained eg. obj.item('name' ) or just obj.surname "; Object.prototype.dot =function( str, jsStrFun ) { if ( typeof str == 'string' )  { return eval( '"'+  protectDoubleQuotes (str)  + '".' + jsStrFun ) } else  { return eval( ''+  str  + '.' + jsStrFun ) }  } ; function oLiteral (literal) {   this.literal  = literal; } function protectDoubleQuotes (str)   {  return str.replace(/\\/g, '\\\\').replace(/"/g,'\\"');   } Object.prototype.toObj =function( literal ) { if ( typeof literal == 'string' )  { return eval( 'new oLiteral("' + protectDoubleQuotes (literal) + '")' ) }  else {return eval( 'new oLiteral(' + literal + ')' )} } ;  Object.prototype.jsMethAdd =function( funname , numParams ) {  var x = buildParamlist (numParams)  ;   return eval('oLiteral.prototype.' + funname + ' = function(' + x + ') { return this.literal.' + funname + '(' + x + '); }'  )  } ; window.onload = function() { document.body.parse = function(json) { return JSON.parse(json); }; document.body.stringify = function(obj, space) { return JSON.stringify(obj, null, space); }}</script> <body id='JSONElem'> </body>
Edited by Shane0000

Share this post


Link to post
Share on other sites
SmOke_N

Are you using the IE-11 and the update from Dec 18th?  If so, uninstall that update until they fix their issues, they broke code all across the coding communities.

  • Like 1

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites
Shane0000

Uninstalling the update KB3025390  that was released 12/18/14 did the trick.

 

Thank you guys!

Share this post


Link to post
Share on other sites
redrider81

Great Looking UDF ozmike.  Appreciate the examples.  

I'm new to JSON, and I'm trying to automate a web service that has a rest API. I have included my dataset below. 

Question 1:  What's the situation on support for parsing nested items?

 (It's not working for me out of box). 

Question 2: Any advice regarding my data not having double quotes (see below)?

 (I see your update: eg valid JSON  '{ "hello" : "world" }' invalid "{ 'hello' : 'world' }")

 (Do I have to do fancy stringreplace() logic to add them in before parsing?)

Question 3: Can I query the json path in the nested object example below?

 (Can't find any reference in the documentation regarding "nested" or "query"). 

In xpath I could do //id[name="Group02"] which would return the id of 2. 

Thanks in advance to any input from anyone. 

Here's a sample of the output I get back from the web service: 

{"status": 200,"data":[{"id":1,"recipients":[{"addr":"some.guy@emailaddress.com","method":"email","comment":"","type":"admin"}],"name":"Group01"}{"id":2,"recipients":[{"addr":"some.guy@emailaddress.com","method":"email","comment":"","type":"admin"}],"name":"Group02"}{"id":3,"recipients":[{"addr":"some.guy@emailaddress.com","method":"email","comment":"","type":"admin"}],"name":"Group03"}],"errmsg":"OK"}

Here's the same data formatted nicely:

{
   "status": 200,
   "data": [{
      "id": 1,
      "recipients": [{
         "addr": "some.guy@emailaddress.com",
         "method": "email",
         "comment": "",
         "type": "admin"
      }],
      "name": "Group01"
   }{
      "id": 2,
      "recipients": [{
         "addr": "some.guy@emailaddress.com",
         "method": "email",
         "comment": "",
         "type": "admin"
      }],
      "name": "Group02"
   }{
      "id": 3,
      "recipients": [{
         "addr": "some.guy@emailaddress.com",
         "method": "email",
         "comment": "",
         "type": "admin"
      }],
      "name": "Group03"
   }],
   "errmsg": "OK"
}
Edited by redrider81

Share this post


Link to post
Share on other sites
mschol

Uninstalling the update KB3025390  that was released 12/18/14 did the trick.

 

Thank you guys!

 

thanks, also ran into problems with a script using this JSON library..

Share this post


Link to post
Share on other sites
ozmike

hi 

redrider81

Q1) You must have well formed json.. (GOOGLE online json parser ;)

Parse error on line 15:
... "Group01" }{ "id":
----------------------^
Expecting 'EOF', '}', ',', ']'

 

Q2) you only need double quote around strings , number will be ok. so '{ "status": 200 } is ok!

 

Q3) I'm not familiar with Xpath - but you could have a look at JSON path ( not in this UDF feel free to write a json path udf if someone else hasn't ! ) .

nested should work ok for well formed JSON see Q1, Here are some examples of nested accessing you'll have to play around !

$var = '{ "status": 200 , "recipients":[{"addr":"some.guy@emailaddress.com","method":"email","comment":"","type":"admin"}] } '
$oJSON = _OO_JSON_Init()

$jsObj = $oJSON.parse($var)
ConsoleWrite("$jsObj.hello;-> " & $jsObj.status & @CR)
ConsoleWrite("$jsObj.hello;-> " & $jsObj.recipients.item(0).addr & @CR)
ConsoleWrite("$jsObj.hello;-> " & $jsObj.item("recipients").item(0).addr & @CR)
Edited by ozmike

Share this post


Link to post
Share on other sites
redrider81

Thanks for the reply with specific examples ozmike. Now I understand that there are two different options for referencing a value using the dot notation. This would have been confusing without your specific example.  Also, the nesting does seem to be working for at least 1 level of nesting which is encouraging. I now also understand that double quotes on the array aren't required in two cases: 

1. the value is numeric

2. the value is an array of objects, in which case you use brackets to enclose the array. 

Learning a lot. 

Also, Unfortunately, writing a JSON Path UDF is beyond me because I am new to JSON, but I do believe would be helpful.  In the meantime, can I easily loop through the items in a nested array so that I can search them for a specific value and return another value at the same level?

For example: I want to get find all the recipients where "type"="admin", and add their "addr" (into an array)

In the example you provided, would it be something like this?  

For $i = 0 to Ubound($jsObj.recipients)

If $jsObj.recipients.type = "admin" Then _ArrayAdd($MyArray,$jsObj.recipients.addr)

Next

Thanks again for the UDF, and support. 

Edited by redrider81

Share this post


Link to post
Share on other sites
redrider81

Also, I fixed my JSON by adding commas on lines 15 and 27, and added a second "recipient to show the level of nesting i'm actually dealing with. 

Here is the corrected/updated JSON.

I really want to loop through and find the "id" number of the item where the name is "Group03". 

{
    "status": 200,
    "data": [{
        "id": 1,
        "recipients": [{
            "addr": "some.guy1@emailaddress.com",
            "method": "email",
            "comment": "",
            "type": "admin"
        }],
        "name": "Group01"
    },
    {
        "id": 2,
        "recipients": [{
            "addr": "some.guy2@emailaddress.com",
            "method": "email",
            "comment": "",
            "type": "admin"
        }],
        "name": "Group02"
    },
    {
        "id": 3,
        "recipients": [{
            "addr": "some.guy3data@emailaddress.com",
            "method": "email",
            "comment": "",
            "type": "admin"
        },
        {
            "addr": "some.guy3voice@emailaddress.com",
            "method": "voice",
            "comment": "",
            "type": "admin"
        }],
        "name": "Group03"
    }],
    "errmsg": "OK"
}

Share this post


Link to post
Share on other sites
ozmike

Hi 

Here is what you want, notice you can't use UBound($obj.data) - Ubound is an auto it function. I have a length property  which you can use in autoit.

$oJSON = _OO_JSON_Init()
$var = '{ "data": [{  "id": 1,   "recipients": [{   "type": "admin" }], "name": "Group01" } , {  "id": 2,   "recipients": [{ "type": "admin" }], "name": "Group03" }] }'
$jsObj = $oJSON.parse($var)


For $i = 0 to $jsObj.data.length - 1
  
   if $jsObj.data.item($i).name = "Group03" Then
      ConsoleWrite("id found ->" & $jsObj.data.item($i).id & @CR)
   endif
next 
Exit

Alternatively try this >json UDF, someone has written _JSONGet($json, "test.x.2")  for this udf. this udf is not as object oriented as mine.

The _JSONGet or similar could be ported to my UDF

;USING JSON.UDF!  create an json object to test
Local $json = _JSONDecode('{"test":{"x":[11,22,{"y":55}]}}')

;query this object
Local $result = _JSONGet($json, "test.x.2")

Share this post


Link to post
Share on other sites
redrider81

Awesome!  I will try that loop at my next opportunity. 

Indeed it would be great if someone ported those Get and Set functions to your OO_JSON.au3 UDF (which seems to be the most favorable one thus far). 

Until then, if I wanted to return an array of all group names which contain a "type":"admin", is a nested for loop that manually stores the results into an array the best way to do that?

Edited by redrider81

Share this post


Link to post
Share on other sites
ozmike

Hi

Just build up a json string for the array

["Group01","Group03"]

and then  create  array..from that.(or you could load it into an Auto it array)

 
 
I'm having a playing with json path ...be some time off..
$oJSON = _OO_JSON_Init()
$var = '{ "data": [{  "id": 1,   "recipients": [{   "type": "admin" }], "name": "Group01" } , {  "id": 2,   "recipients": [{ "type": "admin" }], "name": "Group03" }] }'
$jsObj = $oJSON.parse($var)
$array_text = "["
For $i = 0 to $jsObj.data.length - 1
  
   if $jsObj.data.item($i).recipients.item(0).type = "admin" Then
      $array_text = $array_text & """" & $jsObj.data.item($i).name & ""","
   endif
next 
$array_text = $array_text & """""]"
ConsoleWrite("array ->" & $array_text & @CR)
$jsObj = $oJSON.parse($array_text)
ConsoleWrite("$jsObj.item(1) ->" & $jsObj.item(1) & @CR)
_OO_JSON_Quit (  )
Exit
Edited by ozmike

Share this post


Link to post
Share on other sites
redrider81

1. I will be looking forward to that addition when you get some time. 

2. I will use an AutoIt Array.  CSV.au3 includes two very useful functions:  "_WriteCSV()" and "_ParseCSV()". This enables very easy importing and exporting for my programs for any data that I put into a 2-Dimensional Array (which is what i'll be doing with many of the JSON objects I am working with).  

3.  I will be spending my time figuring out the best ways to loop through all the JSON Objects at a particular level, and put their properties into an AutoIt Array so that I can then use _WriteCSV() to export.  Then my team can update the CSV, and re-import it using the reverse process. 

Thanks again for all your tremendous work with this UDF.  It really among the best I've ever seen. 

EDIT:  Step 3 appears to be much more difficult than I anticipated because there is no native way to enumerate through "all" properties of an object when you don't know their names or how many there are.  Apparently it's a feature of some languages and not others. This is my conclusion based on what I've read... can anyone confirm that this correct?

Edited by redrider81

Share this post


Link to post
Share on other sites
redrider81

I did this string and array manipulation in the meantime. To anyone trying to reference this, sorry for the lack of comments...   Also sorry I can't provide the JSON string. In theory should work for any JSON. 

In my particular JSON data, a host has normal JSON properties, and then additional properties under a "properties" object. It's not nice. If not for this, you could simply remove the second line of code. 

 

$sHostObject = $oGetHostsObject.data.hosts.item(0).stringify()
$sHostProperties = StringReplace($sHostObject,'properties":{"','') ; Remove properties":{" so that all properties appear at same level
$sHostProperties = StringReplace($sHostProperties,'{"','') ; Remove special character
$sHostProperties = StringReplace($sHostProperties,'}','') ; Remove special character

_ArrayAdd($aHostProperties,$sHostProperties,0,':',',"') ; _ArrayAdd supports a delimiter for both dimensions... worked out well. 

For $i = 0 to Ubound($aHostProperties)-1
  For $j = 0 to Ubound($aHostProperties,2)-1
    $aHostProperties[$i][$j] = StringReplace($aHostProperties[$i][$j],'"','')  ;  Clean the remaining double quotes
  Next
Next


_ArrayDisplay($aHostProperties)

Share this post


Link to post
Share on other sites
ozmike

This is how to list  properties,  tell its type or tell is its an array. 

Note , you can extend my UDF without changing code in the UDF..! see protoAdd

$oJSON = _OO_JSON_Init()
$var = '{ "data": [{  "id": 1,   "recipients": [{   "type": "admin" }], "name": "Group01" } , {  "id": 2,   "recipients": [{ "type": "admin" }], "name": "Group03" }] }'
$jsObj = $oJSON.parse($var)

$jsObj.protoAdd( "getKeys2", " function( s ) { if (typeof s == 'object') { return Object.keys(s);}   }; ")
$jsObj.protoAdd( "getType2", " function( s ) { return typeof(s); }; ")
$jsObj.protoAdd( "isArray2", " function( s ) { return Array.isArray(s); }; ")

$keys = $jsObj.getKeys2( $jsObj.item("data").item(0) )
ConsoleWrite("keys of $jsObj.item(""data"").item(0)  ->" & $keys.stringify() & @CR) ; ->["id","recipients","name"]
$value = $jsObj.isArray2( $jsObj.item("data").item(0) )
ConsoleWrite("isArray $jsObj.item(""data"").item(0) ->" & $value & @CR) ;  ->false
$type = $jsObj.getType2( $jsObj.item("data").item(0))
ConsoleWrite("type    $jsObj.item(""data"").item(0) ->" & $type   & @CR & @CR) ;  ->object

$keys = $jsObj.getKeys2( $jsObj.item("data") )
ConsoleWrite("keys of $jsObj.item(""data"")  ->" & $keys.stringify() & @CR) ;->["0","1"]?
$value = $jsObj.isArray2( $jsObj.item("data") )
ConsoleWrite("isArray $jsObj.item(""data"") ->" & $value & @CR) ;  ->true
$type = $jsObj.getType2( $jsObj.item("data"))
ConsoleWrite("type    $jsObj.item(""data"") ->" & $type & @CR  & @CR) ;  ->object

$keys = $jsObj.getKeys2( $jsObj.item("data").item(0).id )
ConsoleWrite("keys of $jsObj.item(""data"").item(0).id ->" & $keys & @CR) ; blank no keys! not an object
$type = $jsObj.getType2( $jsObj.item("data").item(0).id )
ConsoleWrite("type $jsObj.item(""data"").item(0).id  ->" & $type & @CR) ; number
$type = $jsObj.getType2( $jsObj.item("data").item(0).name )
ConsoleWrite("type $jsObj.item(""data"").item(0).name  ->" & $type & @CR) ; string


_OO_JSON_Quit (  ) 

BTW if you need to get into a autoit array maybe look at the other JSON udf i mentioned  ...as it dumps • JSON arrays are decoded “as-is” to one-dimensional AutoIt arrays

Edited by ozmike

Share this post


Link to post
Share on other sites
redrider81

Hi ozmike, 

Another challenge if you have the time.  Just when I thought I was getting good with this UDF and JSON, I found something I don't know how to do:  take an AutoIt Array, and build a JSON object array out of it.  Also, to add to the difficulty, at least one JSON property value will be an object array of it's own.  I know the other UDF's provide some JSON to Array migration functions but once again, I only want to use your UDF if possible.  Your methods are excellent, but to be honest I can still barely wrap my head around them.  Also, extending with ProtoAdd or combining with other UDF is way beyond me at this time. 

My first problem is basic, is that I can't see how to add a "Property" an array of objects when starting with an empty object.  The examples show the object items parsed upon creation.

I do this to define the structure: 

$jsObj = $oJSON.parse( '{}' )

$jsObj.propAdd("data")
$jsObj.data.propAdd("name")
$jsObj.data.propAdd("id")
$jsObj.data.propAdd("recipients")
$jsObj.data.recipients.propAdd("addr")
$jsObj.data.recipients.propAdd("method")
$jsObj.data.recipients.propAdd("comment")
$jsObj.data.recipients.propAdd("type")

.... but I don't know what to do next. I tried several things. 

 

Here's a model of the source data. I import via CSV using _ParseCSV()

#include <Array.au3>
Global $array[1][6] = [['recipientGroupName','recipientGroupId','addr','method','comment','type']]

$string='"LOW"|100|Group1|||"group"' & @CRLF & '"LOW"|100|Group2|||"group"'
$string&= @CRLF & '"MED"|200|Group4|||"group"' & @CRLF & '"MED"|200|Group5|||"group"'
$string&= @CRLF & '"HIGH"|300|Group7|||"group"' & @CRLF & '"HIGH"|300|Group8|||"group"'

_ArrayAdd($array,$string)

_ArrayDisplay($array)

Here's the JSON object I want to make from it: 

{
    "data" : [{
            "id" : 100,
            "recipients" : [{
                    "addr" : "Group1",
                    "method" : "",
                    "comment" : "",
                    "type" : "group"
                }, {
                    "addr" : "Group2",
                    "method" : "",
                    "comment" : "",
                    "type" : "group"
                }
            ],
            "name" : "Groups_LOW"
        }, {
            "id" : 200,
            "recipients" : [{
                    "addr" : "Group4",
                    "method" : "",
                    "comment" : "",
                    "type" : "group"
                }, {
                    "addr" : "Group5",
                    "method" : "",
                    "comment" : "",
                    "type" : "group"
                }
            ],
            "name" : "Groups_MED"
        }, {
            "id" : 300,
            "recipients" : [{
                    "addr" : "Group7",
                    "method" : "",
                    "comment" : "",
                    "type" : "group"
                }, {
                    "addr" : "Group8",
                    "method" : "",
                    "comment" : "",
                    "type" : "group"
                }
            ],
            "name" : "Groups_HIGH"
        }
    ]
}
Edited by redrider81

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • Chimp
      By Chimp
      The DOM allows to do anything with elements and their contents, but first we need to reach the corresponding DOM object, get it into a variable, and then we are able to modify it. *
      Well, this little tool (although it is not very nice aesthetically) allows you to get visually a "selector" usable to reference DOM objects.
      Once you have the "selector" of an element you can pass it to the javascript querySelector() function that will return a reference to that element.
      To use this tool you have to:
      1) open the web page you want to inspect into IE browser
      2) run this script (if it find more instances of IE running, it allows you to chose one)
      3) move the mouse over the browser. The "selector" of the element below the pointer is catched automatically while hovering. To copy the selector in the clipboard just right click on the element.
      As you can see, while hovering, the element pointed by the mouse is highlighted with a thin red dotted frame to allow you to better "take aim"
      when the selector is copied to the clipboard a little acoustic signal is emitted as a confirm, then you can paste it in your listing where you need it.
      I hope it can come in handy and save you time when you need to automate a site .... have fun
      #include <IE.au3> #include <GUIConstantsEx.au3> #include <GuiListBox.au3> #include <WindowsConstants.au3> #include <Misc.au3> ; for _IsPressed (23 END key) Global $hDLL = DllOpen("user32.dll") ; following global variables are automatically updated by events from the browser ; ------------------------------------------------------------------------------------- Global $g_iMouseX, $g_iMouseY ; coordinates of the mouse while mooving over the browser Global $bCopySelector = False ; becomes True when you right click on wanted element ; ------------------------------------------------------------------------------------- Global $oIE = _Get_IE() ; get IE instance to inspect If IsObj($oIE) Then $hIE = _IEPropertyGet($oIE, "hwnd") WinActivate($hIE) _InspectElements() EndIf DllClose($hDLL) Exit Func _InspectElements() ; it uses the global variable $oIE as source ; --- set IE to interact with AutoIt --- Local $oDocument Do ; wait for document Sleep(250) $oDocument = $oIE.document Until IsObj($oDocument) Local $oWindow = $oDocument.ParentWindow ; create a reference to the javascript eval method ; in the body section of the dovument $oWindow.setTimeout("document.body.JSeval = eval; ", 0) ; attach the $JSeval variable to the javascript eval method Local $JSeval Do $JSeval = Execute('$oIE.Document.body.JSeval') Until IsObj($JSeval) ; --------------------------------------------- ; Inject Javascript functions/elements to $oIE ; --------------------------------------------- ; Get the DOM path of an element (a CSS selector) ; ----------------------------------------------- ; This javascript function returns the CSS selector of the passed element. ; You can then use the returned path to get a reference to the pointed ; element by the QuerySelector() javascript function ; function copied from the following link: ; https://stackoverflow.com/questions/5728558/get-the-dom-path-of-the-clicked-a ; see answer by "Aleksandar Totic" (thanks to him) Local $sJScript = "" & _ " function getDomPath(el) {" & _ " if (!el) {" & _ " return;" & _ " }" & _ " var stack = [];" & _ " var isShadow = false;" & _ " while (el.parentNode != null) {" & _ " var sibCount = 0;" & _ " var sibIndex = 0;" & _ " for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {" & _ " var sib = el.parentNode.childNodes[i];" & _ " if ( sib.nodeName == el.nodeName ) {" & _ " if ( sib === el ) {" & _ " sibIndex = sibCount;" & _ " }" & _ " sibCount++;" & _ " }" & _ " }" & _ " var nodeName = el.nodeName.toLowerCase();" & _ " if (isShadow) {" & _ " nodeName += ""::shadow"";" & _ " isShadow = false;" & _ " }" & _ " if ( sibCount > 1 ) {" & _ " stack.unshift(nodeName + ':nth-of-type(' + (sibIndex + 1) + ')');" & _ " } else {" & _ " stack.unshift(nodeName);" & _ " }" & _ " el = el.parentNode;" & _ " if (el.nodeType === 11) {" & _ " isShadow = true;" & _ " el = el.host;" & _ " }" & _ " }" & _ " stack.splice(0,1);" & _ " return stack.join(' > ');" & _ " }" ; more infos here: https://www.kirupa.com/html5/finding_elements_dom_using_querySelector.htm ; Inject the above javascript function contained in the $sJScript variable into the document _JS_Inject($oIE, $sJScript) Local $_getDomPath ; a reference to call above function from AutoIt Do Sleep(250) $_getDomPath = $jsEval("getDomPath") Until IsObj($_getDomPath) ; ; ; Inject a DIV in the web page ; ---------------------------- ; it will be used to higligt selected element $sJScript = 'au3_div = document.createElement("div");' & _ 'au3_div.style.position = "fixed"; ' & _ 'au3_div.style.width = " 10px"; ' & _ 'au3_div.style.height = " 10px"; ' & _ 'au3_div.style.top = "0px"; ' & _ 'au3_div.style.left = "0px"; ' & _ 'au3_div.style.background = "rgba(0, 255, 0, 0.4);"; ' & _ 'au3_div.style.color = " white"; ' & _ 'au3_div.style.zIndex = "10000"; ' & _ 'au3_div.style.visibility = "hidden"; ' & _ 'document.body.appendChild(au3_div);' _JS_Inject($oIE, $sJScript) Do Sleep(250) $oMyDIV = $jsEval("au3_div") Until IsObj($oMyDIV) ; ------------------- ; hook some IE events ; ------------------- Local $oEventObjects[2], $oEventsSource $oEventsSource = $oIE.document.documentElement ; element we want catch events from ; https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa769636(v=vs.85) $oEventObjects[0] = ObjEvent($oEventsSource, "_HTMLElementEvents2_", "HTMLElementEvents2") ; https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa768283(v%3dvs.85) $oEventObjects[1] = ObjEvent($oIE, "_IEEvent_", "DWebBrowserEvents2") ; open a GUI where to show some element's properties ; -------------------------------------------------- Local $hGUIMain = GUICreate("Info", 500, 100, -1, -1, -1, $WS_EX_TOPMOST) Local $hProperties = GUICtrlCreateEdit("", 0, 0, 500, 100) GUICtrlSetFont(-1, 9, -1, -1, "Courier New") GUISetState() ;Show GUI ; -------------------------------------------------- ; --------- ; Main loop ; --------- Local $iMouseX, $iMouseY, $oElement, $oNewElement, $sSelector Local $oGotElement, $sElementInfos Local $sSaved_StyleOutline ; Loop until the user exits. While IsObj($oIE) Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop ; ---> end EndSwitch If ($g_iMouseX <> $iMouseX) Or ($g_iMouseY <> $iMouseY) Then $iMouseX = $g_iMouseX $iMouseY = $g_iMouseY ; $oElement = $oIE.document.elementFromPoint($iMouseX, $iMouseY) ; <-- this way is slower $oNewElement = $JSeval('document.elementFromPoint(' & $iMouseX & ',' & $iMouseY & ');') If $oNewElement <> $oElement Then If IsObj($oElement) Then $oElement.style.outline = $sSaved_StyleOutline $oElement = $oNewElement ; $bSelfie = False ; $iSelf_Timer = TimerInit() $sSaved_StyleOutline = $oElement.style.outline ; save original element outline style $sSelector = $_getDomPath($oElement) If $sSelector <> "" Then $oGotElement = $JSeval('document.querySelector("' & $sSelector & '");') $oGotElement.style.outline = "1px dashed red" ; mark new pointed element ; https://css-tricks.com/ $sElementInfos = "" & _ "nodeName: " & $oGotElement.nodeName & @CRLF & _ "id: " & $oGotElement.id & @CRLF & _ "---------" & @CRLF & _ $sSelector ControlSetText($hGUIMain, "", $hProperties, $sElementInfos) EndIf EndIf EndIf If $bCopySelector And ($sSelector <> "") Then ; And (TimerDiff($iSelf_Timer) > $bSelfie_Delay) Then ; ToolTip ( $sSelector, Default, Default, "", 1, 1) $oMyDIV.style.left = $oGotElement.getBoundingClientRect().left & "px" $oMyDIV.style.top = $oGotElement.getBoundingClientRect().top & "px" $oMyDIV.style.width = $oGotElement.offsetWidth & "px" $oMyDIV.style.height = $oGotElement.offsetHeight & "px" $oMyDIV.style.visibility = "visible" ; shows the green overlay DIV ClipPut($sSelector) $sElementInfos &= @CRLF & "selector copied to ClipBoard" ControlSetText($hGUIMain, "", $hProperties, $sElementInfos) Beep(2000, 50) $bCopySelector = False Sleep(250) $oMyDIV.style.visibility = "hidden" ; hides the green overlay DIV ; ToolTip('') EndIf If _IsPressed("23", $hDLL) Then ; END key pressed If IsObj($oElement) Then $oElement.style.outline = $sSaved_StyleOutline WinActivate($hGUIMain) ; WinSetState($hGUIMain, "", @SW_SHOW) $aWin = WinGetPos($hGUIMain) MouseMove($aWin[0] + $aWin[2] / 2, $aWin[1] + $aWin[3] / 2, 0) EndIf WEnd ; the end ; ------------------------------------------ For $i = 0 To UBound($oEventObjects) - 1 ; Tell IE we don't want to receive events. $oEventObjects[$i] .Stop $oEventObjects[$i] = 0 Next $oIE = 0 ; Remove IE from memory GUIDelete($hGUIMain) ; Remove GUI ; ------------------------------------------ EndFunc ;==>_InspectElements Func _Get_IE() ; Example 5 from the _IEAttach help ; Create an array of object references to all current browser instances ; The first array element will contain the number of instances found Local $aIE[1] $aIE[0] = 0 Local $i = 1, $oIEx While 1 $oIEx = _IEAttach("", "instance", $i) If @error = $_IEStatus_NoMatch Then ExitLoop ReDim $aIE[$i + 1] $aIE[$i] = $oIEx $aIE[0] = $i $i += 1 WEnd If $aIE[0] > 0 Then If $aIE[0] = 1 Then Return $aIE[1] ; only one IE is running, return this then ; ; Create a little list box to choose the IE instance from Local $hChoose_IE = GUICreate("IE Instances", 600, 350) Local $Label1 = GUICtrlCreateLabel($aIE[0] & " running Instances of IE browser found, click the one you want to attach to then click on 'ok'", 5, 5, 590, 20) Local $List1 = GUICtrlCreateList("", 5, 30, 590, 300, BitOR($LBS_STANDARD, $LBS_EXTENDEDSEL)) Local $hButton_choosed = GUICtrlCreateButton("OK", 5, 325, 590, 20) For $i = 1 To $aIE[0] GUICtrlSetData($List1, $i & ") " & _IEPropertyGet($aIE[$i], "locationurl")) Next GUISetState(@SW_SHOW) While 1 ; wait for a selection Switch GUIGetMsg() Case $GUI_EVENT_CLOSE GUIDelete($hChoose_IE) Return False Case $hButton_choosed $aSelected = _GUICtrlListBox_GetSelItems($List1) If $aSelected[0] Then GUIDelete($hChoose_IE) Return $aIE[$aSelected[1] + 1] Else MsgBox(0, "Info", "Please select an item") EndIf EndSwitch WEnd Else MsgBox(0, 'error', "Sorry" & @CRLF & @CRLF & "no running IE instances found") EndIf EndFunc ;==>_Get_IE ; this function creates a javascript script into the html document ; of the passed $oIE object using the createElement method. Func _JS_Inject($oIE, $sJScript, $bIsUrl = False) ; ; get a reference to the document object Local $objDocument = $oIE.document ; Local $oScript = $objDocument.createElement('script') ; $oScript.type = 'text/javascript' If $bIsUrl Then $oScript.src = $sJScript ; works if $sJScript is a link to a js listing (url) Else ; (https://stackoverflow.com/questions/35213147/difference-between-text-content-vs-inner-text) ; $oScript.innerText = $sJScript $oScript.TextContent = $sJScript ; works if $sJScript contains the listing itself EndIf ; $objDocument.getElementsByTagName('head').item(0).appendChild($oScript) ; $objDocument.getElementsByTagName('head').item(0).removeChild($oScript); ; EndFunc ;==>_JS_Inject ; ------------------------------------------------------------------- ; following function(s) are called by registered $oIE elements events ; ------------------------------------------------------------------- ; ; The function automatically fired by an event ; will receive as parameter an Event Obj. ; This obj has properties related to ; the object that fired the event. ; See following link: ; https://msdn.microsoft.com/en-us/library/aa703876(v=vs.85).aspx ; function called by the mousemove event ; we use this to update 2 global variables: Volatile Func _HTMLElementEvents2_onMousemove($oEvent) $g_iMouseX = $oEvent.clientX $g_iMouseY = $oEvent.clientY EndFunc ;==>_HTMLElementEvents2_onMousemove ; function called by the contextmenu event ; we use this to update 1 global variable ; and we also neutralize this event: Volatile Func _HTMLElementEvents2_onContextmenu($oEvent) $oEvent.cancelBubble = True ; event propagation cancelled $oEvent.returnValue = False ; prevent default behaviour $bCopySelector = True ; when True, selector will be copied to clipboard in main loop EndFunc ;==>_HTMLElementEvents2_onContextmenu ; https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa768280%28v%3dvs.85%29 Func _IEEvent_BeforeNavigate2($oIEpDisp, $sIEURL, $iIEFlags, $sIETargetFrameName, $sIEPostData, $iIEHeaders, $bIECancel) ;ConsoleWrite("Debug: navigate away cancelled." & @CRLF) ; https://stackoverflow.com/questions/6526876/how-to-cancel-or-dispose-current-navigation-at-webbrowser-element $oIE.stop EndFunc ;==>_IEEvent_BeforeNavigate2 Here is a simple example on how a "selector" can be used in AutoIt.
      suppose we want automate the login to the AutoIt site with our username and password.
      I've already prepared a very simple "template" where are missing some important parts without which the script can't work. Missing parts are the references to the elements of the AutoIt web page that we have to manage by our script.
      well, here is where the tool I have just posted here above comes to our help.
      follow this steps:
      1) in IE open the AutoIt site at the forum page (https://www.autoitscript.com/forum/)
      2) run the above tool (select the IE instance and/or bring it to front if needed)
      3) when the script is "ready", move the mouse over the "Existing user? Sign In" string and right click the mouse button. Doing so the "selector" of that element is copied to the clipboard. Now we can paste it in our AutoLogIt.au3 script as value of the $sSignIn variable.
      4) now click on the "Existing user? Sign In"  to open the "Sig In" session from where we will copy selectors of each of the 2 input box Username and Password, in the same way as we have already done in step 3, and paste those selectors to the $sInputUserId and $sInputPasswd variables respectively.
      5) do the same for the "Sign In" Button and paste it's selector to the $sSignInButn variable
      6) of course also fill the $sMyUserId and $sMyPasswd variables with your data.
      That's It. Run the AutoLogIt script and it should Log you on automatically to the forum.
      AutoLogIt.au3
      #include <ie.au3> $sMyUserId = "" ; <-- your userid here $sMyPasswd = "" ; <-- your password here ; set selectors here $sSignIn = "" ; <-- SigIn element selector here $sInputUserId = "" ; <-- UserId input selector here $sInputPasswd = "" ; <-- Password input selector here $sSignInButn = "" ; <-- Sig In button selector here $oIE = _IECreate("https://www.autoitscript.com/forum/") ; here is how to use the QuerySelector javascript function $hDOM_Element = $oIE.document.QuerySelector($sSignIn) ; get the "sign in" link element ; perform a click action on the above element $hDOM_Element.click() ; or _IEAction($hDOM_Element, "click") as well ; fill the username input $hDOM_Element = $oIE.document.QuerySelector($sInputUserId) $hDOM_Element.value = $sMyUserId ; fill the password input $hDOM_Element = $oIE.document.QuerySelector($sInputPasswd) $hDOM_Element.value = $sMyPasswd ; .... or also using the dot notation directly .... $oIE.document.QuerySelector($sSignInButn).click() Sleep(5000) ; this should logout $sMenu = "body > div:nth-of-type(2) > header > div > ul > li:nth-of-type(6) > a:nth-of-type(2)" $oIE.document.QuerySelector($sMenu).click() $sLogOut = "body > ul > li:nth-of-type(9) > a" $oIE.document.QuerySelector($sLogOut).click()  
    • Chimp
      By Chimp
      This is a little experiment that makes use of a "Browser Control" embedded in a GUI in order to be able to use AutoIt, HTML, JavaScript and CSS all together.
      This little toy will only work on systems with IE11.
      The purpose is to drag all the names of the scientists & drop on the right ones. (among scientists it has also infiltrated an intruder). I hope you find it entertaining.
      I've posted it here in the hope to have some suggestions on how to improve it all (I mean the interaction between Autoit Javascript html and css). Thanks
      ; this works on systems with IE11 ; ------------------------------- #include <GUIConstantsEx.au3> #include <array.au3> Global $oIE, $oDocument, $ohJS, $sDroping Global $iCorrect = 0, $iGoal = 11 Example() Exit Func Example() Local $aScientists[12][2] = _ [["Schrodinger", "Schrodinger"],["Planck", "Planck"],["Pauli", "Pauli"],["Einstein", "Einstein"], _ ["Chimp", "Chimp"],["Dirac", "Dirac"],["Heisenberg", "Heisenberg"],["Born", "Born"], _ ["De Broglie", "De_Broglie"],["Bohr", "Bohr"],["Sommerfeld", "Sommerfeld"],["", "empty"]] Local $oIE = ObjCreate("Shell.Explorer.2") ; Create a BrowserControl Local $hGUI = GUICreate("", 660, 600, 30, 30) GUICtrlCreateObj($oIE, 0, 0, 660, 600) ; Place BrowserControl on the GUI GUISetState() ;Show GUI $oIE.navigate('about:blank') ; file:///' & @ScriptDir & '\WhoIsWho.html') While Not String($oIE.readyState) = 'complete' ; wait for about:blank Sleep(100) WEnd ; this waits till the document is ready to be used (portion of code from IE.au3) While Not (String($oIE.readyState) = "complete" Or $oIE.readyState = 4) Sleep(100) WEnd While Not (String($oIE.document.readyState) = "complete" Or $oIE.document.readyState = 4) Sleep(100) WEnd $oIE.document.Write(_GetHTML()) ; inject lising directly to the HTML document: $oIE.document.close() ; close the write stream $oIE.document.execCommand("Refresh") While Not String($oIE.readyState) = 'complete' ; wait for readyState after a refresh Sleep(100) WEnd ; https://msdn.microsoft.com/en-us/library/52f50e9t(v=vs.94).aspx ; $ohJS is a reference to the javascript Global Obj ; ------------------------------------------------- $ohJS = $oIE.document.parentwindow.JSglobal $oDocument = $oIE.document Local $oTable1 = $ohJS.table1 Local $oTable2 = $ohJS.table2 _Randomize($aScientists, $oTable1) ; --- Setup events ------------ ; https://msdn.microsoft.com/en-us/library/hh801967(v=vs.85).aspx Local $aoEventObject[2] $aoEventObject[0] = ObjEvent($oTable1, "IEEvent_", "HTMLTableEvents2") $aoEventObject[1] = ObjEvent($oTable2, "IEEvent_", "HTMLTableEvents2") ; ----------------------------- ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch If $iCorrect = $iGoal Then _Goal() _Randomize($aScientists, $oTable1) $iCorrect = 0 EndIf WEnd ; the end For $i = 0 To UBound($aoEventObject) - 1 $aoEventObject[$i] .stop Next $aoEventObject = 0 ; Kill the Event Object $oIE = 0 ; Remove IE from memory (not really necessary). GUIDelete($hGUI) ; Remove GUI EndFunc ;==>Example ; --- event management zone --- ; following functions are fired by events occurred in the browser control Volatile Func IEEvent_onDragstart($oEvent) ; we save the ID of the dragged obj into the $sDroping variable ; for a later use in the drop function $sDroping = $oEvent.srcElement.ID EndFunc ;==>IEEvent_onDragstart Volatile Func IEEvent_onDragOver($oEvent) $ohJS.event.preventDefault() EndFunc ;==>IEEvent_onDragOver Volatile Func IEEvent_onDrop($oEvent) $ohJS.event.preventDefault() If $sDroping <> "" Then If $oDocument.getElementById($sDroping).innerText <> $oEvent.srcElement.innerText Then If $oEvent.srcElement.ClassName = $oDocument.getElementById($sDroping).ClassName Then $oEvent.srcElement.innerText = $oDocument.getElementById($sDroping).innerText $oDocument.getElementById($sDroping).innerText = "" $oDocument.getElementById($sDroping).draggable = False $oDocument.getElementById($sDroping).setAttribute("style") = "background-color: #80ff80;" $iCorrect += 1 Else For $i = 1 To 3 $oDocument.getElementById($sDroping).setAttribute("style") = "background-color: #ff0000;" Sleep(125) $oDocument.getElementById($sDroping).setAttribute("style") = "background-color: #ffffff;" Sleep(125) Next EndIf EndIf $sDroping = "" EndIf EndFunc ;==>IEEvent_onDrop Func _Randomize(ByRef $aScientists, ByRef $oTable) Local $iRows = ($oTable.rows.length) - 1 Local $iCols = ($oTable.rows.item(0).cells.length) - 1 Local $index _ArrayShuffle($aScientists) For $y = 0 To $iRows For $x = 0 To $iCols $index = ($y * ($iCols + 1)) + $x $oTable.rows.item($y).cells.item($x).innerText = $aScientists[$index][0] ; text $oTable.rows.item($y).cells.item($x).className = $aScientists[$index][1] ; class $oTable.rows.item($y).cells.item($x).draggable = $aScientists[$index][0] <> "" Next Next EndFunc ;==>_Randomize Func _Goal() Local $oTable1 = $ohJS.table1 ; names Local $oTable2 = $ohJS.table2 ; photos Local $iRows = ($oTable1.rows.length) Sleep(250) Local $iCols = 6 ; ($oTable1.rows.item(0).cells.length) Local $aIndex[$iRows * $iCols], $sTemp For $i = 0 To UBound($aIndex) - 1 $aIndex[$i] = $i ; + 1 Next _ArrayShuffle($aIndex) For $i = 0 To UBound($aIndex) - 1 $oTable2.rows.item(Int($aIndex[$i] / $iCols)).cells.item(Mod($aIndex[$i], $iCols)).innerText = "" $oTemp0 = $oTable2.rows $oTemp1 = $oTemp0.item(Int($aIndex[$i] / $iCols)).cells $oTemp2 = $oTemp1.item(Mod($aIndex[$i], $iCols)).getAttribute("style") $oTable2.rows.item(Int($aIndex[$i] / $iCols)).cells.item(Mod($aIndex[$i], $iCols)).setAttribute("style") = "background-color: " & _rndColor() Sleep(100); MsgBox(0,"Debug",$sTemp) $oTable2.rows.item(Int($aIndex[$i] / $iCols)).cells.item(Mod($aIndex[$i], $iCols)).setAttribute("style") = $oTemp2 Next For $x = 1 To 2 For $i = 0 To UBound($aIndex) - 1 $oTable1.rows.item(Int($aIndex[$i] / $iCols)).cells.item(Mod($aIndex[$i], $iCols)).setAttribute("style") = "background-color: " & _rndColor() Sleep(100) $oTable1.rows.item(Int($aIndex[$i] / $iCols)).cells.item(Mod($aIndex[$i], $iCols)).setAttribute("style") = "background-color: #ffffff;" Next Next EndFunc ;==>_Goal Func _rndColor() Return String("#" & Hex(Random(0, 255, 1), 2) & Hex(Random(0, 255, 1), 2) & Hex(Random(0, 255, 1), 2) & ";") EndFunc ;==>_rndColor Func _GetHTML() Local $sHTML = _ "<!DOCTYPE HTML>" & @CRLF & _ "<html>" & @CRLF & _ "<head>" & @CRLF & _ "<meta http-equiv=""X-UA-Compatible"" content=""IE=edge"" />" & @CRLF & _ " <script type=""text/javascript"">" & @CRLF & _ " var JSglobal = (1,eval)(""this"");" & @CRLF & _ " </script>" & @CRLF & _ "</head>" & @CRLF & _ "<body>" & @CRLF & _ "<h2>Who is who?</h2>" & @CRLF & _ "<p>Drag&Drop names on the right scientist</p>" & @CRLF & _ "<img src=""http://oi66.tinypic.com/2q0lue9.jpg""" & @CRLF & _ "height=""394"" width=""640""" & @CRLF & _ "style=""position: absolute; left: 10px; top: 100px;"">" & @CRLF & _ "" & @CRLF & _ "<style>" & @CRLF & _ ".target td {width: 100px; height: 160px; text-align: center; color: white; font-weight: bold; vertical-align: bottom; border: 0px solid grey;}" & @CRLF & _ ".source td {width: 100px; height: 30px; text-align: center; border: 1px solid red;}" & @CRLF & _ "</style>" & @CRLF & _ "" & @CRLF & _ "<table class=""target"" style=""position: absolute; left: 25px; top: 100px;"" id=""table2"">" & @CRLF & _ " <tr><td class=""Schrodinger""></td><td class=""Planck""></td><td class=""Pauli""></td><td class=""Einstein""></td><td class=""Chimp""></td><td class=""Dirac""></td></tr>" & @CRLF & _ " <tr><td class=""Heisenberg""></td><td class=""Born""></td><td class=""De_Broglie""></td><td class=""Bohr""></td><td class=""Sommerfeld""></td><td class=""empty""></td></tr>" & @CRLF & _ "</table>" & @CRLF & _ "" & @CRLF & _ "<table class=""source"" style=""position: absolute; left: 10px; top: 504px;"" id=""table1"">" & @CRLF & _ " <tr><td ID=""td1""></td><td ID=""td2""></td><td ID=""td3""></td><td ID=""td4"" ></td><td ID=""td5"" ></td><td ID=""td6"" ></td></tr>" & @CRLF & _ " <tr><td ID=""td7""></td><td ID=""td8""></td><td ID=""td9""></td><td ID=""td10""></td><td ID=""td11""></td><td ID=""td12""></td></tr>" & @CRLF & _ "</table>" & @CRLF & _ "</body>" & @CRLF & _ "</html>" Return $sHTML EndFunc ;==>_GetHTML  
    • Seminko
      By Seminko
      Is there a way to grab non-hardcoded but rather javascript generated data from a webpage?
      Tried a get request as well as _IEBodyReadHTML but both seem to grab the code without the javascript generated data.
      $oHTTP = ObjCreate("winhttp.winhttprequest.5.1") $oHTTP.Open("GET", "link", False) $oHTTP.Send() $oReceived = $oHTTP.ResponseText $oStatusCode = $oHTTP.Status Global $DataArray[10][5] If $oStatusCode <> 200 Then Exit MsgBox(1, "Error", "Status Code <> 200") EndIf FileWrite(@ScriptDir & "\output.txt", $oReceived) ; //////// #include <IE.au3> Local $FullLink = "link" Local $oIE = _IECreate($FullLink, 0, 0) _IELoadWait($oIE) Local $sText = _IEBodyReadHTML($oIE) FileWrite(@ScriptDir & "\output.txt", $sText)  
    • guinness
      By guinness
      Just trying out the latest version of AutoIt and thinking more functional
      #include <Array.au3> ; Example ; An example of filtering, mapping and reducing arrays, using a function reference. ; This is similiar to how it would be done in the likes of JavaScript ; i.e. more functional (declarative) than procedural (imperative) ; Filter example Local $aiFilteredBefore[] = [1, 2, 3, 50, 30, 40, 20, 30] Local $aiFilteredAfter = _ArrayFilter($aiFilteredBefore, GtrThan30) _ArrayDisplay($aiFilteredAfter, '_ArrayFilter::') ; Map example Local $aiMappedBefore[] = [1, 2, 3, 4, 5, 6, 7, 8, 9] Local $aiMappedAfter = _ArrayMap($aiMappedBefore, MultiplyByTwo) _ArrayDisplay($aiMappedAfter, '_ArrayMap::') ; Reduce example ; Sum all values in the array Local $aiReducedBefore[] = [1, 2, 3, 50, 30, 40, 20, 30] ConsoleWrite('_ArrayReduce:: ' & _ArrayReduce($aiReducedBefore, SumValues) & @CRLF) ; Passing an empty array, will return the initial value; otherwise, sets @error to 4 ; if no initial value is defined Local $aEmpty[] = [] ConsoleWrite('_ArrayReduce:: ' & _ArrayReduce($aEmpty, SumValues, 0) & @CRLF) ; Array callback functions (for the examples only) Func GtrThan30($iValue) Return $iValue > 30 EndFunc ;==>GtrThan30 Func MultiplyByTwo($iValue, $iIndex, $aiArray) ; Notice how the function is called with the optional arguments "index" and "original array" ConsoleWrite('Index:: ' & $iIndex & ', Array:: ' & _ArrayToString($aiArray) & @CRLF) Return $iValue * 2 EndFunc ;==>MultiplyByTwo Func SumValues($a, $b) Return $a + $b EndFunc ;==>SumValues ; Functions ; The callback function is invoked with fn(value, [index, [array]]) Func _ArrayFilter($avArray, $hFunc) If Not IsArray($avArray) Then ; Null is more appropriate than returning the likes of -1 or an empty array Return SetError(1, 0, Null) EndIf If Not IsFunc($hFunc) Then Return SetError(2, 0, Null) EndIf Local Const $iLength = UBound($avArray) Local $avFiltered[$iLength] If $iLength = 0 Then Return $avFiltered EndIf Local $iIndex = 0 For $i = 0 To $iLength - 1 Local $bIsFiltered = __ArrayCall($hFunc, 3, $avArray[$i], $i, $avArray) If @error Then Return SetError(@error, @extended, Null) ElseIf $bIsFiltered Then $avFiltered[$iIndex] = $avArray[$i] $iIndex += 1 EndIf Next ReDim $avFiltered[$iIndex] Return $avFiltered EndFunc ;==>_ArrayFilter ; The callback function is invoked with fn(value, [index, [array]]) Func _ArrayMap($avArray, $hFunc) If Not IsArray($avArray) Then ; Null is more appropriate than returning the likes of -1 or an empty array Return SetError(1, 0, Null) EndIf If Not IsFunc($hFunc) Then Return SetError(2, 0, Null) EndIf Local Const $iLength = UBound($avArray) Local $avMapped[$iLength] If $iLength = 0 Then Return $avMapped EndIf For $i = 0 To $iLength - 1 $avMapped[$i] = __ArrayCall($hFunc, 3, $avArray[$i], $i, $avArray) If @error Then Return SetError(@error, @extended, Null) EndIf Next Return $avMapped EndFunc ;==>_ArrayMap ; The callback function is invoked with fn(current, value, [index, [array]]) Func _ArrayReduce($avArray, $hFunc, $vInitial = Default) If Not IsArray($avArray) Then ; Null is more appropriate than returning the likes of -1 or an empty array Return SetError(1, 0, Null) EndIf If Not IsFunc($hFunc) Then Return SetError(2, 0, Null) EndIf Local $bHasInitial = @NumParams >= 3 Local $iLength = UBound($avArray) If $iLength = 0 Then If Not $bHasInitial Then Return SetError(4, 0, Null) EndIf Return $vInitial EndIf For $i = 0 To $iLength - 1 If $bHasInitial Then $vInitial = __ArrayCall($hFunc, 3, $vInitial, $avArray[$i], $i, $avArray) If @error Then Return SetError(@error, @extended, Null) EndIf Else $bHasInitial = True $vInitial = $avArray[$i] EndIf Next Return $vInitial EndFunc ;==>_ArrayReduce Func __ArrayCall($hFunc, $iError, $vArg1 = Default, $vArg2 = Default, $vArg3 = Default, $vArg4 = Default) Local Const $CALL_ERROR = 0xDEAD Local Const $CALL_EXTENDED = 0xBEEF Local $vRet = Call($hFunc, $vArg1) If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then $vRet = Call($hFunc, $vArg1, $vArg2) If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then $vRet = Call($hFunc, $vArg1, $vArg2, $vArg3) If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then $vRet = Call($hFunc, $vArg1, $vArg2, $vArg3, $vArg4) If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then ; The function exists, but there is no appropriate function signature Return SetError($iError, 0, Null) EndIf EndIf EndIf EndIf Return SetError(@error, @extended, $vRet) EndFunc ;==>__ArrayCall  
    • Chimp
      By Chimp
      An example on how to inject jQuery into a web page
      It can be useful to manage the page from AutoIt using jQuery.
      Idea from here: http://www.learningjquery.com/2009/04/better-stronger-safer-jquerify-bookmarklet
      Suggestions and improvements are welcome
      #include <ie.au3> Example() Func Example() Local $oIE = _IECreate("www.google.com") Local $jQuery = _jQuerify($oIE) MsgBox(0, "Version", "jQuery version: " & $jQuery.fn.jquery) MsgBox(0, "Example", "click ok to exit." & @CRLF & "Google logo will fade out by jQuery...") $jQuery('#hplogo').fadeOut(3000) ; jQuery will fade out the google logo EndFunc ;==>Example ; #FUNCTION# ==================================================================================================================== ; Name ..........: _jQuerify ; Description ...: ; Syntax ........: _jQuerify(Byref $oIE) ; Parameters ....: $oIE - Object variable of an InternetExplorer.Application. ; Return values .: an object variable pointing to the jQuery library ; Author ........: Chimp ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _jQuerify(ByRef $oIE) Local $jsEval, $jQuery, $otherlib = False ; create a reference to the javascript eval() function $oIE.document.parentWindow.setTimeout('document.head.eval = eval', 0) Do Sleep(250) $jsEval = Execute('$oIE.Document.head.eval') Until IsObj($jsEval) ; if jQuery is not already loaded then load it If $jsEval("typeof jQuery=='undefined'") Then ; check if the '$' (dollar) name is already in use by other library If $jsEval("typeof $=='function'") Then $otherlib = True Local $oScript = $oIE.document.createElement('script'); $oScript.type = 'text/javascript' ; If you want to load jQuery from a disk file use the following statement ; where i.e. jquery-1.9.1.js is the file containing the jQuery source ; (or also use a string variable containing the whole jQuery listing) ;~ $oScript.TextContent = FileRead(@ScriptDir & "\jquery-1.9.1.js") ; <--- from a file ; If you want to download jQuery from the web use this statement $oScript.src = 'https://code.jquery.com/jquery-latest.min.js' ; <--- from an url $oIE.document.getElementsByTagName('head').item(0).appendChild($oScript) Do Sleep(250) Until $jsEval("typeof jQuery == 'function'") EndIf Do Sleep(250) $jQuery = $jsEval("jQuery") Until IsObj($jQuery) If $otherlib Then $jsEval('jQuery.noConflict();') Return $jQuery EndFunc ;==>_jQuerify  
×