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 的代码,它反序列化为 aDictionary<string, object>以便能够反序列化数组的数组,这是它无法做到的,我还开发了一些方法来将生成的 Dictionary 转换为强类型对象而不使用JavaScriptConverterSystem.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 字符串和可选的 a 作为输入,Dictionary<string, string>并将尝试将其转换为 TypeT字典用于将 JSON 字符串上的任何属性映射到对象的属性(例如,“jdata”/“数据”上面声明的字典)。

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(末尾的两个 'result =' 行DynamicJsonObject.TryGetMember())。如有必要,也可以用哈希表替换通用字典。

json 解析器改编自How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?

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

再次感谢皮特和其他人的精彩帖子。我用一个 SQL Server CLR 标量函数包装了我的,它在查询存储在关系表中的 JSON 时非常有用(我知道有些人会说只使用 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 回答