Collapse Numbered Siblings in XML

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

  1. inputFile points at numbered_items.xml.
  2. TreeDetectionStrategy.standard(true) returns the default detection strategy; the true argument 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.
  3. Tree.loadXml(inputFile, strategy) loads the document into a Tree. 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, the summary element beside the items becomes a fourth record carrying only total.
  4. A XmlReader is created on the same file and configured from the tree: tree.getAllFields() supplies the name and XPath expression of every detected field to addField(). XML carries no type information, so every value arrives as a string.
  5. tree.getAllRecordBreaks() supplies the XPath of the record node to addRecordBreak().
  6. Job.run() streams the records to a StreamWriter on 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
Mobile Analytics