questions/48561403/convert-json-to-newline-delimit-json

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;


using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;	


    // https://stackoverflow.com/questions/48561403/convert-json-to-newline-delimit-json
    public static class JsonExtensions
    {
        public static void ToNewlineDelimitedJson(Stream readStream, Stream writeStream)
        {
            var encoding = new UTF8Encoding(false, true);

            // Let caller dispose the underlying streams.
            using (var textReader = new StreamReader(readStream, encoding, true, 1024, true))
            using (var textWriter = new StreamWriter(writeStream, encoding, 1024, true))
            {
                ToNewlineDelimitedJson(textReader, textWriter);
            }
        }

        public static void ToNewlineDelimitedJson(TextReader textReader, TextWriter textWriter)
        {
            using (var jsonReader = new JsonTextReader(textReader) { CloseInput = false, DateParseHandling = DateParseHandling.None })
            {
                ToNewlineDelimitedJson(jsonReader, textWriter);
            }
        }

        enum State { BeforeArray, InArray, AfterArray };

        public static void ToNewlineDelimitedJson(JsonReader jsonReader, TextWriter textWriter)
        {
            var state = State.BeforeArray;
            do
            {
                if (jsonReader.TokenType == JsonToken.Comment || jsonReader.TokenType == JsonToken.None || jsonReader.TokenType == JsonToken.Undefined || jsonReader.TokenType == JsonToken.PropertyName)
                {
                    // Do nothing
                }
                else if (state == State.BeforeArray && jsonReader.TokenType == JsonToken.StartArray)
                {
                    state = State.InArray;
                }
                else if (state == State.InArray && jsonReader.TokenType == JsonToken.EndArray)
                {
                    state = State.AfterArray;
                }
                else
                {
                    // Formatting.None is the default; I set it here for clarity.
                    using (var jsonWriter = new JsonTextWriter(textWriter) { Formatting = Formatting.None, CloseOutput = false })
                    {
                        jsonWriter.WriteToken(jsonReader);
                    }
                    // http://specs.okfnlabs.org/ndjson/
                    // Each JSON text MUST conform to the [RFC7159] standard and MUST be written to the stream followed by the newline character \n (0x0A). 
                    // The newline charater MAY be preceeded by a carriage return \r (0x0D). The JSON texts MUST NOT contain newlines or carriage returns.
                    textWriter.Write("\n");

                    // Root value wasn't an array after all, so end writing with one item.
                    if (state == State.BeforeArray)
                        state = State.AfterArray;
                }
            }
            while (jsonReader.Read() && state != State.AfterArray);
        }
    }
    
    class TestClass
    {
        public static void Test()
        {
            var fromFileName = "fromFile.json";
            var toFileName = "toFile.json";

            try
            {
                File.WriteAllText(fromFileName, GetJson());

                using (var readStream = File.OpenRead(fromFileName))
                using (var writeStream = File.Open(toFileName, FileMode.Create))
                {
                    JsonExtensions.ToNewlineDelimitedJson(readStream, writeStream);
                }

				Console.WriteLine("\nTesting file streaming: ");
                Console.WriteLine(File.ReadAllText(toFileName));

                var json = GetJson();

				Console.WriteLine("\nTesting in-memory streaming: ");
				
                Test(json);

                Test(JToken.Parse(json).ToString(Formatting.Indented));

				Test("null");

				Test("[[null]]");
			}
            finally
            {
                try
                {
                    if (File.Exists(fromFileName))
                        File.Delete(fromFileName);
                }
                catch (Exception)
                {
                }
                try
                {
                    if (File.Exists(toFileName))
                        File.Delete(toFileName);
                }
                catch (Exception)
                {
                }
            }

            Console.WriteLine("\nDone");
        }

        private static void Test(string json)
        {
            using (var reader = new StringReader(json))
            using (var writer = new StringWriter())
            {
                JsonExtensions.ToNewlineDelimitedJson(reader, writer);
                Console.WriteLine(writer);
            }

            var root1 = new JArray(JToken.Parse(json), JToken.Parse(json));

            using (var reader = root1[0].CreateReader())
            using (var writer = new StringWriter())
            {
                JsonExtensions.ToNewlineDelimitedJson(reader, writer);
                Console.WriteLine(writer);
            }

            var root2 = new JObject(new JProperty("Data", JToken.Parse(json)));

            using (var reader = root2.CreateReader())
            {
                while (reader.TokenType != JsonToken.StartObject)
                    reader.Read();
                using (var writer = new StringWriter())
                {
                    JsonExtensions.ToNewlineDelimitedJson(reader, writer);
                    Console.WriteLine(writer);
                }
            }

            using (var reader = root2.Property("Data").CreateReader())
            using (var writer = new StringWriter())
            {
                JsonExtensions.ToNewlineDelimitedJson(reader, writer);
                Console.WriteLine(writer);
            }
        }

        static string GetJson()
        {
            var json = @"[{""DashboardCategoryId"": 1,""BookingCategoryId"": 3,""BookingChannelId"": 4,""ForDate"": ""2018-01-04"",""BookingCount"": 3,""QuoteCount"": 0,""TotalRevenue"": 2900.5,""AverageDailyRental"": 391.6,""AverageStayLength"": 5,""MarketingCost"": 293,""InlineCost"": 0,""BookingWindows"": [{""DaysRange"": ""31-60 Days"",""BookingNumber"":2},{""DaysRange"": ""Greater Than 1 year"",""BookingNumber"": 1}]},
    {""DashboardCategoryId"": 1,""BookingCategoryId"": 2,""BookingChannelId"": 26,""ForDate"": ""2018-01-04"",""BookingCount"": 2,""QuoteCount"": 0,""TotalRevenue"": 2900.5,""AverageDailyRental"": 391.6,""AverageStayLength"": 5,""MarketingCost"": 293,""InlineCost"": 0,""BookingWindows"": [{""DaysRange"": ""61-120 Days"",""BookingNumber"":1},{""DaysRange"": ""8-14"",""BookingNumber"": 1}]}
    ]";
            return json;
        }
    }

	public class Program
	{
		public static void Main()
		{
			Console.WriteLine("Environment version: " + Environment.Version);
			Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
			Console.WriteLine();

			try
			{
				TestClass.Test();
			}
			catch (Exception ex)
			{
				Console.WriteLine("Failed with unhandled exception: ");
				Console.WriteLine(ex);
				throw;
			}
		}
	}

    public class AssertionFailedException : System.Exception
    {
        public AssertionFailedException() : base() { }

        public AssertionFailedException(string s) : base(s) { }
    }

    public static class Assert
    {
        public static void IsTrue(bool value)
        {
            IsTrue(value, "failed");
        }

        public static void IsTrue(bool value, string message)
        {
            if (value == false)
                throw new AssertionFailedException(message ?? "failed");
        }
    }
;