Краткое описание XPath состоит в том, что он состоит из набора выражений, используемых для навигации по XML-документам. XPath обеспечивает иерархическую адресацию узлов в XML-дереве. Следует отметить, что новая версия XPath также может использоваться для обработки файлов JSON таким же образом.

<?xml version="1.0" encoding="UTF-8"?>
<SHIPMENT>
    <IDOC BEGIN="1">
        <E1EDL24 SEGMENT="1">
            <E1EDL11 SEGMENT="1">
                <SERNR>000558896</SERNR>
            </E1EDL11>
            <E1EDL11 SEGMENT="1">
                <SERNR>000558897</SERNR>
            </E1EDL11>
            <E1EDL11 SEGMENT="1">
                <SERNR>000558898</SERNR>
            </E1EDL11>
            <E1EDL11 SEGMENT="1">
                <SERNR>000558899</SERNR>
            </E1EDL11>
        </E1EDL24>
        <E1EDL37 SEGMENT="1">
            <EXIDV>00000000000099999996</EXIDV>
            <GWEIT>KGM</GWEIT>
            <NTGEW>61155.000</NTGEW>
            <GWEIM>KGM</GWEIM>
            <VEGR2>UNDEF</VEGR2>
            <EXIDV2>000558896</EXIDV2>
        </E1EDL37>
        <E1EDL37 SEGMENT="1">
            <EXIDV>00000000000099999997</EXIDV>
            <GWEIT>KGM</GWEIT>
            <NTGEW>63172.000</NTGEW>
            <GWEIM>KGM</GWEIM>
            <VEGR2>UNDEF</VEGR2>
            <EXIDV2>000558897</EXIDV2>
        </E1EDL37>
        <E1EDL37 SEGMENT="1">
            <EXIDV>00000000000099999998</EXIDV>
            <GWEIT>KGM</GWEIT>
            <NTGEW></NTGEW>
            <GWEIM>KGM</GWEIM>
            <VEGR2>UNDEF</VEGR2>
            <EXIDV2>000558898</EXIDV2>
        </E1EDL37>
    <E1EDL37 SEGMENT="1">
            <EXIDV>00000000000099999998</EXIDV>
            <GWEIT>KGM</GWEIT>
            <NTGEW>33659.000</NTGEW>
            <GWEIM>KGM</GWEIM>
            <VEGR2>UNDEF</VEGR2>
            <EXIDV2>000558899</EXIDV2>
        </E1EDL37>
    </IDOC>
</SHIPMENT>

В этой статье мы будем использовать приведенный выше XML-файл в качестве базового файла для некоторых методов.

Инициализация документа

Прежде чем мы погрузимся в волшебный мир выражений XPath, давайте создадим экземпляр для анализа нашего файла и создадим причудливый объект документа DOM.

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse(getFileInBytes());

Теперь, вот! Я вызову мощный метод getFileInBytes, который любезно вернет наш XML-файл в виде InputStream. Конечно, если вам хочется приключений, вы можете поэкспериментировать с другими типами параметров, чтобы вызвать метод parse. Проверьте эти разрешенные сигнатуры методов:

public Document parse(InputStream is)
public Document parse(InputStream is, String systemId)
public Document parse(String uri)
public Document parse(File f)
public Document parse(InputSource is)

Сначала оцените

Хорошо, теперь, когда мы настроили наше моджо для синтаксического анализа XML, пришло время воспользоваться мощью XPath и создать несколько потрясающих структур на основе наших выражений.

Но ждать! Прежде чем мы продолжим, позвольте мне дать вам краткий обзор этих увлекательных выражений. Полюбуйтесь на эту удобную таблицу:

  • Чтобы увидеть функции, поддерживаемые Xpath, вы можете перейти по этой ссылке.

Фантастика! Вооружившись этими знаниями, теперь мы можем вызвать метод компиляции и раскрыть всю мощь XPath.

xPath.compile("//E1EDL11[2]").evaluate(document);

По умолчанию метод оценки возвращает строку (XPathConstants.STRING), если мы не указываем возвращаемый тип. Однако, если вы хотите что-то изменить, просто добавьте желаемый тип возвращаемого значения перед вызовом метода на основе мощных XPathConstants.

(NodeList) xPath.compile("//E1EDL11[2]").evaluate(document, XPathConstants.NODESET)

Теперь давайте поговорим о NodeList, не так ли? Это великолепное создание представляет собой список узлов, каждый из которых представляет собой великолепный объект в дереве документа.

При работе с NodeList у вас есть возможность перебирать эти великолепные существа и извлекать информацию непосредственно из каждого из них.

Извлечение значений из определенного выражения

Чтобы уточнить, давайте создадим метод, который будет извлекать некоторые данные из нашей базы XML и выводить их на консоль.

void shouldReturnDataBasedOnGivenExpression() {
    final String EXPRESSION = "//E1EDL11[SERNR=000558897 or SERNR=000558896 or SERNR=000558896]";

    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = builderFactory.newDocumentBuilder();
    Document document = builder.parse(getClass().getResourceAsStream("/xpath/dummy.xml"));
    XPath xPath = XPathFactory.newInstance().newXPath();
    NodeList nodeList = (NodeList) xPath.compile(EXPRESSION).evaluate(document, XPathConstants.NODESET);
    assertNotNull(evaluate);
    printNodeList(nodeList);
}

private void printNodeList(NodeList nodeList) {
    for(int i = 0; i < nodeList.getLength(); i++){
        System.out.println(String.format("Position %s, value: %s",
                i,
                nodeList.item(i).getTextContent().trim()));
    }
}

Наша переменная EXPRESSION ищет данные внутри узла E1EDL11, а значение SERNR находится в пределах следующих значений: 000558897, 000558896, 000558896.

Метод printNodeList вернет следующий вывод:

Position 0, value: 000558896
Position 1, value: 000558897
Position 2, value: 000558899

Но подождите, есть еще кое-что, что нужно знать о выражениях XPathExpressions! Обратите особое внимание, выражение будет возвращать только то, что соответствует. Пустые значения или подобные странности должны быть возвращены как пустые значения. Так что будьте осторожны, для этого выражения:

final String EXPRESSION = "//E1EDL37/NTGEW";

Вернется:

Position 0, value: 61155.000
Position 1, value: 63172.000
Position 2, value:
Position 3, value: 33659.000

Другой пример

Теперь давайте рассмотрим требование нашего уважаемого клиента:

Самый тяжелый груз на корабле. Принимая во внимание, что узел NTGEW представляет вес в кг.

Не бойся, мой дорогой читатель, я представлю решение этой головоломки. Один из подходов состоит в том, чтобы найти все значения в прославленном узле NTGEW и определить самое высокое среди них, используя некоторую хитрую логику. Разрешите продемонстрировать:

void shouldReturnHighestNTGEWValue() {
  final String EXPRESSION = "//E1EDL37/NTGEW/text()";
  
 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
  DocumentBuilder builder = builderFactory.newDocumentBuilder();
  Document document = builder.parse(getClass().getResourceAsStream("/xpath/dummy2.xml"));

  XPath xPath = XPathFactory.newInstance().newXPath();
  XPathExpression expr = xPath.compile(EXPRESSION);

  double highestValue = Double.MIN_VALUE;

  NodeList nodeList = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
  for (int i = 0; i < nodeList.getLength(); i++) {
      String value = nodeList.item(i).getNodeValue();
      if (!value.isEmpty()) {
          double numericValue = Double.parseDouble(value);
          highestValue = Math.max(highestValue, numericValue);
      }
  }

  System.out.println("Highest NTGEW value: " + highestValue);
}

Предупреждение

И последнее важное замечание: помните, что XPathExpression не является потокобезопасным. Приложение несет ответственность за то, чтобы этот объект не использовался одновременно несколькими потоками. Остерегайтесь гнева неудач, связанных с потоком!

И вот оно, дорогой читатель! Вооружившись этими знаниями, вы теперь готовы отправиться дальше и покорить чарующее царство выражений XPath. Идите вперед, и пусть ваши приключения по синтаксическому анализу XML будут наполнены триумфом и радостью!