Collapse Numbered Siblings in JSON
Updated: Oct 5, 2026
This example shows how to read numbered siblings such as item-1, item-2 and item-3 as a repeating list of records. Calling enableSiblingPatternCollapse() on the TreeDetectionStrategy inserts a CollapseSiblingPatterns pass ahead of the detection passes; it merges siblings whose names follow a derivable pattern into one node, so each item is read as its own record. The original element name is preserved in the order_item field. The XML version of this example is Collapse Numbered Siblings in XML.
Input JSON file
{
"order": {
"item-1": { "sku": "A100", "qty": 2 },
"item-2": { "sku": "B200", "qty": 1 },
"item-3": { "sku": "C300", "qty": 5 },
"summary": { "total": 8 }
}
}
Java Code Listing
package com.northconcepts.datapipeline.foundations.examples.tree;
import java.io.File;
import com.northconcepts.datapipeline.core.DataWriter;
import com.northconcepts.datapipeline.core.StreamWriter;
import com.northconcepts.datapipeline.foundations.pipeline.tree.Tree;
import com.northconcepts.datapipeline.foundations.pipeline.tree.detect.TreeDetectionStrategy;
import com.northconcepts.datapipeline.job.Job;
import com.northconcepts.datapipeline.json.JsonReader;
public class CollapseNumberedSiblingsInJson {
public static void main(String[] args) {
File inputFile = new File("example/data/input/tree/numbered_items.json");
TreeDetectionStrategy strategy = TreeDetectionStrategy.standard(true)
.enableSiblingPatternCollapse();
Tree tree = Tree.loadJson(inputFile, strategy);
JsonReader reader = new JsonReader(inputFile);
tree.getAllFields().forEach(node -> reader.addField(node.getFieldName(), node.getXpathExpression()));
tree.getAllRecordBreaks().forEach(node -> reader.addRecordBreak(node.getXpathExpression()));
DataWriter writer = StreamWriter.newSystemOutWriter();
Job.run(reader, writer);
}
}
Code Walkthrough
inputFilepoints atnumbered_items.json.TreeDetectionStrategy.standard(true)returns the default detection strategy; thetrueargument turns on tree optimization, which merges dynamically named nodes into a single wildcard node while the tree is being built.enableSiblingPatternCollapse()adds the sibling pattern pass.Tree.loadJson(inputFile, strategy)loads the document into aTree. The collapse pass mergesitem-1,item-2anditem-3into one wildcard node, and the detection passes then mark that node as the record break withskuandqtyas its fields. Thesummaryobject sits beside the items underorder, so it is read as a fourth record whosetotalis filled and whose item fields are null; filter it out downstream if only the items are wanted.- A
JsonReaderis created on the same file and configured from the tree:tree.getAllFields()supplies the name and XPath expression of every detected field toaddField().order_itemholds the element name,skuandqtythe item values andtotalthe summary value. tree.getAllRecordBreaks()supplies the XPath of the record node toaddRecordBreak().Job.run()streams the records to aStreamWriteron the console.
Console Output
-----------------------------------------------
0 - Record (MODIFIED) {
0:[order_item]:STRING=[item-1]:String
1:[sku]:STRING=[A100]:String
2:[qty]:LONG=[2]:Long
3:[total]:STRING=[null]
}
-----------------------------------------------
1 - Record (MODIFIED) {
0:[order_item]:STRING=[item-2]:String
1:[sku]:STRING=[B200]:String
2:[qty]:LONG=[1]:Long
3:[total]:STRING=[null]
}
-----------------------------------------------
2 - Record (MODIFIED) {
0:[order_item]:STRING=[item-3]:String
1:[sku]:STRING=[C300]:String
2:[qty]:LONG=[5]:Long
3:[total]:STRING=[null]
}
-----------------------------------------------
3 - Record (MODIFIED) {
0:[order_item]:STRING=[summary]:String
1:[sku]:STRING=[null]
2:[qty]:STRING=[null]
3:[total]:LONG=[8]:Long
}
-----------------------------------------------
4 records
