You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中从嵌套复杂JSON提取指定字段的问题及模型优化需求

Solution to Extract Test Data from Nested JSON

First, let's fix the core issues with your current model and implement a robust way to parse the nested structure and extract the data you need.

Why Your Current Model Isn't Working

Your existing classes are too simplistic and miss key parts of the JSON structure:

  • The TestSuite class is empty, so it can't deserialize any nested test-suite or test-fixture elements.
  • The JSON uses @ prefixed properties (like @methodname) which require explicit mapping with [JsonProperty] attributes.
  • Nested test-suite elements can be either single objects or arrays—your model doesn't handle this variability.
  • You haven't defined classes for TestFixture or TestCase, which are where the methodname and fullname values live.

Step 1: Define Proper C# Models

We'll use Newtonsoft.Json (Json.NET) for deserialization since it handles complex nested structures and single/array variability well. Here are the complete model classes:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

// Converter to handle properties that can be single objects or arrays
public class SingleOrArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<T>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        return token.Type == JTokenType.Array 
            ? token.ToObject<List<T>>() 
            : new List<T> { token.ToObject<T>() };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException("Writing is not supported for this converter");
    }
}

// Base class for shared properties between TestSuite and TestFixture
public class TestContainer
{
    [JsonProperty("@id")]
    public string Id { get; set; }

    [JsonProperty("@name")]
    public string Name { get; set; }

    [JsonProperty("@fullname")]
    public string FullName { get; set; }

    [JsonProperty("@runstate")]
    public string RunState { get; set; }

    [JsonProperty("@testcasecount")]
    public string TestCaseCount { get; set; }

    [JsonProperty("properties")]
    public PropertiesContainer Properties { get; set; }
}

public class TestSuite : TestContainer
{
    [JsonProperty("test-suite")]
    [JsonConverter(typeof(SingleOrArrayConverter<TestContainer>))]
    public List<TestContainer> ChildTestContainers { get; set; }
}

public class TestFixture : TestContainer
{
    [JsonProperty("@classname")]
    public string ClassName { get; set; }

    [JsonProperty("test-case")]
    [JsonConverter(typeof(SingleOrArrayConverter<TestCase>))]
    public List<TestCase> TestCases { get; set; }
}

public class PropertiesContainer
{
    [JsonProperty("property")]
    [JsonConverter(typeof(SingleOrArrayConverter<Property>))]
    public List<Property> Properties { get; set; }
}

public class Property
{
    [JsonProperty("@name")]
    public string Name { get; set; }

    [JsonProperty("@value")]
    public string Value { get; set; }
}

public class TestCase
{
    [JsonProperty("@id")]
    public string Id { get; set; }

    [JsonProperty("@name")]
    public string Name { get; set; }

    [JsonProperty("@fullname")]
    public string FullName { get; set; }

    [JsonProperty("@methodname")]
    public string MethodName { get; set; }

    [JsonProperty("@classname")]
    public string ClassName { get; set; }

    [JsonProperty("@runstate")]
    public string RunState { get; set; }

    [JsonProperty("@seed")]
    public string Seed { get; set; }

    [JsonProperty("properties")]
    public PropertiesContainer Properties { get; set; }
}

// Root class to match the top-level JSON structure
public class TestRoot
{
    [JsonProperty("test-suite")]
    [JsonConverter(typeof(SingleOrArrayConverter<TestContainer>))]
    public List<TestContainer> TestContainers { get; set; }
}

// Class to hold the extracted data you need
public class ExtractedTestData
{
    public string MethodName { get; set; }
    public string FullName { get; set; }
    public List<Property> Properties { get; set; } = new List<Property>();
}

Step 2: Recursively Extract the Data

We'll write a helper class to traverse the nested structure and collect all the methodname, fullname, and property values:

public class TestDataExtractor
{
    public List<ExtractedTestData> ExtractAllTestData(string jsonContent)
    {
        var root = JsonConvert.DeserializeObject<TestRoot>(jsonContent);
        var extractedData = new List<ExtractedTestData>();
        
        TraverseContainers(root.TestContainers, extractedData);
        
        return extractedData;
    }

    private void TraverseContainers(List<TestContainer> containers, List<ExtractedTestData> extractedData)
    {
        if (containers == null) return;

        foreach (var container in containers)
        {
            if (container is TestSuite suite)
            {
                // Recurse into child test suites/fixtures
                TraverseContainers(suite.ChildTestContainers, extractedData);
            }
            else if (container is TestFixture fixture)
            {
                // Extract data from each test case in the fixture
                foreach (var testCase in fixture.TestCases ?? new List<TestCase>())
                {
                    var data = new ExtractedTestData
                    {
                        MethodName = testCase.MethodName,
                        FullName = testCase.FullName
                    };

                    // Add properties from the fixture
                    if (fixture.Properties?.Properties != null)
                    {
                        data.Properties.AddRange(fixture.Properties.Properties);
                    }

                    // Add properties from the test case itself
                    if (testCase.Properties?.Properties != null)
                    {
                        data.Properties.AddRange(testCase.Properties.Properties);
                    }

                    extractedData.Add(data);
                }
            }
        }
    }
}

Step 3: Use the Extractor

Here's how to use this code to read your JSON file and get the data you need:

using System.IO;

// Read your JSON file
string json = File.ReadAllText("path/to/your/test-file.json");

// Extract the data
var extractor = new TestDataExtractor();
List<ExtractedTestData> result = extractor.ExtractAllTestData(json);

// Example: Iterate over the results
foreach (var item in result)
{
    Console.WriteLine($"Method Name: {item.MethodName}");
    Console.WriteLine($"Full Name: {item.FullName}");
    Console.WriteLine("Properties:");
    foreach (var prop in item.Properties)
    {
        Console.WriteLine($"- {prop.Name}: {prop.Value}");
    }
    Console.WriteLine("---");
}

Key Notes

  • The SingleOrArrayConverter ensures that properties like test-suite and property are deserialized correctly whether they're single objects or arrays.
  • We use inheritance (TestContainer as base class) to avoid duplicating shared properties between TestSuite and TestFixture.
  • The recursive traversal ensures we don't miss any nested test cases, no matter how deep they are in the JSON structure.

内容的提问来源于stack exchange,提问作者Nightwolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:49:12