Udostępnij za pośrednictwem


Jak używać modelu obiektu dokumentu JSON w programie System.Text.Json

W tym artykule pokazano, jak używać modelu obiektów dokumentów JSON (DOM) do losowego dostępu do danych w ładunku JSON.

Opcje modelu DOM w formacie JSON

Praca z dom jest alternatywą dla deserializacji w JsonSerializer przypadku:

  • Nie masz typu do deserializacji.
  • Otrzymany kod JSON nie ma stałego schematu i musi być sprawdzany, aby wiedzieć, co zawiera.

System.Text.Json Udostępnia dwa sposoby tworzenia modelu DOM w formacie JSON:

  • JsonDocument zapewnia możliwość tworzenia modelu DOM tylko do odczytu przy użyciu polecenia Utf8JsonReader. Dostęp do elementów JSON, które tworzą ładunek, można uzyskać za pośrednictwem JsonElement typu . Typ JsonElement udostępnia moduły wyliczania tablic i obiektów wraz z interfejsami API w celu konwertowania tekstu JSON na typowe typy platformy .NET. JsonDocument uwidacznia RootElement właściwość. Aby uzyskać więcej informacji, zobacz Używanie narzędzia JsonDocument w dalszej części tego artykułu.

  • JsonNode i klasy, które pochodzą z niego w System.Text.Json.Nodes przestrzeni nazw, zapewniają możliwość tworzenia modyfikowalnego modelu DOM. Dostęp do elementów JSON, które tworzą ładunek, można uzyskać za pośrednictwem JsonNodetypów , JsonObject, JsonArray, JsonValuei JsonElement . Aby uzyskać więcej informacji, zobacz Używanie JsonNode w dalszej części tego artykułu.

Podczas wybierania między elementami JsonDocument i JsonNodenależy wziąć pod uwagę następujące czynniki:

  • Dom JsonNode można zmienić po jego utworzeniu. Dom JsonDocument jest niezmienny.
  • Dom JsonDocument zapewnia szybszy dostęp do danych.

Korzystanie z polecenia JsonNode

W poniższym przykładzie pokazano, jak używać JsonNode i innych typów w przestrzeni nazw do System.Text.Json.Nodes :

  • Tworzenie modelu DOM na podstawie ciągu JSON
  • Zapis JSON z modelu DOM.
  • Pobierz wartość, obiekt lub tablicę z modelu DOM.
using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodeFromStringExample;

public class Program
{
    public static void Main()
    {
        string jsonString = """
            {
              "Date": "2019-08-01T00:00:00",
              "Temperature": 25,
              "Summary": "Hot",
              "DatesAvailable": [
                "2019-08-01T00:00:00",
                "2019-08-02T00:00:00"
              ],
              "TemperatureRanges": {
                  "Cold": {
                      "High": 20,
                      "Low": -10
                  },
                  "Hot": {
                      "High": 60,
                      "Low": 20
                  }
              }
            }
            """;
        // Create a JsonNode DOM from a JSON string.
        JsonNode forecastNode = JsonNode.Parse(jsonString)!;

        // Write JSON from a JsonNode
        var options = new JsonSerializerOptions { WriteIndented = true };
        Console.WriteLine(forecastNode!.ToJsonString(options));
        // output:
        //{
        //  "Date": "2019-08-01T00:00:00",
        //  "Temperature": 25,
        //  "Summary": "Hot",
        //  "DatesAvailable": [
        //    "2019-08-01T00:00:00",
        //    "2019-08-02T00:00:00"
        //  ],
        //  "TemperatureRanges": {
        //    "Cold": {
        //      "High": 20,
        //      "Low": -10
        //    },
        //    "Hot": {
        //      "High": 60,
        //      "Low": 20
        //    }
        //  }
        //}

        // Get value from a JsonNode.
        JsonNode temperatureNode = forecastNode!["Temperature"]!;
        Console.WriteLine($"Type={temperatureNode.GetType()}");
        Console.WriteLine($"JSON={temperatureNode.ToJsonString()}");
        //output:
        //Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
        //JSON = 25

        // Get a typed value from a JsonNode.
        int temperatureInt = (int)forecastNode!["Temperature"]!;
        Console.WriteLine($"Value={temperatureInt}");
        //output:
        //Value=25

        // Get a typed value from a JsonNode by using GetValue<T>.
        temperatureInt = forecastNode!["Temperature"]!.GetValue<int>();
        Console.WriteLine($"TemperatureInt={temperatureInt}");
        //output:
        //Value=25

        // Get a JSON object from a JsonNode.
        JsonNode temperatureRanges = forecastNode!["TemperatureRanges"]!;
        Console.WriteLine($"Type={temperatureRanges.GetType()}");
        Console.WriteLine($"JSON={temperatureRanges.ToJsonString()}");
        //output:
        //Type = System.Text.Json.Nodes.JsonObject
        //JSON = { "Cold":{ "High":20,"Low":-10},"Hot":{ "High":60,"Low":20} }

        // Get a JSON array from a JsonNode.
        JsonNode datesAvailable = forecastNode!["DatesAvailable"]!;
        Console.WriteLine($"Type={datesAvailable.GetType()}");
        Console.WriteLine($"JSON={datesAvailable.ToJsonString()}");
        //output:
        //datesAvailable Type = System.Text.Json.Nodes.JsonArray
        //datesAvailable JSON =["2019-08-01T00:00:00", "2019-08-02T00:00:00"]

        // Get an array element value from a JsonArray.
        JsonNode firstDateAvailable = datesAvailable[0]!;
        Console.WriteLine($"Type={firstDateAvailable.GetType()}");
        Console.WriteLine($"JSON={firstDateAvailable.ToJsonString()}");
        //output:
        //Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
        //JSON = "2019-08-01T00:00:00"

        // Get a typed value by chaining references.
        int coldHighTemperature = (int)forecastNode["TemperatureRanges"]!["Cold"]!["High"]!;
        Console.WriteLine($"TemperatureRanges.Cold.High={coldHighTemperature}");
        //output:
        //TemperatureRanges.Cold.High = 20

        // Parse a JSON array
        var datesNode = JsonNode.Parse(@"[""2019-08-01T00:00:00"",""2019-08-02T00:00:00""]");
        JsonNode firstDate = datesNode![0]!.GetValue<DateTime>();
        Console.WriteLine($"firstDate={ firstDate}");
        //output:
        //firstDate = "2019-08-01T00:00:00"
    }
}

Tworzenie elementu DOM JsonNode z inicjatorami obiektów i wprowadzanie zmian

W poniższym przykładzie pokazano, jak:

  • Utwórz dom przy użyciu inicjatorów obiektów.
  • Wprowadź zmiany w modelu DOM.
using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodeFromObjectExample;

public class Program
{
    public static void Main()
    {
        // Create a new JsonObject using object initializers.
        var forecastObject = new JsonObject
        {
            ["Date"] = new DateTime(2019, 8, 1),
            ["Temperature"] = 25,
            ["Summary"] = "Hot",
            ["DatesAvailable"] = new JsonArray(
                new DateTime(2019, 8, 1), new DateTime(2019, 8, 2)),
            ["TemperatureRanges"] = new JsonObject
            {
                ["Cold"] = new JsonObject
                {
                    ["High"] = 20,
                    ["Low"] = -10
                }
            },
            ["SummaryWords"] = new JsonArray("Cool", "Windy", "Humid")
        };

        // Add an object.
        forecastObject!["TemperatureRanges"]!["Hot"] =
            new JsonObject { ["High"] = 60, ["Low"] = 20 };

        // Remove a property.
        forecastObject.Remove("SummaryWords");

        // Change the value of a property.
        forecastObject["Date"] = new DateTime(2019, 8, 3);

        var options = new JsonSerializerOptions { WriteIndented = true };
        Console.WriteLine(forecastObject.ToJsonString(options));
        //output:
        //{
        //  "Date": "2019-08-03T00:00:00",
        //  "Temperature": 25,
        //  "Summary": "Hot",
        //  "DatesAvailable": [
        //    "2019-08-01T00:00:00",
        //    "2019-08-02T00:00:00"
        //  ],
        //  "TemperatureRanges": {
        //    "Cold": {
        //      "High": 20,
        //      "Low": -10
        //    },
        //    "Hot": {
        //      "High": 60,
        //      "Low": 20
        //    }
        //  }
        //}
    }
}

Deserializowanie podsekcji ładunku JSON

W poniższym przykładzie pokazano, jak za pomocą narzędzia JsonNode przejść do podsekcji drzewa JSON i deserializować pojedynczą wartość, typ niestandardowy lub tablicę z tej podsekcji.

using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodePOCOExample;

public class TemperatureRanges : Dictionary<string, HighLowTemps>
{
}

public class HighLowTemps
{
    public int High { get; set; }
    public int Low { get; set; }
}

public class Program
{
    public static DateTime[]? DatesAvailable { get; set; }

    public static void Main()
    {
        string jsonString = """
            {
              "Date": "2019-08-01T00:00:00",
              "Temperature": 25,
              "Summary": "Hot",
              "DatesAvailable": [
                "2019-08-01T00:00:00",
                "2019-08-02T00:00:00"
              ],
              "TemperatureRanges": {
                  "Cold": {
                      "High": 20,
                      "Low": -10
                  },
                  "Hot": {
                      "High": 60,
                      "Low": 20
                  }
              }
            }
            """;
        // Parse all of the JSON.
        JsonNode forecastNode = JsonNode.Parse(jsonString)!;

        // Get a single value
        int hotHigh = forecastNode["TemperatureRanges"]!["Hot"]!["High"]!.GetValue<int>();
        Console.WriteLine($"Hot.High={hotHigh}");
        // output:
        //Hot.High=60

        // Get a subsection and deserialize it into a custom type.
        JsonObject temperatureRangesObject = forecastNode!["TemperatureRanges"]!.AsObject();
        using var stream = new MemoryStream();
        using var writer = new Utf8JsonWriter(stream);
        temperatureRangesObject.WriteTo(writer);
        writer.Flush();
        TemperatureRanges? temperatureRanges = 
            JsonSerializer.Deserialize<TemperatureRanges>(stream.ToArray());
        Console.WriteLine($"Cold.Low={temperatureRanges!["Cold"].Low}, Hot.High={temperatureRanges["Hot"].High}");
        // output:
        //Cold.Low=-10, Hot.High=60

        // Get a subsection and deserialize it into an array.
        JsonArray datesAvailable = forecastNode!["DatesAvailable"]!.AsArray()!;
        Console.WriteLine($"DatesAvailable[0]={datesAvailable[0]}");
        // output:
        //DatesAvailable[0]=8/1/2019 12:00:00 AM
    }
}

Przykład średniej klasy JsonNode

Poniższy przykład wybiera tablicę JSON zawierającą wartości całkowite i oblicza średnią wartość:

using System.Text.Json.Nodes;

namespace JsonNodeAverageGradeExample;

public class Program
{
    public static void Main()
    {
        string jsonString = """
            {
              "Class Name": "Science",
              "Teacher\u0027s Name": "Jane",
              "Semester": "2019-01-01",
              "Students": [
                {
                  "Name": "John",
                  "Grade": 94.3
                },
                {
                  "Name": "James",
                  "Grade": 81.0
                },
                {
                  "Name": "Julia",
                  "Grade": 91.9
                },
                {
                  "Name": "Jessica",
                  "Grade": 72.4
                },
                {
                  "Name": "Johnathan"
                }
              ],
              "Final": true
            }
            """;
        double sum = 0;
        JsonNode document = JsonNode.Parse(jsonString)!;

        JsonNode root = document.Root;
        JsonArray studentsArray = root["Students"]!.AsArray();

        int count = studentsArray.Count;
        foreach (JsonNode? student in studentsArray)
        {
            if (student?["Grade"] is JsonNode gradeNode)
            {
                sum += (double)gradeNode;
            }
            else
            {
                sum += 70;
            }
        }

        double average = sum / count;
        Console.WriteLine($"Average grade : {average}");
    }
}
// output:
//Average grade : 81.92

Powyższy kod ma następujące działanie:

  • Oblicza średnią ocenę dla obiektów w Students tablicy, która ma Grade właściwość.
  • Przypisuje domyślną ocenę 70 dla uczniów, którzy nie mają klasy.
  • Pobiera liczbę uczniów z Count właściwości JsonArray.

JsonNode z JsonSerializerOptions

Można użyć JsonSerializer do serializacji i deserializacji wystąpienia klasy JsonNode. Jeśli jednak używasz przeciążenia, które przyjmuje JsonSerializerOptions, wystąpienie opcji jest używane tylko do pobierania konwerterów niestandardowych. Inne funkcje wystąpienia opcji nie są używane. Jeśli na przykład zostanie ustawiona JsonSerializerOptions.DefaultIgnoreCondition WhenWritingNull wartość i wywołana JsonSerializer z przeciążeniem, które przyjmuje JsonSerializerOptions, właściwości null nie zostaną zignorowane.

To samo ograniczenie dotyczy JsonNode metod, które przyjmują JsonSerializerOptions parametr : WriteTo(Utf8JsonWriter, JsonSerializerOptions) i ToJsonString(JsonSerializerOptions). Te interfejsy API używają JsonSerializerOptions tylko do pobierania konwerterów niestandardowych.

Poniższy przykład ilustruje wynik użycia metod, które przyjmują JsonSerializerOptions parametr i serializują JsonNode wystąpienie:

using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;

namespace JsonNodeWithJsonSerializerOptions;

public class Program
{
    public static void Main()
    {
        Person person = new() { Name = "Nancy" };

        // Default serialization - Address property included with null token.
        // Output: {"Name":"Nancy","Address":null}
        string personJsonWithNull = JsonSerializer.Serialize(person);
        Console.WriteLine(personJsonWithNull);

        // Serialize and ignore null properties - null Address property is omitted
        // Output: {"Name":"Nancy"}
        JsonSerializerOptions options = new()
        {
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
        };
        string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
        Console.WriteLine(personJsonWithoutNull);

        // Ignore null properties doesn't work when serializing JsonNode instance
        // by using JsonSerializer.
        // Output: {"Name":"Nancy","Address":null}
        JsonNode? personJsonNode = JsonSerializer.Deserialize<JsonNode>(personJsonWithNull);
        personJsonWithNull = JsonSerializer.Serialize(personJsonNode, options);
        Console.WriteLine(personJsonWithNull);

        // Ignore null properties doesn't work when serializing JsonNode instance
        // by using JsonNode.ToJsonString method.
        // Output: {"Name":"Nancy","Address":null}
        personJsonWithNull = personJsonNode!.ToJsonString(options);
        Console.WriteLine(personJsonWithNull);

        // Ignore null properties doesn't work when serializing JsonNode instance
        // by using JsonNode.WriteTo method.
        // Output: {"Name":"Nancy","Address":null}
        using var stream = new MemoryStream();
        using var writer = new Utf8JsonWriter(stream);
        personJsonNode!.WriteTo(writer, options);
        writer.Flush();
        personJsonWithNull = Encoding.UTF8.GetString(stream.ToArray());
        Console.WriteLine(personJsonWithNull);
    }
}

public class Person
{
    public string? Name { get; set; }
    public string? Address { get; set; }
}

Jeśli potrzebujesz funkcji JsonSerializerOptions innych niż konwertery niestandardowe, użyj z JsonSerializer silnie typinymi obiektami docelowymi (takimi jak Person klasa w tym przykładzie), a nie JsonNode.

Manipulowanie kolejnością właściwości

JsonObject jest jednym z elementów w ładunku elementu JsonNode, który reprezentuje modyfikowalny obiekt JSON. Mimo że typ jest modelowany jako IDictionary<string, JsonNode>element , gdzie każdy wpis jest właściwością obiektu, hermetyzuje niejawną kolejność właściwości. Jednak interfejsy API, takie jak Insert(Int32, String, JsonNode) i RemoveAt(Int32) skutecznie modeluje typ jako uporządkowany słownik, umożliwiając wstawianie i usuwanie elementów w określonym indeksie. Te interfejsy API umożliwiają modyfikacje wystąpień obiektów, które mogą mieć bezpośredni wpływ na kolejność właściwości.

Poniższy kod przedstawia przykład dodawania lub przenoszenia określonej właściwości na początek obiektu.

var schema = (JsonObject)JsonSerializerOptions.Default.GetJsonSchemaAsNode(typeof(MyPoco));

JsonNode? idValue;
switch (schema.IndexOf("$id"))
{
    // $id property missing.
    case < 0:
        idValue = (JsonNode)"https://example.com/schema";
        schema.Insert(0, "$id", idValue);
        break;

    // $id property already at the start of the object.
    case 0:
        break;

    // $id exists but not at the start of the object.
    case int index:
        idValue = schema[index];
        schema.RemoveAt(index);
        schema.Insert(0, "$id", idValue);
        break;
}

Porównanie węzłów JsonNodes

Aby porównać dwa JsonNode obiekty pod kątem równości, w tym ich elementy potomne, użyj JsonNode.DeepEquals(JsonNode, JsonNode) metody .

Korzystanie z polecenia JsonDocument

W poniższym przykładzie pokazano, jak używać JsonDocument klasy do losowego dostępu do danych w ciągu JSON:

double sum = 0;
int count = 0;

using (JsonDocument document = JsonDocument.Parse(jsonString))
{
    JsonElement root = document.RootElement;
    JsonElement studentsElement = root.GetProperty("Students");
    foreach (JsonElement student in studentsElement.EnumerateArray())
    {
        if (student.TryGetProperty("Grade", out JsonElement gradeElement))
        {
            sum += gradeElement.GetDouble();
        }
        else
        {
            sum += 70;
        }
        count++;
    }
}

double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
    Dim root As JsonElement = document.RootElement
    Dim studentsElement As JsonElement = root.GetProperty("Students")
    For Each student As JsonElement In studentsElement.EnumerateArray()
        Dim gradeElement As JsonElement = Nothing
        If student.TryGetProperty("Grade", gradeElement) Then
            sum += gradeElement.GetDouble()
        Else
            sum += 70
        End If
        count += 1
    Next
End Using

Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")

Powyższy kod ma następujące działanie:

  • Przyjęto założenie, że kod JSON do analizy znajduje się w ciągu o nazwie jsonString.
  • Oblicza średnią ocenę dla obiektów w Students tablicy, która ma Grade właściwość.
  • Przypisuje domyślną ocenę 70 dla uczniów, którzy nie mają klasy.
  • JsonDocument Tworzy wystąpienie w instrukcji using , ponieważ JsonDocument implementuje IDisposableelement . Po usunięciu JsonDocument wystąpienia utracisz również dostęp do wszystkich jego JsonElement wystąpień. Aby zachować dostęp do JsonElement wystąpienia, utwórz jego kopię przed likwidacją wystąpienia nadrzędnego JsonDocument . Aby utworzyć kopię, wywołaj metodę JsonElement.Clone. Aby uzyskać więcej informacji, zobacz JsonDocument is IDisposable (Dokument JsonDocument to IDisposable).

Powyższy przykładowy kod zlicza uczniów, zwiększając zmienną count z każdą iterację. Alternatywą jest wywołanie metody GetArrayLength, jak pokazano w poniższym przykładzie:

double sum = 0;
int count = 0;

using (JsonDocument document = JsonDocument.Parse(jsonString))
{
    JsonElement root = document.RootElement;
    JsonElement studentsElement = root.GetProperty("Students");

    count = studentsElement.GetArrayLength();

    foreach (JsonElement student in studentsElement.EnumerateArray())
    {
        if (student.TryGetProperty("Grade", out JsonElement gradeElement))
        {
            sum += gradeElement.GetDouble();
        }
        else
        {
            sum += 70;
        }
    }
}

double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
    Dim root As JsonElement = document.RootElement
    Dim studentsElement As JsonElement = root.GetProperty("Students")

    count = studentsElement.GetArrayLength()

    For Each student As JsonElement In studentsElement.EnumerateArray()
        Dim gradeElement As JsonElement = Nothing
        If student.TryGetProperty("Grade", gradeElement) Then
            sum += gradeElement.GetDouble()
        Else
            sum += 70
        End If
    Next
End Using

Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")

Oto przykład kodu JSON, który przetwarza ten kod:

{
  "Class Name": "Science",
  "Teacher\u0027s Name": "Jane",
  "Semester": "2019-01-01",
  "Students": [
    {
      "Name": "John",
      "Grade": 94.3
    },
    {
      "Name": "James",
      "Grade": 81.0
    },
    {
      "Name": "Julia",
      "Grade": 91.9
    },
    {
      "Name": "Jessica",
      "Grade": 72.4
    },
    {
      "Name": "Johnathan"
    }
  ],
  "Final": true
}

Aby zapoznać się z podobnym przykładem, który używa JsonNode zamiast elementu , zobacz przykład średniej JsonDocumentklasy JsonNode.

Jak wyszukiwać elementy podrzędne JsonDocument i JsonElement

JsonElement Wyszukiwanie wymaga sekwencyjnego wyszukiwania właściwości i dlatego jest stosunkowo powolne (na przykład w przypadku używania metody TryGetProperty). System.Text.Json program został zaprojektowany tak, aby zminimalizować czas analizy początkowej, a nie czas wyszukiwania. W związku z tym należy użyć następujących metod optymalizacji wydajności podczas wyszukiwania JsonDocument obiektu:

  • Użyj wbudowanych modułów wyliczających (EnumerateArray i EnumerateObject), zamiast wykonywać własne indeksowanie lub pętle.
  • Nie należy wykonywać sekwencyjnego wyszukiwania dla całej JsonDocument całej właściwości za pomocą metody RootElement. Zamiast tego wyszukaj zagnieżdżone obiekty JSON na podstawie znanej struktury danych JSON. Na przykład powyższe przykłady kodu wyszukują Grade właściwość w Student obiektach, tworząc pętlę przez Student obiekty i uzyskując wartość Grade dla każdego z nich, zamiast przeszukiwać wszystkie JsonElement obiekty wyszukujące Grade właściwości. Wykonanie tych ostatnich spowoduje niepotrzebne przekazanie tych samych danych.

Porównanie elementów JsonElements

Aby porównać dwa JsonElement obiekty pod kątem równości, w tym ich elementy potomne, użyj JsonElement.DeepEquals(JsonElement, JsonElement) metody .

JsonElement left = JsonDocument.Parse("10e-3").RootElement;
JsonElement right = JsonDocument.Parse("0.01").RootElement;
bool equal = JsonElement.DeepEquals(left, right);
Console.WriteLine(equal); // True.

Użyj JsonDocument polecenia , aby zapisać kod JSON

W poniższym przykładzie pokazano, jak napisać kod JSON z pliku JsonDocument:

string jsonString = File.ReadAllText(inputFileName);

var writerOptions = new JsonWriterOptions
{
    Indented = true
};

var documentOptions = new JsonDocumentOptions
{
    CommentHandling = JsonCommentHandling.Skip
};

using FileStream fs = File.Create(outputFileName);
using var writer = new Utf8JsonWriter(fs, options: writerOptions);
using JsonDocument document = JsonDocument.Parse(jsonString, documentOptions);

JsonElement root = document.RootElement;

if (root.ValueKind == JsonValueKind.Object)
{
    writer.WriteStartObject();
}
else
{
    return;
}

foreach (JsonProperty property in root.EnumerateObject())
{
    property.WriteTo(writer);
}

writer.WriteEndObject();

writer.Flush();
Dim jsonString As String = File.ReadAllText(inputFileName)

Dim writerOptions As JsonWriterOptions = New JsonWriterOptions With {
    .Indented = True
}

Dim documentOptions As JsonDocumentOptions = New JsonDocumentOptions With {
    .CommentHandling = JsonCommentHandling.Skip
}

Dim fs As FileStream = File.Create(outputFileName)
Dim writer As Utf8JsonWriter = New Utf8JsonWriter(fs, options:=writerOptions)
Dim document As JsonDocument = JsonDocument.Parse(jsonString, documentOptions)

Dim root As JsonElement = document.RootElement

If root.ValueKind = JsonValueKind.[Object] Then
    writer.WriteStartObject()
Else
    Return
End If

For Each [property] As JsonProperty In root.EnumerateObject()
    [property].WriteTo(writer)
Next

writer.WriteEndObject()

writer.Flush()

Powyższy kod ma następujące działanie:

  • Odczytuje plik JSON, ładuje dane do JsonDocumentpliku i zapisuje formatowane (dość drukowane) dane JSON do pliku.
  • Umożliwia JsonDocumentOptions określenie, że komentarze w wejściowym formacie JSON są dozwolone, ale ignorowane.
  • Po zakończeniu wywołania Flush modułu zapisywania. Alternatywą jest pozwolić modułowi zapisywania na automatyczne opróżnienie, gdy zostanie usunięte.

Oto przykład danych wejściowych JSON, które mają być przetwarzane przez przykładowy kod:

{"Class Name": "Science","Teacher's Name": "Jane","Semester": "2019-01-01","Students": [{"Name": "John","Grade": 94.3},{"Name": "James","Grade": 81.0},{"Name": "Julia","Grade": 91.9},{"Name": "Jessica","Grade": 72.4},{"Name": "Johnathan"}],"Final": true}

Wynik jest następującymi dość drukowanymi danymi wyjściowymi JSON:

{
  "Class Name": "Science",
  "Teacher\u0027s Name": "Jane",
  "Semester": "2019-01-01",
  "Students": [
    {
      "Name": "John",
      "Grade": 94.3
    },
    {
      "Name": "James",
      "Grade": 81.0
    },
    {
      "Name": "Julia",
      "Grade": 91.9
    },
    {
      "Name": "Jessica",
      "Grade": 72.4
    },
    {
      "Name": "Johnathan"
    }
  ],
  "Final": true
}

JsonDocument to IDisposable

JsonDocument tworzy widok danych w pamięci w buforze w puli. W związku z tym JsonDocument typ implementuje IDisposable i musi być używany wewnątrz using bloku.

Zwróć JsonDocument element z interfejsu API tylko wtedy, gdy chcesz przenieść własność okresu istnienia i usunąć odpowiedzialność za obiekt wywołujący. W większości scenariuszy nie jest to konieczne. Jeśli obiekt wywołujący musi pracować z całym dokumentem JSON, zwróć element Clone RootElement, czyli JsonElement. Jeśli obiekt wywołujący musi pracować z określonym elementem w dokumencie JSON, zwróć Clone ten JsonElementelement . Jeśli zwracasz element podrzędny RootElement lub bezpośrednio bez tworzenia Cloneelementu , obiekt wywołujący nie będzie mógł uzyskać dostępu do zwróconego JsonElement elementu po usunięciu elementu będącego JsonDocument właścicielem.

Oto przykład, który wymaga utworzenia elementu Clone:

public JsonElement LookAndLoad(JsonElement source)
{
    string json = File.ReadAllText(source.GetProperty("fileName").GetString());

    using (JsonDocument doc = JsonDocument.Parse(json))
    {
        return doc.RootElement.Clone();
    }
}

Powyższy kod oczekuje JsonElement właściwości , która zawiera fileName właściwość . Spowoduje to otwarcie pliku JSON i utworzenie pliku JsonDocument. Metoda zakłada, że obiekt wywołujący chce pracować z całym dokumentem, więc zwraca wartość Clone .RootElement

Jeśli otrzymasz element JsonElement i zwraca element podrzędny, nie jest konieczne zwrócenie elementu Clone podrzędnego. Wywołujący jest odpowiedzialny za utrzymanie przy życiu JsonDocument , do którego należy przekazany JsonElement element. Na przykład:

public JsonElement ReturnFileName(JsonElement source)
{
   return source.GetProperty("fileName");
}

JsonDocument z JsonSerializerOptions

Można użyć JsonSerializer do serializacji i deserializacji wystąpienia klasy JsonDocument. Jednak implementacja odczytywania i zapisywania JsonDocument wystąpień przy JsonSerializer użyciu jest otoką obiektów JsonDocument.ParseValue(Utf8JsonReader) i JsonDocument.WriteTo(Utf8JsonWriter). Ta otoka nie przekazuje żadnych JsonSerializerOptions (funkcji serializatora) do Utf8JsonReader lub Utf8JsonWriter. Jeśli na przykład zostanie ustawiona JsonSerializerOptions.DefaultIgnoreCondition WhenWritingNull wartość i wywołana JsonSerializer z przeciążeniem, które przyjmuje JsonSerializerOptions, właściwości null nie zostaną zignorowane.

Poniższy przykład ilustruje wynik użycia metod, które przyjmują JsonSerializerOptions parametr i serializują JsonDocument wystąpienie:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace JsonDocumentWithJsonSerializerOptions;

public class Program
{
    public static void Main()
    {
        Person person = new() { Name = "Nancy" };

        // Default serialization - Address property included with null token.
        // Output: {"Name":"Nancy","Address":null}
        string personJsonWithNull = JsonSerializer.Serialize(person);
        Console.WriteLine(personJsonWithNull);

        // Serialize and ignore null properties - null Address property is omitted
        // Output: {"Name":"Nancy"}
        JsonSerializerOptions options = new()
        {
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
        };
        string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
        Console.WriteLine(personJsonWithoutNull);

        // Ignore null properties doesn't work when serializing JsonDocument instance
        // by using JsonSerializer.
        // Output: {"Name":"Nancy","Address":null}
        JsonDocument? personJsonDocument = JsonSerializer.Deserialize<JsonDocument>(personJsonWithNull);
        personJsonWithNull = JsonSerializer.Serialize(personJsonDocument, options);
        Console.WriteLine(personJsonWithNull);
    }
}
public class Person
{
    public string? Name { get; set; }
    public string? Address { get; set; }
}

Jeśli potrzebujesz funkcji JsonSerializerOptions, należy używać JsonSerializer z silnie typinymi obiektami docelowymi (takimi jak Person klasa w tym przykładzie) zamiast JsonDocument.

Zobacz też