Premt
Premt

Reputation: 81

Newtonsoft Object serialized to String. JObject instance expected

Hi so am trying to parse this JSON line but i got some others that are like this in files thats why i want to automate this so i can remove the invalid lines to make the file a valid JSON for reading, The problem is that the JSON contains multiple JSON in 1 line

Example:

{"item":"value"}{"anotheritem":"value"}

Is there anyway to remove

{"anotheritem":"value"}

So it turns in to a valid JSON that is readable to start parsing the files

I tried doing using StreamReader cause there in a file i have multiple files that contain these invalid JSON

So i got it to be able to detect the Invalid JSON but for some reason i can't get it to read the JSON so i can use .remove to remove the invalid line

using (StreamReader r = new StreamReader(itemDir))
{
    string json = r.ReadToEnd();
    if (json.Contains("anotheritem"))
    {
        JObject NoGood = JObject.FromObject(json);
        MessageBox.Show(NoGood.ToString());
    }
}

The Error:

Object serialized to String. JObject instance expected.

Thank you all for your time and help.

Upvotes: 3

Views: 28693

Answers (2)

Kalten
Kalten

Reputation: 4302

If each object are side by side without space or any other character, you can convert your string to an json array.

string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
string arrayValue = "[" + value.Replace("}{", "},{") + "]";
var array = JArray.Parse(arrayValue);
var goopArray = array.OfType<JObject>().Where(o => o.Property("anotheritem") == null);

⚠️ Edit : see my second answer. More robust solution. More modern. And support dotnet core builtin json serializer.

Upvotes: 7

Kalten
Kalten

Reputation: 4302

Json.Net

Even better solution, Json.NET have a builtin feature for this exact scenario. See Read Multiple Fragments With JsonReader

The JsonTextReader have a property SupportMultipleContent that allow to read consecutive items when set to true

string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";

var reader = new JsonTextReader(new System.IO.StringReader(value));
reader.SupportMultipleContent = true;

var list = new List<JObject>();
while (reader.Read())
{
    var item = JObject.Load(reader);
    list.Add(item);
}

System.Text.Json

If you want to use System.Text.Json, it's also acheivable. They are no SupportMultipleContent property but Utf8JsonReader will do the job for you.

string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";

var bytes = Encoding.UTF8.GetBytes(value).AsSpan();

var list = new List<JsonDocument>();
while (bytes.Length != 0)
{
    var reader = new Utf8JsonReader(bytes);

    var item = JsonDocument.ParseValue(ref reader);
    list.Add(item);
    
    bytes = bytes.Slice((int) reader.BytesConsumed);
}

System.Text.Json Net 9

Dotnet 9 add an option to read multiple json documents. See here for the announcement. Set JsonReaderOptions.AllowMultipleValues to true will allow you to use a single instance of Utf8JsonReader and remove manual span slicing.

ReadOnlySpan<byte> value = """{"item":"value"}{"anotheritem":"value"}"""u8;

JsonReaderOptions options = new()
{
    AllowMultipleValues = true
};

var list = new List<JsonDocument>();

var reader = new Utf8JsonReader(value, options);
while (reader.Read())
{
    list.Add(JsonDocument.ParseValue(ref reader));
}

Upvotes: 1

Related Questions