2014-11-13 1 views
0

У меня есть XML-документ, который я обрабатываю с помощью JDOM-2.0.5. Следующий код работает отлично и bookNodes список содержит все книги узлы из моего файла XML:Поиск XML с использованием XPath с JDOM/JAXEN/SAXON

SAXBuilder builder = new SAXBuilder(); 

// @see http://xerces.apache.org/xerces-j/features.html 
// Disable namespace validation 
builder.setFeature("http://xml.org/sax/features/namespaces", false); 

Document doc = null; 

try { 
    doc = builder.build(xmlURL); 
} catch (JDOMException | IOException e) { 
    e.printStackTrace(); 
    return null; 
} 

// get browse elmt 
Element browse = doc.getRootElement().getChild("browse"); 

// Get all browse's chlidren 
List<Element> bookNodes = browse.getChildren("book"); 

for (Element book : bookNodes) { 
    // Do things with the selected nodes 
    //... 
} 

А вот пример моей XML DATAS:

<?xml version="1.0" encoding="utf-8"?> 
<Books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com/XMLSchema" version="1"> 
    <status code="0"/> 
    <link>http://www.example.com/books</link> 
    <description>Browse, search and ....</description> 
    <language>en-us</language> 
    <pubDate>Sun, 09 Nov 2014 00:00:02 +0000</pubDate> 
    <copyright>Copyright 2014, XXX</copyright> 
    <category>Books</category> 
    <browse> 
     <book id="bk101"> 
      <author>Gambardella, Matthew</author> 
      <title>XML Developer's Guide</title> 
      <genre>Computer</genre> 
      <price>44.95</price> 
      <publish_date>2000-10-01</publish_date> 
      <description>An in-depth look at creating applications 
      with XML.</description> 
     </book> 
     <book id="bk102"> 
      <author>Ralls, Kim</author> 
      <title>The Midnight Rain</title> 
      <genre>Fantasy</genre> 
      <price>5.95</price> 
      <publish_date>2000-12-16</publish_date> 
      <description>A former architect battles corporate zombies, 
      an evil sorceress, and her own childhood to become queen 
      of the world.</description> 
     </book> 
     <book id="bk105"> 
      <author>Corets, Eva</author> 
      <title>The Sundered Grail</title> 
      <genre>Fantasy</genre> 
      <price>5.95</price> 
      <publish_date>2001-09-10</publish_date> 
      <description>The two daughters of Maeve, half-sisters, 
      battle one another for control of England. Sequel to 
      Oberon's Legacy.</description> 
     </book> 
     <book id="bk106"> 
      <author>Randall, Cynthia</author> 
      <title>Lover Birds</title> 
      <genre>Romance</genre> 
      <price>4.95</price> 
      <publish_date>2000-09-02</publish_date> 
      <description>When Carla meets Paul at an ornithology 
      conference, tempers fly as feathers get ruffled.</description> 
     </book> 
    </browse> 
</Books> 

Question.1:

Я хочу только выбрать узлы книг, содержащие некоторый текст. Таким образом, я использовал запрос //book[contains(./title, 'The')] и jaxen-1.1.6 XPath с помощью следующего кода:

filter = "//book[contains(./title, 'The')]"; // should return 2 elements (2nd and 3rd nodes) 

// use the default implementation 
XPathFactory xFactory = XPathFactory.instance(); 

XPathExpression<Element> expr = xFactory.compile(filter, Filters.element()); 

List<Element> bookNodes = expr.evaluate(doc); 

Но bookNodes список был пуст!

Что не так с моим кодом?

Question.2:

Я буду нуждаться в более расширенные функции для поиска мои XML поля, как с помощью:

filter = "//book[matches(./title, '^ *XML.*?Developer.*?Guide *$', 'i')]"; // should return 1 element (1st node) 

Я тогда с помощью saxon9he, который поддерживает XPath 2.0+, но я не мог понять, как заставить его работать с JDOM2 и моим кодом выше.

Так что, если вы можете начать меня, как это сделать на основе моего кода (я уже гугле на помощь, но я не смог найти какой-либо)

Ответ Q.1 поможет мне понять, что я сделал неправильно. Но ответ Q.2 поможет мне продвинуться вперед с моим маленьким личным приложением.

Спасибо

+1

@ThW Старый ответ, класс 'XPath' осуждается в JDOM -2 – Enissay

ответ

1

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

SAXBuilder builder = new SAXBuilder(); 
Document doc = null; 

try { 
    doc = builder.build(xmlURL); 
} catch (JDOMException | IOException e) { 
    e.printStackTrace(); 
    return null; 
} 

Namespace ns = Namespace.getNamespace("http://www.example.com/XMLSchema"); 

// get browse elmt 
Element browse = doc.getRootElement().getChild("browse", ns); 

// Get all browse's chlidren 
List<Element> bookNodes = browse.getChildren("book", ns); 

for (Element book : bookNodes) { 
    // Do things with the selected nodes 
    //... 
} 

Для XPath, необходимо связать URI пространства имен с префиксом:

filter = "//ns:book[contains(./ns:title, 'The')]"; 

// use the default implementation 
XPathFactory xFactory = XPathFactory.instance(); 

XPathBuilder<Element> builder = new XPathBuilder(filter, Filters.element()); 
builder.setNamespace("ns", "http://www.example.com/XMLSchema"); 
XPathExpression<Element> expr = builder.compileWith(xFactory); 

List<Element> bookNodes = expr.evaluate(doc); 

Что касается вопроса 2, XPath двигатель Саксон может работать с JDOM2 деревья, но вы должны использовать API-интерфейс Sathon XPath вместо JDOM, что, в свою очередь, означает, что вы должны использовать стандартный способ связывания префиксов пространства имен с URI, что намного более громоздко, чем JDOM. Вы должны определить свою собственную реализацию NamespaceContext или используйте третью сторону, такую ​​как Spring's SimpleNamespaceContext.

JDOM2DocumentWrapper docw = 
     new JDOM2DocumentWrapper(doc, config); // net.sf.saxon.option.jdom2 

XPathEvaluator xpath = new XPathEvaluator(); // net.sf.saxon.xpath 
SimpleNamespaceContext nsCtx = new SimpleNamespaceContext(); 
nsCtx.bindNamespaceUri("ns", "http://www.example.com/XMLSchema"); 
xpath.setNamespaceContext(nsCtx); 
List<?> bookNodes = (List<?>)xpath.evaluate(
    "//ns:book[matches(./ns:title, '^ *XML.*?Developer.*?Guide *$', 'i')]", docw, 
    XPathConstants.NODESET); 

(адаптировано из саксонской JDOM2Example.java)

+0

Q.1 хорошо. Однако для Q.2 и на основе ссылки вашего примера некоторые импортные данные не могут быть разрешены как «JDOM2DocumentWrapper, ProfessionalConfiguration» ... Я использую [Saxon-HE 9.6] (http://sourceforge.net/projects/saxon/ файлы/Saxon-HE/9.6 /) – Enissay

+0

Хотя Saxon поддерживает API javax.xml.xpath, он также имеет свой собственный API s9api, который намного удобнее для простых задач, таких как определение связывания пространства имен: 'xPathCompiler.declareNamespace (prefix, uri) '. См. Http://www.saxonica.com/documentation/#!javadoc/net.sf.saxon.s9api/XPathCompiler –

+0

@Enissay, что пример кода использует Saxon PE, моя версия адаптирована для HE, используя конструктор no-arg XPathEvaluator. Но, как отмечает Майкл, подход s9api проще. –

0

Для полноты картины, вот как это сделать с s9api интерфейсом саксонской:

Processor proc = new Processor(); 
XdmNode docw = proc.newDocumentBuilder().wrap(doc); 
XPathCompiler xpath = proc.newXPathCompiler(); 
xpath.declareNamespace("ns", "http://www.example.com/XMLSchema"); 
XdmValue bookNodes = xpath.evaluate(
    "//ns:book[matches(./ns:title, '^ *XML.*?Developer.*?Guide *$', 'i')]", docw); 
for (XdmItem book : bookNodes) { 
.... 
} 
+0

Я использовал 'new Processor (false)'. В следующей строке я получаю сообщение об ошибке 'java.lang.ClassCastException: net.sf.saxon.value.ObjectValue не может быть добавлено в net.sf.saxon.om.NodeInfo \t at net.sf.saxon.s9api. DocumentBuilder.wrap (DocumentBuilder.java:511) ' – Enissay

+0

Звучит так, как будто вы используете Saxon-HE, который не поставляется с поддержкой JDOM2« из коробки », хотя вы можете настроить его самостоятельно, если хотите сэкономить £ 50 стоимость лицензии PE. –

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

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