Как получить узел за узлом дерева XML, используя Xpath?

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

Дайте следующий код:

<code>  DocumentBuilderFactory domFactory = 
  DocumentBuilderFactory.newInstance();
  domFactory.setNamespaceAware(true); 
  DocumentBuilder builder = domFactory.newDocumentBuilder();
  Document doc = builder.parse("input.xml");
  XPath xpath = XPathFactory.newInstance().newXPath();
</code>

Если бы я хотел найтиfirst узел раунда 1 и двери 1, здесь:

<code><Game>
    <Round>
        <roundNumber>1</roundNumber>
        <Door>
            <doorName>abd11</doorName>
            <Value>
                <xVal1>0</xVal1>
                <xVal2>25</xVal2>
                <pVal>0.31</pVal>
            </Value>
            <Value>
                <xVal1>25</xVal1>
                <xVal2>50</xVal2>
                <pVal>0.04</pVal>
            </Value>
            <Value>
                <xVal1>50</xVal1>
                <xVal2>75</xVal2>
                <pVal>0.19</pVal>
            </Value>
            <Value>
                <xVal1>75</xVal1>
                <xVal2>100</xVal2>
                <pVal>0.46</pVal>
            </Value>
        </Door>
        <Door>
            <doorName>vvv1133</doorName>
            <Value>
                <xVal1>60</xVal1>
                <xVal2>62</xVal2>
                <pVal>1.0</pVal>
            </Value>
        </Door>
    </Round>
    <Round>
        <roundNumber>2</roundNumber>
        <Door>
            <doorName>eee</doorName>
            <Value>
                <xVal1>0</xVal1>
                <xVal2>-25</xVal2>
                <pVal>0.31</pVal>
            </Value>
            <Value>
                <xVal1>-25</xVal1>
                <xVal2>-50</xVal2>
                <pVal>0.04</pVal>
            </Value>
            <Value>
                <xVal1>-50</xVal1>
                <xVal2>-75</xVal2>
                <pVal>0.19</pVal>
            </Value>
            <Value>
                <xVal1>-75</xVal1>
                <xVal2>-100</xVal2>
                <pVal>0.46</pVal>
            </Value>
        </Door>
        <Door>
            <doorName>cc</doorName>
            <Value>
                <xVal1>-60</xVal1>
                <xVal2>-62</xVal2>
                <pVal>0.3</pVal>
            </Value>
            <Value>
                <xVal1>-70</xVal1>
                <xVal2>-78</xVal2>
                <pVal>0.7</pVal>
            </Value>
        </Door>
    </Round>
</Game>
</code>

Я сделаю это:

<code> XPathExpression expr = xpath.compile("//Round[1]/Door[1]/Value[1]/*/text()");      
  Object result = expr.evaluate(doc, XPathConstants.NODESET);
  NodeList nodes = (NodeList) result;
</code>

и если бы я хотелsecond узел раунда 1 и двери 1, то:

<code>XPathExpression expr = xpath.compile("//Round[1]/Door[1]/Value[2]/*/text()");  
</code>

но как мне сделать это с помощью цикла, так как я не знаю, сколькоValue-nodes Я имею в виду, как я могу сделать это, используя цикл, где каждую итерацию я получаю 3 (я имею в видуxVal1 , xVal2 а такжеpVal values) больше значений узла Value!?

Причины для этого:

Я не знаю сколькоRound меня есть

Я не знаю сколькоValue меня есть

Я не хочу объявлять каждый раз новыйXPathExpression

Благодарность

 Dimitre Novatchev05 мая 2012 г., 21:59
@ ron: это один из самых распространенных вопросов и ответов по XPath: use:count((//Round/Door)[1]/Value) а потомcount((//Round/Door)[$k]/Value)
 Dimitre Novatchev05 мая 2012 г., 19:08
Используйте XPathcount() функция, чтобы найти количество узлов, затем использовать (вложенный) цикл:
 ron05 мая 2012 г., 20:31
@ DimitreNovatchev: я пробовал считать, но он не работает, посмотрите: если я напишу следующее: "double count = (Double) xpath.evaluate (" count (// Round / Door [1] / Value) ", doc, XPathConstants.NUMBER);" тогда я получаю "count == 8" ......... если я пишу вместо "int k = 1; double count = (Double) xpath.evaluate (" count (// Round / Door [k] / Значение) ", doc, XPathConstants.NUMBER);" тогда я получаю "count == 0"
 ron05 мая 2012 г., 19:49
@ erikxiv: Проблема в том, что в каждом раунде есть 2 поля, одно из которых «roundNumber», а второе «Дверь». Теперь с помощью одного запроса, то есть XPathExpression, я могу получить только один, но не оба? потому что из того, что я вижу в данный момент, я должен сделать 2 запроса - один для поля "roundNumber" и другой для "Дверь" каждого раунда ... и т. д.
 erikxiv05 мая 2012 г., 19:18
Почему бы не несколько экспрессов? Разве это не то, что вы хотите (например, сначала получите список раундов, затем дверей, затем значений?)

Ответы на вопрос(1)

Решение Вопроса

Опция - перебирать все элементы Value в документе. Требуется только одна оценка, но трудно понять, какому элементу Round или Door принадлежит значение.

//Round/Door/Value/*/text()", doc, XPathConstants.NODESET);

Вариант 2 - перебирать каждый элемент Round, Door и Value отдельно. Требуется больше оценок, но контекст легко известен. Если требуется индекс, легко добавить счетчик в циклы.

// Get all rounds and iterate over them
NodeList rounds = (NodeList) xpath.evaluate("//Round", doc, XPathConstants.NODESET);
for (Node round : rounds) {
  // Get all doors and iterate over them
  NodeList doors = (NodeList) xpath.evaluate("Door", round, XPathConstants.NODESET);
  for (Node door : doors) {
    // Get all values and iterate over them
    NodeList values = (NodeList) xpath.evaluate("Value/*/text()", door, XPathConstants.NODESET);
    for (Node value : values) {
      // Do something
    }
  }
}

Вариант 3 - Сочетайте вышеперечисленное в зависимости от ваших требований

Обратите внимание, что я удалил шаг компиляции выражений, чтобы сократить пример. Это должно быть добавлено повторно для улучшения производительности.

 viruskimera05 окт. 2017 г., 02:01
Nodelist не может повторяться таким образом.
 erikxiv21 февр. 2016 г., 22:01
@ majorbanzai Вы думаете об улучшенном синтаксисе for-loop? Я подозреваю, что вы правы в том, что пример кода не будет работать какNodeList это неIterable. Делает ли этот пример более читабельным, хотя ...
 majorbanzai23 дек. 2015 г., 18:24
КоторыйNodeList класс вы используете это реализуетIterable?

Ваш ответ на вопрос