代码之家  ›  专栏  ›  技术社区  ›  surfmuggle

如何从executescript转换json数组

  •  -1
  • surfmuggle  · 技术社区  · 7 年前

    范围

    我想用selenium进行自动化的web测试并执行javascript。弦 func1 包含我的js函数并将其传递给 ExecuteScript(func1) 它返回一个如下所示的对象数组 {label:'start', time: 121} 是的。

    我想把结果 ExecuteScript 进入之内 List<timings>

    var result = jsExecutor.ExecuteScript(func1); 
    var list = (ReadOnlyCollection<object>)result;
    var timings = (List<Timing>)list;
    

    我收到了错误

     Cannot convert type 'System.Collections.ObjectModel.ReadOnlyCollection<object>' 
     to 'System.Collections.Generic.List<CoreConsoleApp.TestExecutions.Timing>' 
    

    这是Func1

    string func1= @"var t = window.performance.timing;
      var timings = [];
      timings.push({ label: 'navigationStart', time: t.navigationStart  });
      timings.push({ label: 'PageLoadTime', time: t.loadEventEnd - t.navigationStart  });
    
    return timings;" // result is an array of js-objects
    

    下面的代码是selenium部分的一个片段

     public struct Timing
     {
       public string label;
       public int time;            
     }
    
     using (var driver = new FirefoxDriver())
     {
      ...
      var jsExecutor = (IJavaScriptExecutor)driver;
      var result = jsExecutor.ExecuteScript(func1); 
      var list = (ReadOnlyCollection<object>)result;
     }
    

    问题

    硒文档指出 ExecuteScript attempts to return a List 一个数组。 func1应该返回数组 {label: string, time: number} 结果应该很容易预测 var list = (ReadOnlyCollection<object>)result 进入之内 List<string,int> timings = (List<timings>)list;

    • 如何将“system.collections.objectmodel.readonlycollection”强制转换为列表?

    更多信息

    启动Firefox var driver = new FirefoxDriver() 打开URL driver.Navigate().GoToUrl(url); 找到某个按钮 IWebElement button = driver.FindElement(By.Name("btnK")); 提交表格 button.Submit(); 提交后执行javascript 执行脚本(函数1) 并将结果写入控制台

    最重要的是工作。但是我很难将javascript转换成一个c对象列表。

    所以我的解决办法是

    var result = jsExecutor.ExecuteScript(func1); 
    var list = (ReadOnlyCollection<object>)result;
    
    foreach (object item in list)
    {   
        var timing = (Dictionary<string, object>)item;
        foreach(KeyValuePair<string, object> kvp in timing)
        {
           Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
        }                    
     }
    

    这表明:

     Key = label, Value = navigationStart
     Key = time, Value = 1529720672670
     Key = label, Value = PageLoadTime
     Key = time, Value = 1194
     Key = label, Value = DOMContentLoadedTime
     Key = time, Value = 589
     Key = label, Value = ResponseTime
    
    3 回复  |  直到 7 年前
        1
  •  1
  •   bit    7 年前

    你需要反序列化 result 进入所需的 List<Timings> 是的。

    1. 从中引用json.net包 here
    2. 反序列化 结果 (假设是 string )具体如下:

      List<Timing> timings = JsonConvert.DeserializeObject<List<Timing>>(result);

    以下是有关序列化的一些基本帮助: https://www.newtonsoft.com/json/help/html/SerializingJSON.htm

        2
  •  1
  •   teamchong    7 年前

    在返回之前尝试序列化数据。

    string func1= @"var t = window.performance.timing;
    var timings = [];
    timings.push({ label: 'navigationStart', time: t.navigationStart  });
    timings.push({ label: 'PageLoadTime', time: t.loadEventEnd - t.navigationStart  });
    
    return JSON.stringify(timings);" // result is string
    

    并使用 Json.NET

    using Newtonsoft.Json.Linq;
    
    string result = Convert.ToString(jsExecutor.ExecuteScript(func1));
    Console.Write("result = " + result);
    List<Timing> list = JToken.Parse(result).ToObject<List<Timing>>();
    Console.Write("result = " + JToken.FromObject(list));
    
    // or access using dynamic
    dynamic dynamicList = JToken.Parse(jsExecutor.ExecuteScript(func1)); 
    for (var i = 0; i < dynamicList.Count; i++) {
       Console.Write(dynamicList[i]);
    }
    
        3
  •  0
  •   surfmuggle    7 年前

    问题是 var result = jsExecutor.ExecuteScript(func1); 与预期不同。

    这个 result 看起来像 List<object>() 我创造了这个 程序:

    var dictionary1= new Dictionary<string, object>();
    
    dictionary1.Add("label", (object)"PageloadTime");
    dictionary1.Add("time", (object)"1087");    
    var dictionary2= new Dictionary<string, object>()
    { 
        {"label", (object)"DOMContentLoadedTime"},
        {"time", (object)"494"}
    };
    
    var list = new List<object>(); // this is the structure of result
    list.Add(dictionary1);
    list.Add(dictionary2);  
    list.Dump();
    

    如果你打电话 list.Dump(); 看起来是这样的:

    Output of List of dictionaries

    如您所见,该结构包含n个此类词典 Dictionary<string, object>(); 因此,我尝试了两个嵌套循环来更好地理解对象的嵌套

    Object result = jsExecutor.ExecuteScript(func1); // 
    
    var resultCollection = (ReadOnlyCollection<object>)result;       
    foreach (Dictionary<string, object> item in resultCollection)
    {
       Console.WriteLine("{0} ", item.GetType()); 
       foreach (KeyValuePair<string, object> kvp in item)
       {
         Console.WriteLine("Keys: {0} Values: {1}", kvp.Key, kvp.Value);
       }
    }
    

    最后

    // create a structure similar to result
    var list = new List<object>(); 
    list.Add(dictionary1);
    list.Add(dictionary2);  
    
    var timings = new List<Timing>();
    
    foreach (Dictionary<string, object> dict in list)
    {       
        Console.WriteLine("Label = {0}  Value ={1} "
                  , (string)dict["label"]
                  , (string)dict["time"]);
        // create a timing object
        var t = new Timing();
        t.label = (string)dict["label"];
        t.time = (string)dict["time"];
        timings.Add(t);
    }   
    

    因为有时我得到一个无效的强制转换异常 (int)dict["time"] 我将属性time从int改为string。

    更新

    正如Steven Chong建议的那样我改变了功能 func1 要返回字符串:

    public static string jsGetTiming(){
    
        // func1 is the javascript function that will get executed
        string func1= @"var t = window.performance.timing; 
        var PageLoadTime =  t.loadEventEnd - t.navigationStart;            
        var ResponseTime = t.responseEnd - t.requestStart;            
    
        var timings = 'navigationStart=' + t.navigationStart;
            timings += '|PageLoadTime=' + PageLoadTime;        
            timings += '|ResponseTime=' + ResponseTime;            
         return timings;";
    
       return func1;
    } 
    

    执行字符串 功能1 作为一个函数,你可以这样调用它

     Object result = jsExecutor.ExecuteScript(MyClass.jsGetTiming());
     // result is a string and looks like this
    result = 
     navigationStart=1534377023791|PageLoadTime=943  
       |DOMContentLoadedTime=434|ResponseTime=337
       |Response=269|DomainLookup=0
       |LoadEvent=5|UnloadEvent=8
       |DOMContentLoadedEvent=17