Использование функции text () при использовании xPath в dom4j - PullRequest
0 голосов
/ 28 марта 2012

Я унаследовал приложение, которое анализирует xml, используя dom4j и xPath:

Анализируемый xml похож на следующее:

<cache>
  <content>
    <transaction>
      <page>
        <widget name="PAGE_ID">WRK_REGISTRATION</widget>
        <widget name="TRANS_DETAIL_ID">77145</widget>
        <widget name="GRD_ERRORS" />
      </page>
      <page>
        <widget name="PAGE_ID">WRK_REGISTRATION</widget>
        <widget name="TRANS_DETAIL_ID">77147</widget>
        <widget name="GRD_ERRORS" />
      </page>
      <page>
        <widget name="PAGE_ID">WRK_PROCESSING</widget>
        <widget name="TRANS_DETAIL_ID">77152</widget>
        <widget name="GRD_ERRORS" />
      </page>
    </transaction>
  </content>
</cache>

Поиск отдельных узлов осуществляется с помощью следующего:

String xPathToGridErrorNode = "//cache/content/transaction/page/widget[@name='PAGE_ID'][text()='WRK_DNA_REGISTRATION']/../widget[@name='TRANS_DETAIL_ID'][text()='77147']/../widget[@name='GRD_ERRORS_TEMP']";

org.dom4j.Element root = null;

SAXReader reader = new SAXReader();
Document document = reader.read(new BufferedInputStream(new ByteArrayInputStream(xmlToParse.getBytes())));
root = document.getRootElement();

Node gridNode = root.selectSingleNode(xPathToGridErrorNode);

где xmlToParse - строка XML, аналогичная приведенной выше выдержке.

Код пытается получить узел GRD_ERROR для страницы с PAGE_ID и TRANS_DETAIL_ID, предоставленными в xPath.

Я вижу периодический (~ 1-2%) сбой (возвращаемый узел является нулевым) этого запроса selectSingleNode, даже если запрошенный узел находится в искомом xml.

Я знаю, что есть некоторые ошибки, связанные с использованием text () = в xPath, и мне было интересно, есть ли лучший способ отформатировать строку xPath для этого типа поиска.

1 Ответ

0 голосов
/ 29 марта 2012

Из ваших фрагментов есть проблема относительно GRD_ERRORS против GRD_ERRORS_TMP и WRK_REGISTRATION против WRK_DNA_REGISTRATION.

Игнорируя это, я бы предложил переписать

//cache/content/transaction/page
  /widget[@name='PAGE_ID'][text()='WRK_DNA_REGISTRATION']
  /../widget[@name='TRANS_DETAIL_ID'][text()='77147']
  /../widget[@name='GRD_ERRORS_TEMP']

в качестве * * +1010

//cache/content/transaction/page
  [widget[@name='PAGE_ID'][text()='WRK_REGISTRATION']]
  [widget[@name='TRANS_DETAIL_ID'][text()='77147']]
  /widget[@name='GRD_ERRORS']

Просто потому, что это делает код, на мой взгляд, более легким для чтения и выражает то, что вы, кажется, имеете в виду более четко: «элемент page, у которого есть дети с этими условиями, а затем возьмите виджет с этим @name. »Или, если это ближе к тому, как вы думаете об этом,

//cache/content/transaction/page/widget[@name='GRD_ERRORS']
  [preceding-sibling::widget[@name='PAGE_ID'][text()='WRK_REGISTRATION']]
  [preceding-sibling::widget[@name='TRANS_DETAIL_ID'][text()='77147']]
...