如题,我想在 Excel 中显示如下 JSON 数据集( Python 写的 API 接口)
{
"msg": "success",
"state": 10000,
"data": {
"data": [
{
"index": 0,
"test_1": 110,
"test_2": "000001",
"test_3": "CN",
"test_4": "Bank",
"test_5": 893,
"test_6": 229
}
],
"schema": {
"fields": [
{
"type": "integer",
"name": "index"
},
{
"type": "string",
"name": "test_1"
},
{
"type": "string",
"name": "test_2"
},
{
"type": "number",
"name": "test_3"
},
{
"type": "number",
"name": "test_4"
},
{
"type": "number",
"name": "test_5"
},
{
"type": "string",
"name": "test_6"
}
],
"pandas_version": "0.20.0",
"primaryKey": [
"index"
]
}
}
}
下面是我 C#的数据集代码 TestDataset.cs
:
using System;
using System.IO;
using System.Net;
using Newtonsoft.Json.Linq;
using ExcelDna.Integration;
using Excel = Microsoft.Office.Interop.Excel;
namespace Test_Atune
{
public class Request
{
Excel.Application ExcelApp = (Excel.Application)ExcelDnaUtil.Application;
public object GetDatasetFromUrl(string root, string path, string headval, Excel.Range excelAddress)
{
string historicalData= "{}";
var webConnection = new WebClient();
webConnection.Headers.Add("Host", headval);
try
{
historicalData = webConnection.DownloadString(root+path);
}
catch (WebException ex)
{
string error_str = ex.Message;
if (ex.Status.ToString() == "ConnectFailure" || ex.Status.ToString() == "Timeout")
{
root = Constant.setURL_ROOT_COMMON(root);
try
{
historicalData= webConnection.DownloadString(root + path);
}
catch (WebException ex2)
{
return "";
}
}
}
finally
{
webConnection.Dispose();
}
JObject jsonFeed = JObject.Parse(historicalData);
Excel.Range range = excelAddress;
JObject B = new JObject();
JArray data = (JArray)jsonFeed["data"]["data"];
JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"];
int rowNum = data.Count;
int colNum = columns.Count;
Excel.Range range_head = ExcelApp.Cells[range.Row + 1, range.Column];
range_head = range_head.get_Resize(1, colNum);
Excel.Range range_data = ExcelApp.Cells[range.Row + 2, range.Column];
range_data = range_data.get_Resize(rowNum, colNum);
// write header
object[,] headerData = new object[1, colNum];
for (int iCol = 0; iCol < colNum; iCol++)
{
headerData[0, iCol] = columns[iCol]["name"];
}
range_head.Value2 = headerData;
// write data
object[,] cellData = new object[rowNum, colNum];
int iRow = 0;
foreach (JObject jo in data)
{
var a = jo["test_code"];
for (int iCol = 0; iCol < colNum; iCol++)
{
if (columns[iCol]["test_1"].ToString() == "string")
{
cellData[iRow, iCol] = "'" + jo[columns[iCol]["name"].ToString()];
}
else
{
cellData[iRow, iCol] = jo[columns[iCol]["name"].ToString()];
}
}
iRow += 1;
}
range_data.Value2 = cellData;
return "Total" + rowNum.ToString() + "cells";
}
}
}
请求 Python 接口的 C#代码 request.cs
using ExcelDna.Integration;
using Excel = Microsoft.Office.Interop.Excel;
namespace Test_Atune
{
public class Dataset
{
public static string baseurl = Constant.URL_ROOT_COMMON;
public static string headval = Constant.HEADVAL_COMMON;
public static Request request = new Request();
[ExcelFunction(Category = "test", IsMacroType = true, Description = "test dataset")]
public static object TEST_DATASET(
[ExcelArgument(Description = "test_code")] string test_1,
[ExcelArgument(Description = "YYYYMMDD")] string test_2,
[ExcelArgument(Description = "YYYYMMDD")] string test_3
)
{
string parstr = @"/test_dataset/?" +
@"test_1=" + test_1 +
@"&test_2=" + test_2 +
@"&test_3=" + test_3;
ExcelReference caller = (ExcelReference)XlCall.Excel(XlCall.xlfCaller);
Excel.Range rg = caller.ToPiaRange();
return ExcelAsyncUtil.Run("TEST_DATASET",
new object[] { parstr },
() => request.GetDatasetFromUrl(Constant.URL_ROOT_COMMON, parstr, headval, rg));
}
}
}
但在这一行 JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"];
我遇到了如下报错:
System.NullReferenceException HResult=0x80004003 message=Object reference not set to an instance of an object.
Debug 后得到如下结果,是否 NewtonJson Jarray 需要判断下是否为空值?数据集不太会判别,对 C#一窍不通,求大神指点一二,非常感谢
Name: historicalData, Value:"{}"; Name: jsonFeed,Vaule:Null; Name:B,Vaule:{{}}, Name:data, Value:"null"
1
noreplay 2019-12-27 10:08:41 +08:00
感觉好像是你没等数据下载完就开始解析了。当你解析的时候,data 还是一个“{}”,里面的所有字段都是空值,所以就报错了。
|
3
minigo 2019-12-27 10:34:07 +08:00
JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"];
======> JArray columns = (JArray)jsonFeed["data"]?["schema"]?["fields"]; |
4
guolaopi 2019-12-27 10:40:16 +08:00
断点看一下 try catch 之后的 historicalData 值就知道了
|
5
noreplay 2019-12-27 10:42:37 +08:00
假如只是判断 null 的话,有一个笨方法:
代码大约是这个样子的: var feedData=(JArray)jsonFeed["data"]; if(feedData!=null){ // balabala } 不过这样子的代码很丑陋就是了。 |
6
crclz 2019-12-27 10:52:58 +08:00
不建议用 JArray JObject 实现。很容易出错。建议定义类来承载数据,再用 JsonConvert.Deserialize<T>(jsonString)解析。
|
7
forgottencoast 2019-12-27 11:14:38 +08:00
@noreplay #3 的才是正经写法,你大概不是 C#程序员。
|
8
noreplay 2019-12-27 11:15:33 +08:00
@forgottencoast 被看出来了,好尴尬。。。。。
|
9
forgottencoast 2019-12-27 11:20:41 +08:00
原因:
从你说的(JArray)jsonFeed["data"]["schema"]["fields"];这样出错, 但是上面一行没有出错,可以推断出是 schema 字段为 null,这个时候你再读取它的属性就会报空引用异常。 处理: 出现空引用异常的时候,你看一下服务端回传的 json 数据,一定是里面个别字段为空。 这次是 schema,下次可能是别的,所以你要和服务端确认哪些可能为空,你如果用到的话,可能都需要额外处理的。 |
10
elsagong OP @minigo 非常感谢,加```?```似乎真的有用,现在那行没有报错了,不过轮到```int rowNum = data.Count;
int colNum = columns.Count;```了,实在不懂 C#,可以再咨询一下您吗😂万分感谢!!!! |
11
kkkkkrua 2019-12-27 11:28:44 +08:00
JArray data = (JArray)jsonFeed["data"]["data"];
JArray columns = (JArray)jsonFeed["data"]["schema"]["fields"]; ------- JArray data = (JArray)jsonFeed["data"]?["data"] ?? new Jarray(); JArray columns = (JArray)jsonFeed["data"]?["schema"]?["fields"] ?? new JArray(); |
12
elsagong OP @kkkkkrua 再次感谢,无奈它还是会报错😂这一行``` range_head = range_head.get_Resize(1, colNum);
``` 报出的 System.Runtime.InteropServices.COMException HResult=0x800A03EC Message=异常来自 HRESULT:0x800A03EC, |
13
yefuchao 2019-12-27 13:57:50 +08:00
|
14
elsagong OP @yefuchao 感谢,我搜到了这个问题,但依然觉得是上面空值的代码问题,并非 Excel 版本的问题
|