为什么使用 Newtonsoft 在 JSON 中反序列化字符串化 JSON 模式时出错?

Why an Error Deserializing Stringified JSON Schema in JSON with Newtonsoft?

提问人:cyclingLinguist 提问时间:10/5/2023 更新时间:10/5/2023 访问量:69

问:

我正在从表示 ChaptGPT api 请求中的函数的客户端接收数据,可在此处查看:https://platform.openai.com/docs/api-reference/chat/create

我希望收到的 JSON 由 Newtonsoft.Json 解析,然后在 JSON 解析期间进行 JSchema 解析,但似乎 JSchema 解析可能在正常的 JSON 解析之前发生,并且具有讽刺意味的是,我的属性被 JSchema 解析忽略了。[JsonIgnore]

以下是我的主要问题:

  • 为什么在下面的for循环中处理会导致错误?json1
  • 当 ParametersJson 的类型为字符串时,为什么 JSchema 解析器需要对象或布尔值?
  • 难道没有一种实用的方法可以像我一样对 JSON 进行编码,并按照我的期望对其进行全部反序列化,而不会出错吗?我想在客户端上将 JSON 架构表示为字符串。json1

这是错误:Unhandled exception. Newtonsoft.Json.Schema.JSchemaReaderException: Unexpected token encountered when reading schema. Expected StartObject, Boolean, got String. Path 'parameters', line 7, position 9. at Newtonsoft.Json.Schema.Infrastructure.JSchemaReader.EnsureToken(JsonReader reader, String name, List`1 tokenTypes, String errorMessage)

下面是 .NET Fiddle:https://dotnetfiddle.net/GE8OMP

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Schema;

public class Program
{
    public static void Main()
    {
        string json0 = @"
{
    'Name': 'TestFunction',
    'Description': 'This is a test function.',
    'parameters': 
    {
        'type': 'object', 
        'properties': 
        {
            'prop1': 
            {
                'type': 'string'
            }
        }
    }
}".Replace("'", "\"");
        string json1 = @"
{
    'Name': 'TestFunction',
    'Description': 'This is a test function.',
    'parameters': 
    '{
        'type': 'object', 
        'properties': 
        {
            'prop1': 
            {
                'type': 'string'
            }
        }
    }'
}".Replace("'", "\"");
        var arr = new[]{json0, json1};
        foreach (var json in arr)
        {
            Function deserializedFunction = JsonConvert.DeserializeObject<Function>(json);
            Console.WriteLine($"Name: {deserializedFunction.Name}");
            Console.WriteLine($"Description: {deserializedFunction.Description}");
            Console.WriteLine($"Parameters: {deserializedFunction.Parameters}");
            Console.WriteLine("-------------");
        }
    }
}

#nullable enable
public class Function
{
    /// <summary>
    /// The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// A description of what the function does, used by the model to choose when and how to call the function.
    /// </summary>
    public string? Description { get; set; }

    /// <summary>
    /// The parameters the functions accepts, described as a JSON Schema object.
    /// <br></br>
    /// <br></br>
    /// To describe a function that accepts no parameters, provide the value {"type": "object", "properties": { } }.
    /// </summary>
     // Need to convert from string coming from client to the JSchema object.
    [JsonIgnore]
    public JSchema Parameters { get; set; }

    [JsonProperty("parameters")]
    public string ParametersJson { get => Parameters.ToString(); set => Parameters = JSchema.Parse(value); }

    public Function(string name, string? description, JSchema parameters)
    {
        Name = name;
        Description = description;
        Parameters = parameters;
    }
}
C# JSON 序列化 json.net jsonschema

评论

0赞 Yong Shun 10/5/2023
在第二个 JSON 中,该值是一个字符串。听起来你想反序列化 的 JSON 字符串 成 ?parametersparametersJsonSchema

答:

1赞 Serge 10/5/2023 #1

恕我直言,您需要修复 json1

    string json1 = @"
{
    'Name': 'TestFunction',
    'Description': 'This is a test function.',
    'parameters': 
    '{
        'type': 'object', 
        'properties': 
        {
            'prop1': 
            {
                'type': 'string'
            }
        }
    }'
}".Replace("'{", "{").Replace("}'", "}").Replace("'", "\"");
1赞 Yong Shun 10/5/2023 #2

第一件事是你的第二个JSON无效:

  1. 值中的引号需要转义 ()。parameters\"

  2. 字符串值不能在 JSON 中包含多行。

正确的 JSON 应为:

{
    "Name": "TestFunction",
    "Description": "This is a test function.",
    "parameters": "{\"type\": \"object\", \"properties\": {\"prop1\": {\"type\": \"string\"}}}"
}

假设你已经修复了JSON问题,对于构造函数,你应该用多种类型来处理:parameters

  1. 在构造函数中将类型更改为 以允许多种类型的值。parametersJToken

  2. 处理不同的 (, )。parameters.TypeJTokenTypeStringObject

public Function(string name, string? description, JToken parameters)
{
    Name = name;
    Description = description;
        
    if (parameters.Type == JTokenType.String)
    {
        Parameters = JSchema.Parse(parameters.ToString());
    }
    else if (parameters.Type == JTokenType.Object)
    {
        Parameters = parameters.ToObject<JSchema>();
    }
}

注意,处理不同的语句也可以简化为:if-elseJTokenType

Parameters = JSchema.Parse(parameters.ToString());

评论

0赞 Yong Shun 10/5/2023
演示 @ .NET Fiddle