2017-02-13 9 views
0

После исследования в google я не нашел рабочего решения для этого. В книге «MAVEN by Example» используется пример погоды Yahoo. К сожалению, похоже, что Yahoo изменил свой интерфейс. Я пытался адаптировать код Java для этого, но получить это досадное исключение:XpathException в Java MAVEN пример Выражение использует префикс незанятого пространства имен

 exec-maven-plugin:1.5.0:java 
    Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.5.0:java 
      Caused by: org.dom4j.XPathException: 
Exception occurred evaluting XPath: /query/results/channel/yweather:location/@city. 
Exception: XPath expression uses unbound namespace prefix yweather 

сам XML-строка:

<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="1" yahoo:created="2017-02-13T10:57:34Z" yahoo:lang="en-US"> 
<results> 
    <channel> 
    ... 
     <yweather:location xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" city="Theale" country="United Kingdom" region=" England"/> 

Всего XML может быть получена из:

https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%3D91731537 

Мой код (согласно «MAVEN By Example» ebook, xpath и url, измененный для измененного Yahoo):

public Weather parse(InputStream inputStream) throws Exception { 
    Weather weather = new Weather(); 

    SAXReader xmlReader = createXmlReader(); 
    Document doc = xmlReader.read(inputStream); 
    weather.setCity(doc.valueOf ("//yweather:location/@city")); 
    // and several more, such as setCountry, setTemp 
} 

(я не эксперт XPath, поэтому я попытался

/query/results/channel/item/yweather:location/@city 

, а также, на всякий случай, с тем же результатом.

XMLReader:

public InputStream retrieve(String woeid) throws Exception { 
     String url = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%3D"+woeid; // eg 91731537 
     URLConnection conn = new URL(url).openConnection(); 
     return conn.getInputStream(); 
    } 

и класс погода просто набор добытчиками и сеттеров

Когда я пытаюсь это в this XML тестером, он прекрасно работает, но это может быть следствием XPATH-v2 vs Java v1.

ответ

1

Когда вы оцениваете XPath //yweather:location/@city, процессор XPath не знает, для какого пространства имен привязан префикс yweather. Вам нужно будет предоставить эту информацию. Теперь вы можете подумать: «информация прямо там, в документе!» и ты был бы прав. Но префиксы - это просто своего рода stand-in (как переменная) для реального пространства имен. Пространство имен может быть привязано к любому префиксу, который вам нравится, который следует правилам именования префикса и может быть привязан к нескольким префиксам. Точно так же, как имя переменной в Java, относящееся к объекту, само по себе не имеет значения, и несколько переменных могут ссылаться на один и тот же объект.

Например, если вы использовали XPath //yw:location/@city с префиксом yw, связанным с пространством имен http://xml.weather.yahoo.com/ns/rss/1.0, он все равно будет работать так же.

Я предлагаю вам использовать класс org.dom4j.xpath.DefaultXPath вместо звонка valueOf. Создайте его экземпляр и инициализируйте контекст пространства имен. Существует метод setNamespaceURIs that takes a Map from prefixes to namespaces и позволяет создавать привязки. Свяжите указанное пространство прогнозов погоды (фактический URI) с некоторым префиксом по вашему выбору (может быть, yweather, но может быть любым, что вы хотите использовать в своем фактическом выражении XPath), а затем использовать экземпляр для оценки его по документу.

Вот ответ, который я дал какой-то вопрос, который идет более углубленное о том, что пространство имен и их префиксы действительно являются: https://stackoverflow.com/a/8231272/630136

EDIT: онлайн XPath тестер вы использовали, вероятно, делает некоторые за кадром магии извлеките пространства имен и их префиксы из данного документа и привяжите их к процессору XPath.

Если вы посмотрите на свой образец XML и настройте его так ...

<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org"> 
    <actors> 
     <actor id="1">Christian Bale</actor> 
     <actor id="2">Liam Neeson</actor> 
     <actor id="3">Michael Caine</actor> 
    </actors> 
    <foo:singers xmlns:test="http://www.foo.org/"> 
     <test:singer id="4">Tom Waits</test:singer> 
     <foo:singer id="5">B.B. King</foo:singer> 
     <foo:singer id="6">Ray Charles</foo:singer> 
    </foo:singers> 
</root> 

XML-семантически эквивалентны, так как префикс test привязан к тому же пространству имен, как foo. XPath //foo:singer/@id по-прежнему возвращает все правильные результаты, поэтому инструмент умный. Тем не менее, он не знает, что делать с XML ...

<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org"> 
    <actors> 
     <foo:actor id="1">Christian Bale</foo:actor> 
     <actor id="2">Liam Neeson</actor> 
     <actor id="3">Michael Caine</actor> 
    </actors> 
    <foo:singers xmlns:test="http://www.foo.org/" xmlns:foo="http://www.bar.org"> 
     <test:singer id="4">Tom Waits</test:singer> 
     <foo:singer id="5">B.B. King</foo:singer> 
     <foo:singer id="6">Ray Charles</foo:singer> 
    </foo:singers> 
</root> 

и XPath //foo:*/@id. Префикс foo привязан к другому пространству имен в области элементов исполнителей, и теперь он возвращает только идентификаторы 5 и 6. Контрастируйте его с этим XPath, который не использует префикс, но функция namespace-uri(): //*[namespace-uri()='http://www.foo.org/']/@id

Это последнее возвращает идентификаторы 1 и 4, как и ожидалось.

+0

Спасибо за подробное объяснение, я получил его сейчас, просто вставив предлагаемую функцию пространства имен-uri следующим образом: 'weather.setCity (doc.valueOf (" // * [namespace-uri() = 'http: //xml.weather.yahoo.com/ns/rss/1.0']/@city "));' На данный момент это служит цели, поскольку я пытаюсь узнать Maven, но мне нужно обновить себя с именами в XML, а также, поскольку я не могу заявить, что полностью понимаю примеры, которые вы дали .... Спасибо! – user3211098

0

Я нашел ошибку, это моя незнакомость с пространствами имен. Используемый в моем примере выше 'createXmlReader()' - это метод, который устанавливает правильное пространство имен, за исключением того, что я забыл изменить его после того, как Yahoo изменил xml. Тщательное повторное чтение документации Maven-by-example, сгенерированной ошибки и сравнение с подробным ответом, приведенным здесь, внезапно щелкнули. Обновленный код (в пользу тех, кто пытается тот же пример):

private SAXReader createXmlReader() { 
    Map<String,String> uris = new HashMap<String,String>(); 
    uris.put("yweather", "http://xml.weather.yahoo.com/ns/rss/1.0"); 
    DocumentFactory factory = new DocumentFactory(); 
    factory.setXPathNamespaceURIs(uris); 
    SAXReader xmlReader = new SAXReader(); 
    xmlReader.setDocumentFactory(factory); 
    return xmlReader; 
} 

Единственное изменение в строке «uris.put()» Первоначально пространство имен был «у», теперь «yweather ».

 Смежные вопросы

  • Нет связанных вопросов^_^