Извлечение измерений из узлов XML
Я анализирую большие XML-файлы, используя Java 8 и XmlPath 1.0. Я хочу извлечь название теста, его измеренные значения и результат (пройден или не пройден). Каждый тест может иметь несколько TestResult, который содержит один из двух типов ограничений:
- SingleLimit, который будет иметь только один
LimitPair, которая всегда будет иметь два ограничения
<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>
В настоящее время я использую эти пути для извлечения измерений PairLimit и для создания строк, содержащих значения.
Мой вопрос заключается в том, как мне написать код / xPaths, чтобы позаботиться о возможном множестве TestResults в одном тесте.
В начале я предположил, что у Test может быть только PairLimit или SingleLimit, что было неверно. Мой текущий код правильно извлекает все значения, но назначенные измерения неверны, когда внутри Test есть много TestResults.
Например, если Test ID = 1 содержит 3 (три) TestResults, то в последней строке, содержащей измерения, у меня будут значения из первого теста в течение секунды, потому что он "переопределит" значения.
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();
}
}
1 ответ
Вы можете просто перебрать каждый Test, затем перебрать каждый TestResult, а затем поместить логику в TestLimits и т.д.
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)));
}
}