1

サードパーティのライブラリを使用する柔軟性がないプラットフォームで、C# 3.5 のカットダウン バージョンを使用しています。

JSON を (json ストリーム リーダーを使用して) 解析できますが、実際にそれをクラスに変換する方法がわかりません。(通常の json からクラスへのデシリアライザーへのアクセスもありません)。

リフレクションを使用して手動で (まだ動的に) JSON 文字列をクラスに変換する方法を知っている人はいますか?

サンプル Json:

{"items":[ {"firstName":"bob", "lastName":"smith", "id":1001, "foods": [{"name":"fish", "name":"bacon", "name":"cereal"}]}, {"firstName":"sarah", "lastName":"smith", "id":1002, "foods": [{"name":"bacon", "name":"apples", "name":"chocolate"}]}, {"firstName":"tom", "lastName":"waffle", "id":1003, "foods": [{"name":"waffles", "name":"sticks", "name":"stones"}]}, {"firstName":"reginald", "lastName":"hamtuft", "id":1003, "foods": [{"name":"ham", "name":"cigars", "name":"noisy children"}]} ]}

4

3 に答える 3

2

ピートと、私を正しい軌道に乗せてくれた他の人たちに感謝します。私の場合、JSON 文字列を SQL CLR 関数の厳密に型指定されたオブジェクトに逆シリアル化する必要もあったため、「安全に」使用できるライブラリが制限されていました (詳細はこちら)。

ParseJSON のコードを変更しました。これは、配列の配列を逆シリアル化Dictionary<string, object>できるように逆シリアル化しますが、これはできませんでした。また、JavaScriptConverterまたはSystem.Runtime.Serializationライブラリを使用せずに、結果の辞書を厳密に型指定されたオブジェクトにキャストする方法をいくつか開発しました。このコードでは、次のことができます。

//we have a foo and bar classes with a variety of fields and properties
private class foo
{
    public List<double[][]> data;
    public IEnumerable<object> DataObj;
    public int integerField;
    public long longProperty { get; set; }
    public string stringValue;
    public int? nullableInt;
    public DateTime dateTimeValue;
    public List<bar> classValues;
}

private class bar
{
    public string stringValue;
    public DateTimeOffset dateTimeOffsetValue;
}

static void Main(string[] args)
{
    //lets deserialize the following JSON string into our foo object, 
    //the dictionary is optional, and not necessary if our JSON property names are the same as in our object.
    //in this case it's used to map the "jdata" property on the JSON string to the "data" property of our object,
    //in the case of the "dataObj", we are mapping to the uppercase field of our object
    string JSONstring = "{\"jdata\":[[[1526518800000,7.0],[1526518834200,7.0]],[[1526549272200,25.0],[1526549306400,25.0]]],\"dataObj\":[[[1526518800000,7.0],[1526518834200,7.0]],\"abc\",123],\"integerField\":623,\"longProperty\":456789,\"stringValue\":\"foo\",\"nullableInt\":\"\",\"dateTimeValue\":\"2018-05-17T01:00:00.0000000\", \"classValues\": [{\"stringValue\":\"test\",\"dateTimeOffsetValue\":\"2018-05-17T05:00:00.0000000\"},{\"stringValue\":\"test2\",\"dateTimeOffsetValue\":\"2018-05-17T06:00:00.0000000\"}]}";
    var mappingDict = new Dictionary<string, string>() { { "jdata", "data" }, { "dataObj", "DataObj" } };
    foo myObject = ParseJSON<foo>(JSONstring, mappingDict);
}

ParseJSON メソッドは、JSON 文字列を入力として受け取り、オプションでDictionary<string, string>それを Type にキャストしようとしTます。辞書は、JSON 文字列の任意のプロパティをオブジェクトのプロパティにマップするために使用されます (たとえば、"jdata"/" data" ディクショナリは上記で宣言されています)。

public static T ParseJSON<T>(string jsonString, Dictionary<string, string> mappingTable = null)
{
    Dictionary<string, object> jsonDictionary = ParseJSON(jsonString);
    T castedObj = CastAs<T>(jsonDictionary, mappingTable);
    return castedObj;
}

以下は、JSON 解析用に変更した方法です (配列の配列を解析できます)。

public static Dictionary<string, object> ParseJSON(string json)
{
    int end;
    return ParseJSON(json, 0, out end);
}

private static Dictionary<string, object> ParseJSON(string json, int start, out int end)
{
    Dictionary<string, object> dict = new Dictionary<string, object>();
    bool escbegin = false;
    bool escend = false;
    bool inquotes = false;
    string key = null;
    int cend;
    StringBuilder sb = new StringBuilder();
    Dictionary<string, object> child = null;
    List<object> arraylist = null;
    Regex regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
    int autoKey = 0;
    int subArrayCount = 0;
    List<int> arrayIndexes = new List<int>();
    bool inSingleQuotes = false;
    bool inDoubleQuotes = false;
    for (int i = start; i < json.Length; i++)
    {
        char c = json[i];
        if (c == '\\') escbegin = !escbegin;
        if (!escbegin)
        {
            if (c == '"' && !inSingleQuotes)
            {
                inDoubleQuotes = !inDoubleQuotes;
                inquotes = !inquotes;
                if (!inquotes && arraylist != null)
                {
                    arraylist.Add(DecodeString(regex, sb.ToString()));
                    sb.Length = 0;
                }
                continue;
            }
            else if (c == '\'' && !inDoubleQuotes)
            {
                inSingleQuotes = !inSingleQuotes;
                inquotes = !inquotes;
                if (!inquotes && arraylist != null)
                {
                    arraylist.Add(DecodeString(regex, sb.ToString()));
                    sb.Length = 0;
                }
                continue;
            }
            if (!inquotes)
            {
                switch (c)
                {
                    case '{':
                        if (i != start)
                        {
                            child = ParseJSON(json, i, out cend);
                            if (arraylist != null)
                            {
                                arraylist.Add(child);
                            }
                            else
                            {
                                dict.Add(key.Trim(), child);
                                key = null;
                            }
                            i = cend;
                        }
                        continue;
                    case '}':
                        end = i;
                        if (key != null)
                        {
                            if (arraylist != null) dict.Add(key.Trim(), arraylist);
                            else dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
                        }
                        return dict;
                    case '[':
                        if (arraylist != null)
                        {
                            List<object> _tempArrayList = arraylist;
                            for (int l = 0; l < subArrayCount; l++)
                            {
                                if (l == subArrayCount - 1)
                                {
                                    _tempArrayList.Add(new List<object>());
                                }
                                else
                                {
                                    _tempArrayList = (List<object>)_tempArrayList[arrayIndexes[l]];
                                }
                            }

                            if (arrayIndexes.Count < subArrayCount)
                            {
                                arrayIndexes.Add(0);
                            }
                            subArrayCount++;
                        }
                        else
                        {
                            arraylist = new List<object>();
                            subArrayCount++;
                        }
                        continue;
                    case ']':
                        if (key == null)
                        {
                            key = "array" + autoKey.ToString();
                            autoKey++;
                        }
                        if (arraylist != null)
                        {
                            List<object> _tempArrayList = arraylist;
                            for (int l = 0; l < subArrayCount; l++)
                            {
                                if (l == subArrayCount - 1)
                                {
                                    if (sb.Length > 0)
                                    {
                                        _tempArrayList.Add(sb.ToString());
                                    }
                                    subArrayCount--;
                                    if (subArrayCount == arrayIndexes.Count)
                                    {
                                        if (arrayIndexes.Count > 0)
                                        {
                                            arrayIndexes[arrayIndexes.Count - 1]++;
                                        }
                                    }
                                    else if (subArrayCount == arrayIndexes.Count - 1)
                                    {
                                        arrayIndexes.RemoveAt(arrayIndexes.Count - 1);
                                        if (arrayIndexes.Count > 0)
                                        {
                                            arrayIndexes[arrayIndexes.Count - 1]++;
                                        }
                                    }
                                }
                                else
                                {
                                    _tempArrayList = (List<object>)_tempArrayList[arrayIndexes[l]];
                                }
                            }
                            sb.Length = 0;
                        }
                        if (subArrayCount == 0)
                        {
                            dict.Add(key.Trim(), arraylist);
                            arraylist = null;
                            key = null;
                        }
                        continue;
                    case ',':
                        if (arraylist == null && key != null)
                        {
                            dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
                            key = null;
                            sb.Length = 0;
                        }
                        if (arraylist != null && sb.Length > 0)
                        {
                            List<object> _tempArrayList = arraylist;
                            for (int l = 0; l < subArrayCount; l++)
                            {
                                if (l == subArrayCount - 1)
                                {
                                    _tempArrayList.Add(sb.ToString());
                                }
                                else
                                {
                                    _tempArrayList = (List<object>)_tempArrayList[arrayIndexes[l]];
                                }
                            }
                            sb.Length = 0;
                        }
                        continue;
                    case ':':
                        key = DecodeString(regex, sb.ToString());
                        sb.Length = 0;
                        continue;
                }
            }
        }
        sb.Append(c);
        if (escend) escbegin = false;
        if (escbegin) escend = true;
        else escend = false;
    }
    end = json.Length - 1;
    return dict; //shouldn't ever get here unless the JSON is malformed
}

private static string DecodeString(Regex regex, string str)
{
    return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber))));
}

次のメソッドは、前のメソッドから返された辞書を強い型指定されたオブジェクトにキャストしようとします。長いことはわかっていますが、うまく機能します。

private static T CastAs<T>(Dictionary<string, object> source, Dictionary<string, string> mappingTable = null)
{
    T outputData = (T)Activator.CreateInstance(typeof(T));
    TrySet(outputData, source, mappingTable);
    return outputData;
}

private static void TrySet(object target, Dictionary<string, object> source, Dictionary<string, string> mappingTable = null)
{
    if (target == null)
    {
        throw new ArgumentNullException("target");
    }
    bool useMappingTable = mappingTable != null && mappingTable.Count > 0;
    foreach (KeyValuePair<string, object> kv in source)
    {
        string propertyName = null;
        if (useMappingTable && mappingTable.ContainsKey(kv.Key))
        {
            propertyName = mappingTable[kv.Key];
        }
        else
        {
            propertyName = kv.Key;
        }

        if (!string.IsNullOrEmpty(propertyName))
        {
            UpdateMember(target, propertyName, kv.Value, mappingTable);
        }
    }
}

private static void UpdateMember(object target, string propertyName, object value, Dictionary<string, string> mappingTable)
{
    try
    {
        FieldInfo fieldInfo = target.GetType().GetField(propertyName);

        if (fieldInfo != null)
        {
            value = ConvertTo(value, fieldInfo.FieldType, mappingTable);
            fieldInfo.SetValue(target, value);
        }
        else
        {
            PropertyInfo propInfo = target.GetType().GetProperty(propertyName);

            if (propInfo != null)
            {
                value = ConvertTo(value, propInfo.PropertyType, mappingTable);
                propInfo.SetValue(target, value);
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

private static object ConvertTo(object value, Type targetType, Dictionary<string, string> mappingTable)
{
    try
    {
        bool isNullable = false;
        Type sourceType = value.GetType();

        //Obtain actual type to convert to (this is necessary in case of Nullable types)
        if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            isNullable = true;
            targetType = targetType.GetGenericArguments()[0];
        }

        if (isNullable && string.IsNullOrWhiteSpace(Convert.ToString(value)))
        {
            return null;
        }
        //if we are converting from a dictionary to a class, call the TrySet method to convert its members
        else if (targetType.IsClass && sourceType.IsGenericType && sourceType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
        {
            //make sure our value is actually a Dictionary<string, object> in order to be able to cast
            if (sourceType.GetGenericArguments()[0] == typeof(string))
            {
                object convertedValue = Activator.CreateInstance(targetType);
                TrySet(convertedValue, (Dictionary<string, object>)value, mappingTable);
                return convertedValue;
            }
            return null;
        }
        else if (IsCollection(value))
        {
            Type elementType = GetCollectionElementType(targetType);

            if (elementType != null)
            {
                if (targetType.BaseType == typeof(Array))
                {
                    return ConvertToArray(elementType, value, mappingTable);
                }
                else
                {
                    return ConvertToList(elementType, value, mappingTable);
                }
            }
            else
            {
                throw new NullReferenceException();
            }
        }
        else if (targetType == typeof(DateTimeOffset))
        {
            return new DateTimeOffset((DateTime)ChangeType(value, typeof(DateTime)));
        }
        else if (targetType == typeof(object))
        {
            return value;
        }
        else
        {
            return ChangeType(value, targetType);
        }
    }
    catch (Exception ex)
    {
        if (targetType.IsValueType)
        {
            return Activator.CreateInstance(targetType);
        }
        return null;
    }
}

private static Array ConvertToArray(Type elementType, object value, Dictionary<string, string> mappingTable)
{
    Array collection = Array.CreateInstance(elementType, ((ICollection)value).Count);

    int i = 0;
    foreach (object item in (IEnumerable)value)
    {
        try
        {
            collection.SetValue(ConvertTo(item, elementType, mappingTable), i);
            i++;
        }
        catch (Exception ex)
        {
            //nothing here, just skip the item
        }
    }

    return collection;
}

private static IList ConvertToList(Type elementType, object value, Dictionary<string, string> mappingTable)
{
    Type listType = typeof(List<>);
    Type constructedListType = listType.MakeGenericType(elementType);
    IList collection = (IList)Activator.CreateInstance(constructedListType);

    foreach (object item in (IEnumerable)value)
    {
        try
        {
            collection.Add(ConvertTo(item, elementType, mappingTable));
        }
        catch (Exception ex)
        {
            //nothing here, just skip the item
        }
    }

    return collection;
}

private static bool IsCollection(object obj)
{
    bool isCollection = false;

    Type objType = obj.GetType();
    if (!typeof(string).IsAssignableFrom(objType) && typeof(IEnumerable).IsAssignableFrom(objType))
    {
        isCollection = true;
    }

    return isCollection;
}

private static Type GetCollectionElementType(Type objType)
{
    Type elementType;
    Type[] genericArgs = objType.GenericTypeArguments;
    if (genericArgs.Length > 0)
    {
        elementType = genericArgs[0];
    }
    else
    {
        elementType = objType.GetElementType();
    }

    return elementType;
}

private static object ChangeType(object value, Type castTo)
{
    try
    {
        return Convert.ChangeType(value, castTo);
    }
    catch (Exception ex)
    {
        //if the conversion failed, just return the original value
        return value;
    }
}

これが、これを行う方法をまだ探している人に役立つことを願っています。

于 2018-05-23T16:01:17.493 に答える
1

さて、フィードバックに基づいて回答をやり直しています。動的オブジェクトジェネレーターのコードは、引き続き次のようになります。

JSONをC#動的オブジェクトに逆シリアル化しますか?

これはRegEx、Genericコレクションを使用し、Linqを使用しますが、2行のみであり、Linqを使用しないように簡単に書き換えることができます(最後の2つの'result ='行DynamicJsonObject.TryGetMember())。必要に応じて、汎用辞書をハッシュテーブルに置き換えることもできます。

jsonパーサーは、JSONをASP.NETの単純なDictionary <string、string>に逆シリアル化するにはどうすればよいですか?

class Program
{
    static void Main(string[] args)
    {
        string data = "{ 'test': 42, 'test2': 'test2\"', 'structure' : { 'field1': 'field1', 'field2': 44 } }";

        dynamic x = new DynamicJsonObject(JsonMaker.ParseJSON(data));
        Console.WriteLine(x.test2);
        Console.WriteLine(x.structure.field1);
        Console.ReadLine();
    }
}

public class DynamicJsonObject : DynamicObject
{
    private readonly IDictionary<string, object> _dictionary;

    public DynamicJsonObject(IDictionary<string, object> dictionary)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");
        _dictionary = dictionary;
    }

    public override string ToString()
    {
        var sb = new StringBuilder();
        ToString(sb);
        return sb.ToString();
    }

    private void ToString(StringBuilder sb)
    {
        sb.Append("{");
        var firstInDictionary = true;
        foreach (var pair in _dictionary)
        {
            if (!firstInDictionary)
                sb.Append(",");
            firstInDictionary = false;
            var value = pair.Value;
            var name = pair.Key;
            if (value is string)
            {
                sb.AppendFormat("\"{0}\":\"{1}\"", name, value);
            }
            else if (value is IDictionary<string, object>)
            {
                sb.AppendFormat("\"{0}\":", name);
                new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
            }
            else if (value is ArrayList)
            {
                sb.Append("\"");
                sb.Append(name);
                sb.Append("\":[");
                var firstInArray = true;
                foreach (var arrayValue in (ArrayList)value)
                {
                    if (!firstInArray)
                        sb.Append(",");
                    firstInArray = false;
                    if (arrayValue is IDictionary<string, object>)
                        new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
                    else if (arrayValue is string)
                        sb.AppendFormat("\"{0}\"", arrayValue);
                    else
                        sb.AppendFormat("{0}", arrayValue);

                }
                sb.Append("]");
            }
            else
            {
                sb.AppendFormat("\"{0}\":{1}", name, value);
            }
        }
        sb.Append("}");
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (!_dictionary.TryGetValue(binder.Name, out result))
        {
            // return null to avoid exception.  caller can check for null this way...
            result = null;
            return true;
        }

        var dictionary = result as IDictionary<string, object>;
        if (dictionary != null)
        {
            result = new DynamicJsonObject(dictionary);
            return true;
        }

        var arrayList = result as ArrayList;
        if (arrayList != null && arrayList.Count > 0)
        {
            if (arrayList[0] is IDictionary<string, object>)
                result = new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)));
            else
                result = new List<object>(arrayList.Cast<object>());
        }

        return true;
    }
}

public static class JsonMaker
{
    public static Dictionary<string, object> ParseJSON(string json)
    {
        int end;
        return ParseJSON(json, 0, out end);
    }
    private static Dictionary<string, object> ParseJSON(string json, int start, out int end)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        bool escbegin = false;
        bool escend = false;
        bool inquotes = false;
        string key = null;
        int cend;
        StringBuilder sb = new StringBuilder();
        Dictionary<string, object> child = null;
        List<object> arraylist = null;
        Regex regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
        int autoKey = 0;
        bool inSingleQuotes = false;
        bool inDoubleQuotes = false;
        for (int i = start; i < json.Length; i++)
        {
            char c = json[i];
            if (c == '\\') escbegin = !escbegin;
            if (!escbegin)
            {
                if (c == '"' && !inSingleQuotes)
                {
                    inDoubleQuotes = !inDoubleQuotes;
                    inquotes = !inquotes;
                    if (!inquotes && arraylist != null)
                    {
                        arraylist.Add(DecodeString(regex, sb.ToString()));
                        sb.Length = 0;
                    }
                    continue;
                }
                else if (c == '\'' && !inDoubleQuotes)
                {
                    inSingleQuotes = !inSingleQuotes;
                    inquotes = !inquotes;
                    if (!inquotes && arraylist != null)
                    {
                        arraylist.Add(DecodeString(regex, sb.ToString()));
                        sb.Length = 0;
                    }
                    continue;
                }
                if (!inquotes)
                {
                    switch (c)
                    {
                        case '{':
                            if (i != start)
                            {
                                child = ParseJSON(json, i, out cend);
                                if (arraylist != null) arraylist.Add(child);
                                else
                                {
                                    dict.Add(key.Trim(), child);
                                    key = null;
                                }
                                i = cend;
                            }
                            continue;
                        case '}':
                            end = i;
                            if (key != null)
                            {
                                if (arraylist != null) dict.Add(key.Trim(), arraylist);
                                else dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
                            }
                            return dict;
                        case '[':
                            arraylist = new List<object>();
                            continue;
                        case ']':
                            if (key == null)
                            {
                                key = "array" + autoKey.ToString();
                                autoKey++;
                            }
                            if (arraylist != null && sb.Length > 0)
                            {
                                arraylist.Add(sb.ToString());
                                sb.Length = 0;
                            }
                            dict.Add(key.Trim(), arraylist);
                            arraylist = null;
                            key = null;
                            continue;
                        case ',':
                            if (arraylist == null && key != null)
                            {
                                dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
                                key = null;
                                sb.Length = 0;
                            }
                            if (arraylist != null && sb.Length > 0)
                            {
                                arraylist.Add(sb.ToString());
                                sb.Length = 0;
                            }
                            continue;
                        case ':':
                            key = DecodeString(regex, sb.ToString());
                            sb.Length = 0;
                            continue;
                    }
                }
            }
            sb.Append(c);
            if (escend) escbegin = false;
            if (escbegin) escend = true;
            else escend = false;
        }
        end = json.Length - 1;
        return dict; //theoretically shouldn't ever get here
    }

    private static string DecodeString(Regex regex, string str)
    {
        return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber))));
    }
}
于 2013-02-19T21:22:06.677 に答える
1

素晴らしい投稿をしてくれたピートと他の人たちにもう一度感謝します。私は、リレーショナル テーブルに格納された JSON を調べるのに非常に便利な SQL Server CLR スカラー関数をラップしました (MongoDB を使用するだけだと言う人もいるでしょう!)。

下記を参照してください:

    public class JsonHelper
{
    /// <summary>
    /// Parses the JSON.
    /// Thanks to http://stackoverflow.com/questions/14967618/deserialize-json-to-class-manually-with-reflection
    /// </summary>
    /// <param name="json">The json.</param>
    /// <returns></returns>
    public static Dictionary<string, object> DeserializeJson(string json)
    {
        int end;

        return DeserializeJson(json, 0, out end);
    }

    /// <summary>
    /// Parses the JSON.
    /// </summary>
    /// <param name="json">The json.</param>
    /// <param name="start">The start.</param>
    /// <param name="end">The end.</param>
    /// <returns></returns>
    private static Dictionary<string, object> DeserializeJson(string json, int start, out int end)
    {
        var dict = new Dictionary<string, object>();
        var escbegin = false;
        var escend = false;
        var inquotes = false;
        string key = null;
        var sb = new StringBuilder();
        List<object> arraylist = null;
        var regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
        var autoKey = 0;
        var inSingleQuotes = false;
        var inDoubleQuotes = false;

        for (var i = start; i < json.Length; i++)
        {
            var c = json[i];
            if (c == '\\') escbegin = !escbegin;
            if (!escbegin)
            {
                if (c == '"' && !inSingleQuotes)
                {
                    inDoubleQuotes = !inDoubleQuotes;
                    inquotes = !inquotes;
                    if (!inquotes && arraylist != null)
                    {
                        arraylist.Add(DecodeString(regex, sb.ToString()));
                        sb.Length = 0;
                    }

                    continue;
                }

                if (c == '\'' && !inDoubleQuotes)
                {
                    inSingleQuotes = !inSingleQuotes;
                    inquotes = !inquotes;
                    if (!inquotes && arraylist != null)
                    {
                        arraylist.Add(DecodeString(regex, sb.ToString()));
                        sb.Length = 0;
                    }

                    continue;
                }

                if (!inquotes)
                {
                    switch (c)
                    {
                        case '{':
                            if (i != start)
                            {
                                int cend;
                                var child = DeserializeJson(json, i, out cend);
                                if (arraylist != null)
                                {
                                    arraylist.Add(child);
                                }
                                else
                                {
                                    dict.Add(key.Trim(), child);
                                    key = null;
                                }

                                i = cend;
                            }

                            continue;

                        case '}':
                            end = i;

                            if (key != null)
                            {
                                if (arraylist != null) dict.Add(key.Trim(), arraylist);
                                else dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
                            }

                            return dict;

                        case '[':
                            arraylist = new List<object>();
                            continue;

                        case ']':
                            if (key == null)
                            {
                                key = "array" + autoKey;
                                autoKey++;
                            }

                            if (arraylist != null && sb.Length > 0)
                            {
                                arraylist.Add(sb.ToString());
                                sb.Length = 0;
                            }

                            dict.Add(key.Trim(), arraylist);
                            arraylist = null;
                            key = null;
                            continue;

                        case ',':
                            if (arraylist == null && key != null)
                            {
                                dict.Add(key.Trim(), DecodeString(regex, sb.ToString().Trim()));
                                key = null;
                                sb.Length = 0;
                            }

                            if (arraylist != null && sb.Length > 0)
                            {
                                arraylist.Add(sb.ToString());
                                sb.Length = 0;
                            }

                            continue;

                        case ':':
                            key = DecodeString(regex, sb.ToString());
                            sb.Length = 0;

                            continue;
                    }
                }
            }

            sb.Append(c);

            if (escend) escbegin = false;
            escend = escbegin;
        }

        end = json.Length - 1;
        return dict; // theoretically shouldn't ever get here
    }

    /// <summary>
    /// Decodes the string.
    /// </summary>
    /// <param name="regex">The regex.</param>
    /// <param name="str">The STR.</param>
    /// <returns></returns>
    private static string DecodeString(Regex regex, string str)
    {
        return
            Regex.Unescape(regex.Replace(str,
                match =>
                    char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value,
                        System.Globalization.NumberStyles
                            .HexNumber))));
    }

    /// <summary>
    /// Returns true if string has an "appearance" of being JSON-like
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static bool IsJson(string input)
    {
        input = input.Trim();
        return input.StartsWith("{") && input.EndsWith("}")
               || input.StartsWith("[") && input.EndsWith("]");
    }
}

CLR 関数は以下のとおりです。

/// <summary>
/// Json "extractor" capable of extracting a value of a key using the object notation.
/// </summary>
/// <param name="json"></param>
/// <param name="key"></param>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString fn_GetKeyValue(SqlString json, SqlString key)
{
    var jsonString = json.ToString();

    // Return if N/A
    if (string.IsNullOrEmpty(jsonString) || !JsonHelper.IsJson(jsonString))
    {
        return json;
    }

    var keyString = key.ToString();

    var jsonDictionary = JsonHelper.DeserializeJson(jsonString);
    var lastNode = string.Empty;

    foreach (var node in keyString.Split('.'))
    {
        if (!jsonDictionary.ContainsKey(node)) continue;

        var childDictionary = jsonDictionary[node] as Dictionary<string, object>;

        if (childDictionary != null)
        {
            jsonDictionary = childDictionary;
        }

        lastNode = node;
    }

    if (!jsonDictionary.ContainsKey(lastNode))
    {
        return null;
    }

    var keyValueString = jsonDictionary[lastNode].ToString();

    return keyValueString == "null" ? null : new SqlString(keyValueString);
}

使用法は次のとおりです。

-- Example 1 (querying a parent node)
SELECT  dbo.fn_GetKeyValue('{
    "ExchangeRates": {
        "GBP": "1.2",
        "USD": "2.0"
    },
    "Timestamp": "2015-04-10"
}', 'Timestamp');

-- Example 2 (querying a child node using a dot notation)
SELECT  dbo.fn_GetKeyValue('{
    "ExchangeRates": {
        "GBP": "1.2",
        "USD": "2.0"
    },
    "Timestamp": "2015-04-10"
}', 'ExchangeRates.GBP');
于 2015-04-10T07:50:22.883 に答える