Add JObject.Property overload with a StringComparison and JsonMergeSettings.PropertyNameComparison (#1843)
This commit is contained in:
@@ -2063,5 +2063,28 @@ Parameter name: arrayIndex");
|
||||
Assert.AreEqual(1, (int)(JToken)value);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void Property()
|
||||
{
|
||||
JObject a = new JObject();
|
||||
a["Name"] = "Name!";
|
||||
a["name"] = "name!";
|
||||
a["title"] = "Title!";
|
||||
|
||||
Assert.AreEqual(null, a.Property("NAME", StringComparison.Ordinal));
|
||||
Assert.AreEqual(null, a.Property("NAME"));
|
||||
Assert.AreEqual(null, a.Property("TITLE"));
|
||||
Assert.AreEqual(null, a.Property(null, StringComparison.Ordinal));
|
||||
Assert.AreEqual(null, a.Property(null, StringComparison.OrdinalIgnoreCase));
|
||||
Assert.AreEqual(null, a.Property(null));
|
||||
|
||||
// Return first match when ignoring case
|
||||
Assert.AreEqual("Name", a.Property("NAME", StringComparison.OrdinalIgnoreCase).Name);
|
||||
// Return exact match before ignoring case
|
||||
Assert.AreEqual("name", a.Property("name", StringComparison.OrdinalIgnoreCase).Name);
|
||||
// Return exact match without ignoring case
|
||||
Assert.AreEqual("name", a.Property("name", StringComparison.Ordinal).Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -666,5 +666,40 @@ namespace Newtonsoft.Json.Tests.Linq
|
||||
|
||||
StringAssert.AreEqual(newJson, newFoo.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Merge_IgnorePropertyCase()
|
||||
{
|
||||
JObject o1 = JObject.Parse(@"{
|
||||
'Id': '1',
|
||||
'Words': [ 'User' ]
|
||||
}");
|
||||
JObject o2 = JObject.Parse(@"{
|
||||
'Id': '1',
|
||||
'words': [ 'Name' ]
|
||||
}");
|
||||
|
||||
o1.Merge(o2, new JsonMergeSettings
|
||||
{
|
||||
MergeArrayHandling = MergeArrayHandling.Concat,
|
||||
MergeNullValueHandling = MergeNullValueHandling.Merge,
|
||||
PropertyNameComparison = StringComparison.OrdinalIgnoreCase
|
||||
});
|
||||
|
||||
Assert.IsNull(o1["words"]);
|
||||
Assert.IsNotNull(o1["Words"]);
|
||||
|
||||
JArray words = (JArray)o1["Words"];
|
||||
Assert.AreEqual("User", (string)words[0]);
|
||||
Assert.AreEqual("Name", (string)words[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MergeSettingsComparisonDefault()
|
||||
{
|
||||
JsonMergeSettings settings = new JsonMergeSettings();
|
||||
|
||||
Assert.AreEqual(StringComparison.Ordinal, settings.PropertyNameComparison);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ namespace Newtonsoft.Json.Linq
|
||||
|
||||
foreach (KeyValuePair<string, JToken> contentItem in o)
|
||||
{
|
||||
JProperty existingProperty = Property(contentItem.Key);
|
||||
JProperty existingProperty = Property(contentItem.Key, settings?.PropertyNameComparison ?? StringComparison.Ordinal);
|
||||
|
||||
if (existingProperty == null)
|
||||
{
|
||||
@@ -263,14 +263,44 @@ namespace Newtonsoft.Json.Linq
|
||||
/// <param name="name">The property name.</param>
|
||||
/// <returns>A <see cref="JProperty"/> with the specified name or <c>null</c>.</returns>
|
||||
public JProperty Property(string name)
|
||||
{
|
||||
return Property(name, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JProperty"/> with the specified name.
|
||||
/// The exact name will be searched for first and if no matching property is found then
|
||||
/// the <see cref="StringComparison"/> will be used to match a property.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name.</param>
|
||||
/// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
|
||||
/// <returns>A <see cref="JProperty"/> matched with the specified name or <c>null</c>.</returns>
|
||||
public JProperty Property(string name, StringComparison comparison)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_properties.TryGetValue(name, out JToken property);
|
||||
return (JProperty)property;
|
||||
if (_properties.TryGetValue(name, out JToken property))
|
||||
{
|
||||
return (JProperty)property;
|
||||
}
|
||||
|
||||
// test above already uses this comparison so no need to repeat
|
||||
if (comparison != StringComparison.Ordinal)
|
||||
{
|
||||
for (int i = 0; i < _properties.Count; i++)
|
||||
{
|
||||
JProperty p = (JProperty)_properties[i];
|
||||
if (string.Equals(p.Name, name, comparison))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -509,25 +539,9 @@ namespace Newtonsoft.Json.Linq
|
||||
}
|
||||
|
||||
// attempt to get value via dictionary first for performance
|
||||
JProperty property = Property(propertyName);
|
||||
if (property != null)
|
||||
{
|
||||
return property.Value;
|
||||
}
|
||||
var property = Property(propertyName, comparison);
|
||||
|
||||
// test above already uses this comparison so no need to repeat
|
||||
if (comparison != StringComparison.Ordinal)
|
||||
{
|
||||
foreach (JProperty p in _properties)
|
||||
{
|
||||
if (string.Equals(p.Name, propertyName, comparison))
|
||||
{
|
||||
return p.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return property?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
#region License
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace Newtonsoft.Json.Linq
|
||||
@@ -9,6 +34,15 @@ namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
private MergeArrayHandling _mergeArrayHandling;
|
||||
private MergeNullValueHandling _mergeNullValueHandling;
|
||||
private StringComparison _propertyNameComparison;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonMergeSettings"/> class.
|
||||
/// </summary>
|
||||
public JsonMergeSettings()
|
||||
{
|
||||
_propertyNameComparison = StringComparison.Ordinal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the method used when merging JSON arrays.
|
||||
@@ -45,5 +79,25 @@ namespace Newtonsoft.Json.Linq
|
||||
_mergeNullValueHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the comparison used to match property names while merging.
|
||||
/// The exact property name will be searched for first and if no matching property is found then
|
||||
/// the <see cref="StringComparison"/> will be used to match a property.
|
||||
/// </summary>
|
||||
/// <value>The comparison used to match property names while merging.</value>
|
||||
public StringComparison PropertyNameComparison
|
||||
{
|
||||
get => _propertyNameComparison;
|
||||
set
|
||||
{
|
||||
if (value < StringComparison.CurrentCulture || value > StringComparison.OrdinalIgnoreCase)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
|
||||
_propertyNameComparison = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user