3

I'm parsing large XMLs using Java 8 and XmlPath 1.0. I want to extract, name of the Test, his measured values and the outcome (Passed or Failed). Each Test can have many TestResult which contains one of the two types of limits:

  • SingleLimit, which will have only one < Limit comparator="XYZ">
  • LimitPair which will have always two limits

    <tr:Test ID = "282" name = "DIP1-8 High">  
        <tr:Extension>
            <ts:TSStepProperties>
                ...
            </ts:TSStepProperties>
        </tr:Extension>
        <tr:Outcome value = "Passed" /> <!-- value -->
        <tr:TestResult ID = "xyz" name = "TC 8.7.4 - Current breaker output J10:1-2"> <!-- name -->
        <tr:TestLimits>
            <tr:Limits>
                <c:LimitPair operator = "AND">
                    <c:Limit comparator = "GE">
                        <!-- value -->
                        <c:Datum nonStandardUnit = "V" value = "2.8" xsi:type="ts:TS_double" flags = "0x0000"/> 
                    </c:Limit>
                    <c:Limit comparator = "LE">
                        <!-- value -->
                        <c:Datum nonStandardUnit = "V" value = "3.5" xsi:type="ts:TS_double" flags = "0x0000"/>
                    </c:Limit>
                </c:LimitPair>
            </tr:Limits>
            </tr:TestLimits>
        </tr:TestResult>
    </tr:Test>
    

Currently I'm using these paths to extract PairLimit measurements and to create String containing values.

My question is how I should write code/xPaths to take care of possible many TestResults inside one Test.

I assumed at the beginning that Test can have only PairLimit or SingleLimit, which was wrong. My current code extract all values correctly, but assigned measurements are incorrect when there are many TestResults inside Test.

For instance, if Test ID = 1 contains 3 (three) TestResults then in the final String containing measurements, I will have values from first Test inside second, because it will "override" the values.

        private ArrayList<String> preparePairLimitPaths() {
    final ArrayList<String> list = new ArrayList<>();
    list.add("//Test[TestResult//LimitPair]/@name");
    list.add("//Test/TestResult[TestLimits//LimitPair]/TestData/Datum/@value");
    list.add("//Test/TestResult/TestLimits/Limits/LimitPair/Limit[*]/Datum/@value");
    list.add("//Test/TestResult/TestLimits/Limits/LimitPair/Limit[*]/Datum/@value");
    list.add("//Test[TestResult//TestLimits//LimitPair]/Outcome/@value");
    return list;
}
for (String expr : preparePairLimitPaths) {
    try {
        final NodeList evaluate = (NodeList) xPath.evaluate(expr, parse, XPathConstants.NODESET);
        for (int i = 0; i < evaluate.getLength(); i++) {
            final String textContent = evaluate.item(i).getTextContent();
            if (textContent != null && !textContent.isEmpty()) {
                stringBuilder.append(textContent).append(";");
            }
        }
        stringBuilder.append("@@@");
    } catch (XPathExpressionException e) {
        e.printStackTrace();
    }
}
nanomader
  • 410
  • 9
  • 22

1 Answers1

4

You can just iterate over each Test and then iterate over each TestResult and then put the logic with TestLimits etc.

    NodeList allTests = (NodeList) xPath.evaluate("/xml/Test", xmlDocument, XPathConstants.NODESET);
    for (int i = 0; i < tests.getLength(); i++) {
        Element singleTest = (Element) tests.item(i);
        // Here, you can extract some values from your test like:
        // testOutcome = xPath.evaluate("Outcome/@value", singleTest);

        NodeList testResults = (NodeList) xPath.evaluate("TestResult",test, XPathConstants.NODESET);

        for (int j=0; j<testResults.getLength(); j++) {
            // Now you can iterate over all your testResults from test
            // testResultName = xPath.evaluate("@name",testResults.item(j)));
        }
    }
mkuligowski
  • 1,544
  • 1
  • 17
  • 27