using System.Collections.Generic;
public class DataSplitter
public enum State { Root, Steps, StepObj, Data, DataObj };
private readonly List<string> templateParts;
public static DataSplitter Create(TextReader source)
var splitter = new DataSplitter();
var buffer = new StringBuilder();
var bufferWriter = new StringWriter(buffer);
using (var reader = new JsonTextReader(source))
using (var writer = new JsonTextWriter(bufferWriter))
writer.WriteToken(reader.TokenType, reader.Value);
if (reader.TokenType == JsonToken.StartArray && reader.Path == "Job.Steps")
if (reader.TokenType == JsonToken.StartObject)
else if (reader.TokenType == JsonToken.EndArray)
writer.WriteToken(reader.TokenType, reader.Value);
writer.WriteToken(reader.TokenType, reader.Value);
if (reader.TokenType == JsonToken.StartArray && reader.Path == $"Job.Steps[{stepIndex}].InstrumentData")
else if (reader.TokenType == JsonToken.EndObject && reader.Path == $"Job.Steps[{stepIndex}]")
if (reader.TokenType == JsonToken.EndArray && reader.Path == $"Job.Steps[{stepIndex}].InstrumentData")
writer.WriteToken(reader.TokenType, reader.Value);
splitter.templateParts.Add(buffer.ToString());
this.templateParts = new List<string>();
public void Split(TextReader source, Action<int, int, string> handler)
var buffer = new StringBuilder(GetStart());
var bufferWriter = new StringWriter(buffer);
var bufferStepsStart = buffer.Length;
var bufferDataStart = -1;
using (var reader = new JsonTextReader(source))
using (var writer = new JsonTextWriter(bufferWriter))
if (reader.TokenType == JsonToken.StartArray && reader.Path == "Job.Steps")
if (reader.TokenType == JsonToken.StartObject)
buffer.Append(GetStepStart(++stepIndex));
bufferDataStart = buffer.Length;
else if (reader.TokenType == JsonToken.EndArray)
if (reader.TokenType == JsonToken.StartArray && reader.Path == $"Job.Steps[{stepIndex}].InstrumentData")
else if (reader.TokenType == JsonToken.EndObject && reader.Path == $"Job.Steps[{stepIndex}]")
buffer.Length = bufferStepsStart;
if (reader.TokenType == JsonToken.StartObject)
writer.WriteToken(reader.TokenType, reader.Value);
else if (reader.TokenType == JsonToken.EndArray)
writer.WriteToken(reader.TokenType, reader.Value);
if (reader.TokenType == JsonToken.EndObject && reader.Path == $"Job.Steps[{stepIndex}].InstrumentData[{dataIndex}]")
buffer.Append(GetStepEnd(stepIndex));
handler(stepIndex, dataIndex, buffer.ToString());
buffer.Length = bufferDataStart;
private string GetStart() => templateParts[0];
private string GetEnd() => templateParts[templateParts.Count - 1];
private string GetStepStart(int index) => templateParts[index * 2 + 1];
private string GetStepEnd(int index) => templateParts[index * 2 + 2];
public static void Main()
var reader = new StringReader(JsonText);
var splitter = DataSplitter.Create(reader);
reader = new StringReader(JsonText);
splitter.Split(reader, (step, index, content) => {
Console.WriteLine("=== step: {0}, index: {1} ===", step, index);
Console.WriteLine(content);
private const string JsonText = @"{
""FileType"": ""Measurements"",
""InstrumentDescriptions"": [
""InstrumentID"": ""1723007"",
""InstrumentType"": ""Actual1"",
""DataType"": ""Double"",
""InstrumentID"": ""2424009"",
""InstrumentType"": ""Actual2"",
""DataType"": ""Double"",
""StepResult"": ""NormalEnd""
""InstrumentID"": ""1723007""
""DateTime"": ""2021-11-16 21:18:37.000"",
""DateTime"": ""2021-11-16 21:18:37.100"",
""DateTime"": ""2021-11-16 21:18:37.200"",
""DateTime"": ""2021-11-16 21:18:37.300"",
""DateTime"": ""2021-11-16 21:18:37.400"",
""DateTime"": ""2021-11-16 21:18:37.500"",
""DateTime"": ""2021-11-16 21:18:37.600"",
""DateTime"": ""2021-11-16 21:18:37.700"",
""DateTime"": ""2021-11-16 21:18:37.800"",
""InstrumentID"": ""2424009""
""DateTime"": ""2021-11-16 21:18:37.000"",
""DateTime"": ""2021-11-16 21:18:37.100"",
""DateTime"": ""2021-11-16 21:18:37.200"",
""DateTime"": ""2021-11-16 21:18:37.300"",
""DateTime"": ""2021-11-16 21:18:37.400"",
""DateTime"": ""2021-11-16 21:18:37.500"",
""DateTime"": ""2021-11-16 21:18:37.600"",
""DateTime"": ""2021-11-16 21:18:37.700"",
""DateTime"": ""2021-11-16 21:18:37.800"",