如何使用c#将字符串中的分层键值对转换为json?

时间:2015-05-14 16:20:52

标签: c# asp.net json chargify

我有以下http帖子正文通过chargify的web钩子发送到asp.net web api。

id=38347752&event=customer_update&payload[customer][address]=qreweqwrerwq&payload[customer][address_2]=qwerewrqew&payload[customer][city]=ererwqqerw&payload[customer][country]=GB&payload[customer][created_at]=2015-05-14%2004%3A46%3A48%20-0400&payload[customer][email]=a%40test.com&payload[customer][first_name]=Al&payload[customer][id]=8619620&payload[customer][last_name]=Test&payload[customer][organization]=&payload[customer][phone]=01&payload[customer][portal_customer_created_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][portal_invite_last_accepted_at]=&payload[customer][portal_invite_last_sent_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][reference]=&payload[customer][state]=&payload[customer][updated_at]=2015-05-14%2011%3A25%3A19%20-0400&payload[customer][verified]=false&payload[customer][zip]=&payload[site][id]=26911&payload[site][subdomain]=testsubdomain

如何使用c#将此有效负载[customer] [address] = value等转换为json字符串?

1 个答案:

答案 0 :(得分:0)

你当前的问题

  

如何使用c#将chargify webhooks转换为json?

可以推广到

如何从字符串中提取键值对,将它们转换为相应的层次结构并以JSON格式返回?

回答你的问题:

string rawData = "id=38347752&event=customer_update&payload[customer][address]=qreweqwrerwq&payload[customer][address_2]=qwerewrqew&payload[customer][city]=ererwqqerw&payload[customer][country]=GB&payload[customer][created_at]=2015-05-14%2004%3A46%3A48%20-0400&payload[customer][email]=a%40test.com&payload[customer][first_name]=Al&payload[customer][id]=8619620&payload[customer][last_name]=Test&payload[customer][organization]=&payload[customer][phone]=01&payload[customer][portal_customer_created_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][portal_invite_last_accepted_at]=&payload[customer][portal_invite_last_sent_at]=2015-05-14%2004%3A46%3A49%20-0400&payload[customer][reference]=&payload[customer][state]=&payload[customer][updated_at]=2015-05-14%2011%3A25%3A19%20-0400&payload[customer][verified]=false&payload[customer][zip]=&payload[site][id]=26911&payload[site][subdomain]=testsubdomain";
ChargifyWebHook webHook = new ChargifyWebHook(rawData);
JSONNode node = new JSONNode("RootOrWhatEver");

foreach (KeyValuePair<string, string> keyValuePair in webHook.KeyValuePairs)
{
    node.InsertInHierarchy(ChargifyWebHook.ExtractHierarchyFromKey(keyValuePair.Key), keyValuePair.Value);
}

string result = node.ToJSONObject();

使用指定的输入,结果如下所示(没有换行符):

{
    "id": "38347752",
    "event": "customer_update",
    "payload": {
                   "customer": {
                                   "address": "qreweqwrerwq",
                                   "address_2": "qwerewrqew",
                                   "city": "ererwqqerw",
                                   "country": "GB",
                                   "created_at": "2015-05-14 04:46:48 -0400",
                                   "email": "a@test.com",
                                   "first_name": "Al",
                                   "id": "8619620",
                                   "last_name": "Test",
                                   "organization": "",
                                   "phone": "01",
                                   "portal_customer_created_at": "2015-05-14 04:46:49 -0400",
                                   "portal_invite_last_accepted_at": "",
                                   "portal_invite_last_sent_at": "2015-05-14 04:46:49 -0400",
                                   "reference": "",
                                   "state": "",
                                   "updated_at": "2015-05-14 11:25:19 -0400",
                                   "verified": "false",
                                   "zip": ""
                               },
                       "site": {
                                   "id": "26911",
                                   "subdomain": "testsubdomain"
                               }
               }
}

由于您的问题不仅限于1,2或3级,您显然需要递归解决方案。因此,我创建了一个JSONNode类,它可以通过将层次结构指定为List<string>来插入子项。

如果以A.B.C为例,在开始时方法InsertIntoHierarchy检查是否需要更多级别(取决于指定条目的长度,在我们的例子中,我们将得到一个包含ABC的列表,如果是这样,它会插入一个具有指定name级别的子项(用作容器)并将问题传递给此儿童。当然,在该步骤中删除了当前递归级别的名称,因此根据我们的示例,将添加包含name A的容器,并且列表包含B和{{1会被传递给这个容器。如果达到最后一级递归,将插入包含Cname的节点。

要使解决方案正常运行,您需要以下两个类:

<强> ChargifyWebHook

value

<强> JSONNode

/// <summary>
/// Represents the chargify web hook class.
/// </summary>
public class ChargifyWebHook
{
    /// <summary>
    /// Indicates whether the raw data has already been parsed or not.
    /// </summary>
    private bool initialized;

    /// <summary>
    /// Contains the key value pairs extracted from the raw data.
    /// </summary>
    private Dictionary<string, string> keyValuePairs;

    /// <summary>
    /// Initializes a new instance of the <see cref="ChargifyWebHook"/> class.
    /// </summary>
    /// <param name="data">The raw data of the web hook.</param>
    /// <exception cref="System.ArgumentException">Is thrown if the sepcified raw data is null or empty.</exception>
    public ChargifyWebHook(string data)
    {
        if (String.IsNullOrEmpty(data))
        {
            throw new ArgumentException("The specified value must neither be null nor empty", data);
        }

        this.initialized = false;
        this.keyValuePairs = new Dictionary<string, string>();
        this.RawData = data;
    }

    /// <summary>
    /// Gets the raw data of the web hook.
    /// </summary>
    public string RawData
    {
        get;
        private set;
    }

    /// <summary>
    /// Gets the key value pairs contained in the raw data.
    /// </summary>
    public Dictionary<string, string> KeyValuePairs
    {
        get
        {
            if (!initialized)
            {
                this.keyValuePairs = ExtractKeyValuesFromRawData(this.RawData);
                initialized = true;
            }

            return this.keyValuePairs;
        }
    }

    /// <summary>
    /// Extracts the key value pairs from the specified raw data.
    /// </summary>
    /// <param name="rawData">The data which contains the key value pairs.</param>
    /// <param name="keyValuePairSeperator">The pair seperator, default is '&'.</param>
    /// <param name="keyValueSeperator">The key value seperator, default is '='.</param>
    /// <returns>The extracted key value pairs.</returns>
    /// <exception cref="System.FormatException">Is thrown if an key value seperator is missing.</exception>
    public static Dictionary<string, string> ExtractKeyValuesFromRawData(string rawData, char keyValuePairSeperator = '&', char keyValueSeperator = '=')
    {
        Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();

        string[] rawDataParts = rawData.Split(new char[] { keyValuePairSeperator });

        foreach (string rawDataPart in rawDataParts)
        {
            string[] keyAndValue = rawDataPart.Split(new char[] { keyValueSeperator });

            if (keyAndValue.Length != 2)
            {
                throw new FormatException("The format of the specified raw data is incorrect. Key value pairs in the following format expected: key=value or key1=value1&key2=value2...");
            }

            keyValuePairs.Add(Uri.UnescapeDataString(keyAndValue[0]), Uri.UnescapeDataString(keyAndValue[1]));
        }

        return keyValuePairs;
    }

    /// <summary>
    /// Extracts the hierarchy from the key, e.g. A[B][C] will result in A, B and C.
    /// </summary>
    /// <param name="key">The key who's hierarchy shall be extracted.</param>
    /// <param name="hierarchyOpenSequence">Specifies the open sequence for the hierarchy speration.</param>
    /// <param name="hierarchyCloseSequence">Specifies the close sequence for the hierarchy speration.</param>
    /// <returns>A list of entries for the hierarchy names.</returns>
    public static List<string> ExtractHierarchyFromKey(string key, string hierarchyOpenSequence = "[", string hierarchyCloseSequence = "]")
    {
        if (key.Contains(hierarchyOpenSequence) && key.Contains(hierarchyCloseSequence))
        {
            return key.Replace(hierarchyCloseSequence, string.Empty).Split(new string[] { hierarchyOpenSequence }, StringSplitOptions.None).ToList();
        }

        if (key.Contains(hierarchyOpenSequence) && !key.Contains(hierarchyCloseSequence))
        {
            return key.Split(new string[] { hierarchyOpenSequence }, StringSplitOptions.None).ToList();
        }

        if (!key.Contains(hierarchyOpenSequence) && key.Contains(hierarchyCloseSequence))
        {
            return key.Split(new string[] { hierarchyCloseSequence }, StringSplitOptions.None).ToList();
        }

        return new List<string>() { key };
    }
}