Is there any way of parsing a JSON string without deserialising it?

243 Views Asked by At

I am calling a web service that returns JSON with a duplicate node in some circumstances, providing output similar to this:

{
    "shipments": [
        {
            "id": "A000001",
            "name": "20141208 140652",
            "type": "OUTLET",
            "date": "2014-12-08 14:06:52",
            "status": "SENT",
            "received_at": null,
            "created_at": "2014-12-08 14:06:52",
            "updated_at": null,
            "outlet_id": "SH000064"
        },
        {
            "id": "A000002",
            "name": "20141204 122650",
            "type": "SUPPLIER",
            "date": "2014-12-04 12:26:50",
            "outlet_id": "SH000064",
            "supplier_id": null,
            "status": "RECEIVED",
            "outlet_id": "SH000064",
            "received_at": "2014-12-04 12:28:43",
            "created_at": "2014-12-04 12:26:50",
            "updated_at": "2014-12-04 12:28:43"
        }
    ]
}

I am dependent on the provider of the service to fix this and this is not a priority for them so I have to deal with it. To handle this I am converting the JSON to XML, using the JsonReaderWriterFactory, and then removing the duplicate nodes from the resulting XML using the following routine:

protected virtual void RemoveDuplicateChildren(XmlNode node)
{
    if (node.NodeType != XmlNodeType.Element || !node.HasChildNodes)
    {
        return;
    }

    var xNode = XElement.Load(node.CreateNavigator().ReadSubtree());
    var duplicateNames = new List<string>();

    foreach (XmlNode child in node.ChildNodes)
    {
        var isBottom = this.IsBottomElement(child); // Has no XmlNodeType.Element type children

        if (!isBottom)
        {
            this.RemoveDuplicateChildren(child);
        }
        else
        {
            var count = xNode.Elements(child.Name).Count();

            if (count > 1 && !duplicateNames.Contains(child.Name))
            {
                duplicateNames.Add(child.Name);
            }
        }
    }

    if (duplicateNames.Count > 0)
    {
        foreach (var duplicate in duplicateNames)
        {
            var nodeList =  node.SelectNodes(duplicate);

            if (nodeList.Count > 1)
            {
                for (int i=1; i<nodeList.Count; i++)
                {
                    node.RemoveChild(nodeList[i]);
                 }
             }
        }
    }
}

I now in a separate area need to use the DataContractJsonSerializer to deserialise the JSON to a strongly typed object, using the following code:

DataContractJsonSerializer serialiser = new DataContractJsonSerializer(typeof(ShipmentList));
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json));

var result = serialiser.ReadObject(stream);

This fails when the JSON contains that duplicate node, so I need to implement the same functionality as in the RemoveDuplicateChildren method but stepping through the JSON instead of an XML node, before the deserialisation. I can't use the quick-and-dirty option of using JsonConvert to convert to XML, removing the node with my existing method, then converting back to JSON because of the changes in the JSON that will result from the conversion to and from XML. Is there an equivalent way of navigating through a JSON hierarchy in C# as is provided by the XmlNode class?

UPDATE:

This question has become obfuscated by some of the comments. To clarify, the nodes I want to remove from the JSON are any nodes that are a repeat (by name, the content is irrelevant) at the same level of the same parent, such as the second "outlet_id" of the second "shipments" item in the example above. I need to do this in a generic way without hard coded element names. The RemoveDuplicateChildren method above does exactly what is needed, I'm just asking if there is a class I can use to do exactly the same as that method on a JSON string instead of an XML string.

0

There are 0 best solutions below