Saurav Saurav - 3 months ago 24
C# Question

How to remove parent element of each collection and represent it as array in json

I have the following XML:

<Envelops
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<BusinessPartners>
<CardCode>L10002</CardCode>
<BPAddresses>
<row>
<AddressName>Bill To</AddressName>
<AddressType>bo_BillTo</AddressType>
<BPCode>L10002</BPCode>
<U_WBCUSTADDID>84</U_WBCUSTADDID>
<RowNum>0</RowNum>
</row>
</BPAddresses>
<U_WBCUSTID>74</U_WBCUSTID>
<UploadURL>BusinessPartners('L10002')</UploadURL>
</BusinessPartners>
</Envelops>


I am using Json.Net with the following code for serialization to JSON:

foreach (XmlNode data2 in d1.GetElementsByTagName("BusinessPartners"))
{
var requestBody = JsonConvert.SerializeXmlNode(data2, Newtonsoft.Json.Formatting.Indented, true);
}


I am getting the JSON format below:

{
"CardCode": "L10002",
"BPAddresses": {
"row": {
"AddressName": "Bill To",
"AddressType": "bo_BillTo",
"BPCode": "L10002",
"U_WBCUSTADDID": "84",
"RowNum": "0"
}
},
"U_WBCUSTID": "74",
"UploadURL": "BusinessPartners('L10002')"
}


What I would like to achieve is this format instead:

{
"CardCode": "L10002",
"BPAddresses": [{
"AddressName": "Bill To",
"AddressType": "bo_BillTo",
"BPCode": "L10002",
"U_WBCUSTADDID": "84",
"RowNum": "0"
}],
"U_WBCUSTID": "74",
"UploadURL": "BusinessPartners('L10002')"
}


How can I do this?

Answer

You'll need to do some manipulation on the XML prior to using SerializeXmlNode in order to get the result you want.

  1. Add a json:Array="true" attribute to the BPAddresses element to signal Json.Net to treat that element as part of an array when converted to JSON. (Note the json: attribute prefix corresponds to the http://james.newtonking.com/projects/json XML namespace.)
  2. Move the children of the row element directly into BPAddresses. If there's more than one row, then create additional BPAddresses elements as siblings of the original BPAddresses element for each row. (Make sure each new BPAddresses element also has the json:Array="true" attribute.)

The code below should give you what you need:

foreach (XmlElement data2 in d1.GetElementsByTagName("BusinessPartners"))
{
    XmlElement bpa = (XmlElement)data2.SelectSingleNode("BPAddresses");
    XmlElement insertionPoint = bpa;

    foreach (XmlElement row in bpa.GetElementsByTagName("row"))
    {
        // Create a new BPAddresses element and add an Array="true" attribute to it 
        // so JSON.Net will know to treat it as an array
        XmlElement addr = d1.CreateElement("BPAddresses");
        XmlAttribute attr = d1.CreateAttribute("Array", "http://james.newtonking.com/projects/json");
        attr.Value = "true";
        addr.Attributes.Append(attr);

        // move all the children of the row element into the new BPAddresses element
        foreach (XmlElement child in row.GetElementsByTagName("*").Cast<XmlElement>().ToList())
        {
            addr.AppendChild(child);
        }

        // insert the new element after the last BPAddresses element
        data2.InsertAfter(addr, insertionPoint);
        insertionPoint = addr;
    }

    // remove the original BPAddresses element (and its children)
    data2.RemoveChild(bpa);

    var requestBody = JsonConvert.SerializeXmlNode(data2, Formatting.Indented, true);
    Console.WriteLine(requestBody);
}

Fiddle: https://dotnetfiddle.net/ML0D6Z