已经存在为System.Text.Json
请求此功能的问题:https://github.com/dotnet/corefx/issues/42466
同时,您可以基于Merge
编写自己的Utf8JsonWriter
方法作为解决方法(因为现有的JsonDocument
,JsonElement
API是只读的)
如果您的JSON对象仅包含非null的简单/原始值,并且属性显示的顺序并不特别在意,则以下相对简单的代码示例应该对您有用:
public static string SimpleObjectMerge(string originalJson,string newContent)
{
var outputBuffer = new ArrayBufferWriter<byte>();
using (JsonDocument jDoc1 = JsonDocument.Parse(originalJson))
using (JsonDocument jDoc2 = JsonDocument.Parse(newContent))
using (var jsonWriter = new Utf8JsonWriter(outputBuffer,new JsonWriterOptions { Indented = true }))
{
JsonElement root1 = jDoc1.RootElement;
JsonElement root2 = jDoc2.RootElement;
// Assuming both JSON strings are single JSON objects (i.e. {...})
Debug.Assert(root1.ValueKind == JsonValueKind.Object);
Debug.Assert(root2.ValueKind == JsonValueKind.Object);
jsonWriter.WriteStartObject();
// Write all the properties of the first document that don't conflict with the second
foreach (JsonProperty property in root1.EnumerateObject())
{
if (!root2.TryGetProperty(property.Name,out _))
{
property.WriteTo(jsonWriter);
}
}
// Write all the properties of the second document (including those that are duplicates which were skipped earlier)
// The property values of the second document completely override the values of the first
foreach (JsonProperty property in root2.EnumerateObject())
{
property.WriteTo(jsonWriter);
}
jsonWriter.WriteEndObject();
}
return Encoding.UTF8.GetString(outputBuffer.WrittenSpan);
}
Newtonsoft.Json
在合并时null
具有不同的null
处理方式,其中null
不会覆盖non-null属性的值(当存在重复项时)。我不确定您是否要这样做。如果需要,您将需要修改上述方法来处理public static string SimpleObjectMergeWithNullHandling(string originalJson,new JsonWriterOptions { Indented = true }))
{
JsonElement root1 = jDoc1.RootElement;
JsonElement root2 = jDoc2.RootElement;
// Assuming both JSON strings are single JSON objects (i.e. {...})
Debug.Assert(root1.ValueKind == JsonValueKind.Object);
Debug.Assert(root2.ValueKind == JsonValueKind.Object);
jsonWriter.WriteStartObject();
// Write all the properties of the first document that don't conflict with the second
// Or if the second is overriding it with null,favor the property in the first.
foreach (JsonProperty property in root1.EnumerateObject())
{
if (!root2.TryGetProperty(property.Name,out JsonElement newValue) || newValue.ValueKind == JsonValueKind.Null)
{
property.WriteTo(jsonWriter);
}
}
// Write all the properties of the second document (including those that are duplicates which were skipped earlier)
// The property values of the second document completely override the values of the first,unless they are null in the second.
foreach (JsonProperty property in root2.EnumerateObject())
{
// Don't write null values,unless they are unique to the second document
if (property.Value.ValueKind != JsonValueKind.Null || !root1.TryGetProperty(property.Name,out _))
{
property.WriteTo(jsonWriter);
}
}
jsonWriter.WriteEndObject();
}
return Encoding.UTF8.GetString(outputBuffer.WrittenSpan);
}
情况。修改如下:
public static string Merge(string originalJson,new JsonWriterOptions { Indented = true }))
{
JsonElement root1 = jDoc1.RootElement;
JsonElement root2 = jDoc2.RootElement;
if (root1.ValueKind != JsonValueKind.Array && root1.ValueKind != JsonValueKind.Object)
{
throw new InvalidOperationException($"The original JSON document to merge new content into must be a container type. Instead it is {root1.ValueKind}.");
}
if (root1.ValueKind != root2.ValueKind)
{
return originalJson;
}
if (root1.ValueKind == JsonValueKind.Array)
{
MergeArrays(jsonWriter,root1,root2);
}
else
{
MergeObjects(jsonWriter,root2);
}
}
return Encoding.UTF8.GetString(outputBuffer.WrittenSpan);
}
private static void MergeObjects(Utf8JsonWriter jsonWriter,JsonElement root1,JsonElement root2)
{
Debug.Assert(root1.ValueKind == JsonValueKind.Object);
Debug.Assert(root2.ValueKind == JsonValueKind.Object);
jsonWriter.WriteStartObject();
// Write all the properties of the first document.
// If a property exists in both documents,either:
// * Merge them,if the value kinds match (e.g. both are objects or arrays),// * Completely override the value of the first with the one from the second,if the value kind mismatches (e.g. one is object,while the other is an array or string),// * Or favor the value of the first (regardless of what it may be),if the second one is null (i.e. don't override the first).
foreach (JsonProperty property in root1.EnumerateObject())
{
string propertyName = property.Name;
JsonValueKind newValueKind;
if (root2.TryGetProperty(propertyName,out JsonElement newValue) && (newValueKind = newValue.ValueKind) != JsonValueKind.Null)
{
jsonWriter.WritePropertyName(propertyName);
JsonElement originalValue = property.Value;
JsonValueKind originalValueKind = originalValue.ValueKind;
if (newValueKind == JsonValueKind.Object && originalValueKind == JsonValueKind.Object)
{
MergeObjects(jsonWriter,originalValue,newValue); // Recursive call
}
else if (newValueKind == JsonValueKind.Array && originalValueKind == JsonValueKind.Array)
{
MergeArrays(jsonWriter,newValue);
}
else
{
newValue.WriteTo(jsonWriter);
}
}
else
{
property.WriteTo(jsonWriter);
}
}
// Write all the properties of the second document that are unique to it.
foreach (JsonProperty property in root2.EnumerateObject())
{
if (!root1.TryGetProperty(property.Name,out _))
{
property.WriteTo(jsonWriter);
}
}
jsonWriter.WriteEndObject();
}
private static void MergeArrays(Utf8JsonWriter jsonWriter,JsonElement root2)
{
Debug.Assert(root1.ValueKind == JsonValueKind.Array);
Debug.Assert(root2.ValueKind == JsonValueKind.Array);
jsonWriter.WriteStartArray();
// Write all the elements from both JSON arrays
foreach (JsonElement element in root1.EnumerateArray())
{
element.WriteTo(jsonWriter);
}
foreach (JsonElement element in root2.EnumerateArray())
{
element.WriteTo(jsonWriter);
}
jsonWriter.WriteEndArray();
}
如果您的JSON对象可能包含嵌套的JSON值(包括其他对象和数组),那么您也想扩展逻辑来处理它。这样的事情应该起作用:
Merge
注意:如果性能对于您的方案至关重要,则此方法(即使带有缩进形式)在运行时和分配方面均优于Newtonsoft.Json的outputBuffer
方法。也就是说,可以根据需要使实现更快一些(例如,不要缩进,缓存
BenchmarkDotNet=v0.12.0,OS=Windows 10.0.19041
Intel Core i7-6700 CPU 3.40GHz (Skylake),1 CPU,8 logical and 4 physical cores
.NET Core SDK=5.0.100-alpha1-015914
[Host] : .NET Core 5.0.0 (CoreCLR 5.0.19.56303,CoreFX 5.0.19.56306),X64 RyuJIT
Job-LACFYV : .NET Core 5.0.0 (CoreCLR 5.0.19.56303,X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000
,不接受/返回字符串等)。
| Method | Mean | Error | StdDev | Median | Min | Max | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------- |---------:|---------:|---------:|---------:|---------:|---------:|------:|-------:|-------:|------:|----------:|
| MergeNewtonsoft | 29.01 us | 0.570 us | 0.656 us | 28.84 us | 28.13 us | 30.19 us | 1.00 | 7.0801 | 0.0610 | - | 28.98 KB |
| Merge_New | 16.41 us | 0.293 us | 0.274 us | 16.41 us | 16.02 us | 17.00 us | 0.57 | 1.7090 | - | - | 6.99 KB |
let maxDuration:Float64 = 60
let videoDuration = asset!.duration
let videoDurationSeconds = CMTimeGetSeconds(videoDuration)
if videoDurationSeconds > maxDuration {
if UIVideoEditorController.canEditVideoAtPath(asset!.URL.path!) {
let videoEditor = UIVideoEditorController()
self.videoEditor.videoPath = asset!.URL.path!
self.videoEditor.videoMaximumDuration = 60.0
self.presentViewController(self.videoEditor,animated: true,completion: nil)
}
}
// MARK: - UIVideoEditorControllerDelegate
func videoEditorController(editor: UIVideoEditorController,didSaveEditedVideoToPath editedVideoPath: String) {
self.videoEditor.dismissViewControllerAnimated(true,completion: nil)
//Do whatever you wish with the trimmed video here
}
,
从.Net Core 3.0开始,System.Text.Json
尚未实现JSON对象的合并:
通常,JsonDocument
是只读的。它
提供一种机制,可以检查 JSON值的结构内容,而无需自动实例化数据值。
因此,它并非旨在支持以任何方式修改JSON值,包括将另一个JSON值合并到其中。
当前存在一个增强请求,以实现可修改的JSON文档对象模型:
Issue #39922: Writable Json DOM 。它具有关联的规范 Writable JSON Document Object Model (DOM) for System.Text.Json
。如果实施了此增强功能,则可以合并JSON文档。您可以添加一个要求与JContainer.Merge()
等效的功能的问题,并作为前提条件链接回问题#39922。
本文链接:https://www.f2er.com/3166239.html