Collapse Numbered Siblings in XML
Updated: Oct 5, 2026
This example shows how to read numbered XML elements 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 sibling elements whose names follow a derivable pattern into one node, so each item is read as its own record. The element name is preserved in the order_item field and the sku and price attributes become fields alongside the qty child element. The JSON version of this example is Collapse Numbered Siblings in JSON.
Input XML file
<?xml version="1.0" encoding="UTF-8"?>
<order id="po-1001">
<item-1 sku="A100" price="9.99">
<qty>2</qty>
</item-1>
<item-2 sku="B200" price="19.99">
<qty>1</qty>
</item-2>
<item-3 sku="C300" price="29.99">
<qty>5</qty>
</item-3>
<summary>
<total>8</total>
</summary>
</order>
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.xml.XmlReader;
public class CollapseNumberedSiblingsInXml {
public static void main(String[] args) {
File inputFile = new File("example/data/input/tree/numbered_items.xml");
TreeDetectionStrategy strategy = TreeDetectionStrategy.standard(true)
.enableSiblingPatternCollapse();
Tree tree = Tree.loadXml(inputFile, strategy);
XmlReader reader = new XmlReader(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.xml.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.loadXml(inputFile, strategy)loads the document into aTree. The collapse pass merges the three item elements into one wildcard node, which the detection passes mark as the record break. As in the JSON version, thesummaryelement beside the items becomes a fourth record carrying onlytotal.- A
XmlReaderis created on the same file and configured from the tree:tree.getAllFields()supplies the name and XPath expression of every detected field toaddField(). XML carries no type information, so every value arrives as a string. 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:[price]:STRING=[9.99]:String
3:[qty]:STRING=[2]:String
4:[total]:STRING=[null]
}
-----------------------------------------------
1 - Record (MODIFIED) {
0:[order_item]:STRING=[item-2]:String
1:[sku]:STRING=[B200]:String
2:[price]:STRING=[19.99]:String
3:[qty]:STRING=[1]:String
4:[total]:STRING=[null]
}
-----------------------------------------------
2 - Record (MODIFIED) {
0:[order_item]:STRING=[item-3]:String
1:[sku]:STRING=[C300]:String
2:[price]:STRING=[29.99]:String
3:[qty]:STRING=[5]:String
4:[total]:STRING=[null]
}
-----------------------------------------------
3 - Record (MODIFIED) {
0:[order_item]:STRING=[summary]:String
1:[sku]:STRING=[null]
2:[price]:STRING=[null]
3:[qty]:STRING=[null]
4:[total]:STRING=[8]:String
}
-----------------------------------------------
4 records
