这是我希望能够解析的示例JSON:
[
{
"a":{
"username":"aaa",
"email":"aaa@gmail.com"
}
},
{
"b":{
"username":"bbb",
"email":"bbb@gmail.com"
}
}
]
我需要拨打getData('b', 'email')
的电话必须输出bbb@gmail.com
!
我真的很难理解如何使用System.JSON
单位,但我无法得到解决方案!我希望能够编写一个从上述JSON结构中提取特定数据的函数。到目前为止这是我的代码。在类构造函数中,我有:
var
FIds: TJSONArray;
begin
FIds := TJSONObject.ParseJSONValue({json string here}) as TJSONArray;
end;
然后,在必须返回数据的函数内部,我写了这个:
// 'name' can be 'a' or 'b' | 'data' can be 'username' or 'email'
function TTest.getData(const name, data: string): string;
var
FValue, FValueInner: TJSONValue;
begin
for FValue in Fids do
begin
if (FValue is TJSONArray) then
begin
//Here I am sure that I have a TJSONArray (which can be 'a' or 'b' from above)
end;
end;
end;
根据我上面所写的内容,我必须检查name
的值,并决定是否必须访问a
或b
中的数据。然后,一旦我选择了正确的JSON数组a
或b
,我必须选择是否要显示username
或email
字段(在内部指定) data
变量)。
我该怎么做?
这是我最近的尝试,但我真的不明白该怎么做:
... same code above ...
if (FValue is TJSONArray) then
begin
//here I want to check if the current array is a or b
if ((FValue as TJSONArray).Items[0] as TJSONValue).Value = name then
begin
Farr := TJSONObject.ParseJSONValue(((FValue as TJSONArray).Items[0] as TJSONValue).ToJSON) as TJSONArray;
try
//here I want to get the data inside username or email
for FValueInner in Farr do
Result := FValueInner.GetValue<string>(data);
finally
Farr.Free;
end;
end;
end;
Farr: TJSONArray;
和FValueInner: TJSONValue;
答案 0 :(得分:4)
您的JSON是一个对象数组,因此FIds
是包含TJSONArray
元素的TJSONObject
。这些对象的a
和b
字段本身就是对象,而不是数组。因此,枚举该数组时FValue is TJSONArray
将始终为false。
此外,(FValue as TJSONArray).Items[0] as TJSONValue).Value = name
是错误的,因为JSON对象包含名称/值对,但您忽略了名称,并且您试图枚举这些对,就好像它们是数组的元素一样不。如果要枚举对象的对,请使用TJSONObject.Count
和TJSONObject.Pairs[]
属性。但在这种情况下,这不是必需的,因为您正在寻找一个特定的名称对。 TJSONObject
为此目的拥有Values[]
属性。
TJSONObject.ParseJSONValue(((FValue as TJSONArray).Items[0] as TJSONValue).ToJSON) as TJSONArray
简直荒谬可笑。没有理由将对象转换回JSON字符串只是为了再次解析它。它已被解析过一次,你不需要再次解析它。
最后,FValueInner.GetValue<string>(data)
是错误的,因为TJSONValue
没有GetValue()
方法,更不用说使用泛型的方法了。
现在,说到这里,尝试更像这样的东西:
// 'name' can be 'a' or 'b' | 'data' can be 'username' or 'email'
function TTest.getData(const name, data: string): string;
var
FValue, FValueInner: TJSONValue;
begin
Result := '';
for FValue in Fids do
begin
if (FValue is TJSONObject) then
begin
FValueInner := TJSONObject(FValue).Values[name];
if FValueInner <> nil then
begin
if (FValueInner is TJSONObject) then
begin
FValueInner := TJSONObject(FValueInner).Values[data];
if FValueInner <> nil then
Result := FValueInner.Value;
end;
Exit;
end;
end;
end;
end;
答案 1 :(得分:1)
对于寻求这些答案的新读者。
该功能如何?如果重构JSON数据,该功能甚至更简单?
function getData(JsonString: String; User: String; Field: String): String;
var
JSonValue: TJSonValue;
JsonArray: TJSONArray;
ArrayElement: TJSonValue;
FoundValue: TJSonValue;
begin
Result :='';
// create TJSonObject from string
JsonValue := TJSonObject.ParseJSONValue(JsonString);
// get the array
JsonArray := JsonValue as TJSONArray;
// iterate the array
for ArrayElement in JsonArray do begin
FoundValue := ArrayElement.FindValue(User);
if FoundValue <> nil then begin
Result := ArrayElement.GetValue<string>(User + '.' + Field);
break;
end;
end;
end;
上面的示例JSON代码的问题在于,它使用用户名“ a”“ b”作为用户数据的 JSON键 {key:data}。这样,您就无法在数据搜索中使用GetValue(“ a”)。以不同的方式构造JSON数据使搜索过程更加容易。稍后我将举一个例子。
处理给定JSON数据的一种方法是使用 FindValue ,因此您可以检查是否具有 key 的字段strong>存在“ a”或“ b”。
FoundValue := ArrayElement.FindValue("b");
if FoundValue <> nil then begin
Result := ArrayElement.GetValue<string>("b"+ '.' + "email");
break;
关于“ 解析JSON数组”问题:将数据作为TJSonObject加载后,您可以将数据更改为TJSONArray并迭代元素。
JsonValue := TJSonObject.ParseJSONValue(JsonString);
JsonArray := JsonValue as TJSONArray;
for ArrayElement in JsonArray do begin
...
给定JSON数据的有效示例代码:
unit JsonArray1;
interface
uses System.JSON;
function getData2(JsonString: String; User: String; Field: String): String;
procedure Test1();
implementation
function getData2(JsonString: String; User: String; Field: String): String;
var
JSonValue: TJSonValue;
JsonArray: TJSONArray;
ArrayElement: TJSonValue;
FoundValue: TJSonValue;
begin
Result :='';
// create TJSonObject from string
JsonValue := TJSonObject.ParseJSONValue(JsonString);
// get the array
JsonArray := JsonValue as TJSONArray;
// iterate the array
for ArrayElement in JsonArray do begin
FoundValue := ArrayElement.FindValue(User);
if FoundValue <> nil then begin
Result := ArrayElement.GetValue<string>(User + '.' + Field);
break;
end;
end;
end;
procedure Test1();
var
DataBase: String;
EmailAddress : String;
Username: String;
begin
DataBase := '[ {"a" : {"username":"aaa","email":"aaa@gmail.com"}},' +
'{"b" : {"username":"bbb","email":"bbb@gmail.com"}} ]';
EmailAddress := getData2(DataBase, 'b', 'email');
Username := getData2(DataBase, 'a', 'username');
end;
end.
如前所述,使用适当的键重组JSON数据可使代码查找数据更加简单。由于用户数据“ a”:{},“ b”:{}之间存在一对一的关系,因此很容易引入“用户”密钥。此外,向阵列添加“用户”键也会导致所有数据都具有键。
'{"users" : [{ "user":"a", "username":"aaa","email":"aaa@gmail.com"},' +
'{ "user":"b", "username":"bbb","email":"bbb@gmail.com"}]}';
迭代用户时,现在可以将GetValue与新的“用户”键一起使用。
if ArrayElement.GetValue<String>('user') = 'b' then begin
Result := ArrayElement.GetValue<String>('email');
通过为数组提供键,您现在可以使用以下方法获取数组:
JsonArray := JsonValue.GetValue<TJSONArray>('users');
重构后的JSON数据的工作示例代码:
unit JsonArray2;
interface
uses System.JSON;
function getData2(JsonString: String; User: String; Field: String): String;
procedure Test2();
implementation
function getData2(JsonString: String; User: String; Field: String): String;
var
JSonValue: TJSonValue;
JsonArray: TJSONArray;
ArrayElement: TJSonValue;
FoundValue: TJSonValue;
begin
Result :='';
// create TJSonObject from string
JsonValue := TJSonObject.ParseJSONValue(JsonString);
// get the array
JsonArray := JsonValue.GetValue<TJSONArray>('users');
// iterate the array
for ArrayElement in JsonArray do begin
if ArrayElement.GetValue<String>('user') = User then begin
Result := ArrayElement.GetValue<String>(Field);
break;
end;
end;
end;
procedure Test2();
var
DataBase: String;
EmailAddress : String;
Username: String;
begin
DataBase := '{"users" : [{ "user":"a", "username":"aaa","email":"aaa@gmail.com"},' +
'{ "user":"b", "username":"bbb","email":"bbb@gmail.com"}]}';
EmailAddress := getData2(DataBase, 'b', 'email');
Username := getData2(DataBase, 'a', 'username');
end;
end.
答案 2 :(得分:-1)
如果您使用Alcinoe TalJsonDocument,它会很简单:
aJsonDoc := TalJsonDocU.create;
aJsonDoc.loadFromFile(...);
for i := 0 to aJsonDoc.node.childnodes.count-1 do begin
myValue := aJsonDoc.node.childNodes[i].getchildNodeValueText(['b', 'email']);
if myValue <> '' then break;
end;