// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Text.Json;
namespace EpicGames.Core
{
///
/// Extensions for parsing values out of generic dictionary objects
///
public static class JsonElementExtensions
{
///
/// Checks if the element has a property with the given value
///
/// Element to search
/// Name of the property
/// Expected value of the property
/// True if the property exists and matches
public static bool HasStringProperty(this JsonElement element, ReadOnlySpan name, string value)
{
JsonElement property;
return element.ValueKind == JsonValueKind.Object && element.TryGetProperty(name, out property) && property.ValueEquals(value);
}
///
/// Checks if the element has a property with the given value
///
/// Element to search
/// Name of the property
/// Expected value of the property
/// True if the property exists and matches
public static bool HasStringProperty(this JsonElement element, string name, string value)
{
JsonElement property;
return element.ValueKind == JsonValueKind.Object && element.TryGetProperty(name, out property) && property.ValueEquals(value);
}
///
/// Gets a property value of a certain type
///
/// The element to get a property from
/// Name of the element
/// The required type of property
/// Value of the property
/// True if the property exists and was a string
public static bool TryGetProperty(this JsonElement element, ReadOnlySpan name, JsonValueKind valueKind, [NotNullWhen(true)] out JsonElement value)
{
JsonElement property;
if (element.TryGetProperty(name, out property) && property.ValueKind == valueKind)
{
value = property;
return true;
}
else
{
value = new JsonElement();
return false;
}
}
///
/// Gets a property value of a certain type
///
/// The element to get a property from
/// Name of the element
/// The required type of property
/// Value of the property
/// True if the property exists and was a string
public static bool TryGetProperty(this JsonElement element, string name, JsonValueKind valueKind, [NotNullWhen(true)] out JsonElement value)
{
JsonElement property;
if (element.TryGetProperty(name, out property) && property.ValueKind == valueKind)
{
value = property;
return true;
}
else
{
value = new JsonElement();
return false;
}
}
///
/// Gets a string property value
///
/// The element to get a property from
/// Name of the element
/// Value of the property
/// True if the property exists and was a string
public static bool TryGetStringProperty(this JsonElement element, ReadOnlySpan name, [NotNullWhen(true)] out string? value)
{
JsonElement property;
if (element.TryGetProperty(name, out property) && property.ValueKind == JsonValueKind.String)
{
value = property.GetString()!;
return true;
}
else
{
value = null;
return false;
}
}
///
/// Gets a string property value
///
/// The element to get a property from
/// Name of the element
/// Value of the property
/// True if the property exists and was a string
public static bool TryGetStringProperty(this JsonElement element, string name, [NotNullWhen(true)] out string? value)
{
return TryGetStringProperty(element, Encoding.UTF8.GetBytes(name).AsSpan(), out value);
}
///
/// Gets a property value from a document or subdocument, indicated with dotted notation
///
/// Document to get a property for
/// Name of the property
/// Receives the nexted element
/// True if the property exists and was of the correct type
public static bool TryGetNestedProperty(this JsonElement element, ReadOnlySpan name, [NotNullWhen(true)] out JsonElement outElement)
{
int dotIdx = name.IndexOf((byte)'.');
if (dotIdx == -1)
{
return element.TryGetProperty(name, out outElement);
}
JsonElement docValue;
if (element.TryGetProperty(name.Slice(0, dotIdx), out docValue) && docValue.ValueKind == JsonValueKind.Object)
{
return TryGetNestedProperty(docValue, name.Slice(dotIdx + 1), out outElement);
}
outElement = new JsonElement();
return false;
}
///
/// Gets a property value from a document or subdocument, indicated with dotted notation
///
/// Document to get a property for
/// Name of the property
/// Receives the nexted element
/// True if the property exists and was of the correct type
public static bool TryGetNestedProperty(this JsonElement element, string name, [NotNullWhen(true)] out JsonElement outElement)
{
return TryGetNestedProperty(element, Encoding.UTF8.GetBytes(name).AsSpan(), out outElement);
}
///
/// Gets an int32 value from the document
///
/// Document to get a property for
/// Name of the property
/// Receives the property value
/// True if the property was retrieved
public static bool TryGetNestedProperty(this JsonElement element, string name, out int outValue)
{
JsonElement value;
if (element.TryGetNestedProperty(name, out value) && value.ValueKind == JsonValueKind.Number)
{
outValue = value.GetInt32();
return true;
}
else
{
outValue = 0;
return false;
}
}
///
/// Gets a string value from the document
///
/// Document to get a property for
/// Name of the property
/// Receives the property value
/// True if the property was retrieved
public static bool TryGetNestedProperty(this JsonElement element, string name, [NotNullWhen(true)] out string? outValue)
{
JsonElement value;
if (element.TryGetNestedProperty(name, out value) && value.ValueKind == JsonValueKind.String)
{
outValue = value.GetString();
return outValue != null;
}
else
{
outValue = null;
return false;
}
}
}
}