XPath: получить узлы, где дочерний элемент node содержит атрибут

Предположим, что у меня есть следующий XML:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

<book category="WEB">
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
</book>

<book category="WEB">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
</book>

Я хотел бы сделать xpath, который возвращает все узлы книги, которые имеют заголовок node с атрибутом языка "it".

Моя попытка выглядела примерно так:

//book[title[@lang='it']]

Но это не сработало. Я ожидаю вернуть узлы:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

Любые подсказки? Спасибо заранее.

Ответ 1

Try

//book[title/@lang = 'it']

Это гласит:

  • получить все элементы book
    • у которых есть хотя бы один title
      • который имеет атрибут lang
        • со значением "it"

Вы можете найти этот полезный - это статья под названием "XPath in Пять абзацев" Рональда Бурре.

Но, честно говоря, //book[title[@lang='it']] и выше должны быть эквивалентными, если у вашего XPath-движка нет "проблем". Таким образом, это может быть что-то в коде или образце XML, который вы не показываете нам, например, ваш образец является фрагментом XML. Может ли быть, что корневой элемент имеет пространство имен, и вы не рассчитываете на это в своем запросе? И вы только сказали нам, что это не сработало, но вы не сказали нам, какие результаты вы получили.

Ответ 2

Спустя годы, но полезным вариантом было бы использование осей XPath (https://www.w3schools.com/xml/xpath_axes.asp). Точнее, вы хотите использовать оси потомков.

Я считаю, что этот пример поможет

//book[descendant::title[@lang='it']]

Это позволяет вам выбрать все элементы book которые содержат дочерний элемент title (независимо от того, насколько глубоко он вложен), содержащий значение атрибута языка, равное 'it'.

Я не могу точно сказать, относится ли этот ответ к 2009 году, так как я не уверен на 100%, что в то время существовали оси XPath. Я могу подтвердить, что они существуют сегодня, и я обнаружил, что они чрезвычайно полезны в навигации по XPath, и я уверен, что вы тоже это сделаете.

Ответ 3

//book[title[@lang='it']]

фактически эквивалентно

 //book[title/@lang = 'it']

Я попробовал это с помощью vtd-xml, оба выражения выплевывают один и тот же результат... какой механизм обработки xpath вы использовали? Я предполагаю, что это проблема соответствия Ниже приведен код

import com.ximpleware.*;
public class test1 {
  public static void main(String[] s) throws Exception{
      VTDGen vg = new VTDGen();
      if (vg.parseFile("c:/books.xml", true)){
          VTDNav vn = vg.getNav();
          AutoPilot ap = new AutoPilot(vn);
          ap.selectXPath("//book[title[@lang='it']]");
                  //ap.selectXPath("//book[title/@lang='it']");

          int i;
          while((i=ap.evalXPath())!=-1){
              System.out.println("index ==>"+i);
          }
          /*if (vn.endsWith(i, "< test")){
             System.out.println(" good ");  
          }else
              System.out.println(" bad ");*/

      }
  }
}

Ответ 4

Я бы подумал, что ваше собственное предложение верно, однако xml не совсем корректен. Если вы используете //book[title[@lang='it']] on <root>[Your"XML"Here]</root>, то бесплатные онлайн-тестеры xPath, такие как здесь, найдут ожидаемый результат.

Ответ 5

Попробуйте использовать это выражение xPath:

//book/title[@lang='it']/..

Это должно дать вам все узлы книг в "it" lang

Ответ 6

как бы ты это сделал?

Название этих книг по крайней мере с одним автором, который содержит Джеймса в своем значении