XPath: Есть ли способ установить пространство имен по умолчанию для запросов?
Есть ли способ установить, что Java XPath имеет префикс пространства имен по умолчанию для экспрессов? Например, вместо:/html: html/html: head/html: title/text() ", запрос может быть:/html/head/title/text()
При использовании префикса пространства имен работает более элегантный способ.
Пример фрагмента кода того, что я делаю сейчас:
Node node = ... // DOM of a HTML document
XPath xpath = XPathFactory.newInstance().newXPath();
// set to a NamespaceContext that simply returns the prefix "html"
// and namespace URI ""http://www.w3.org/1999/xhtml"
xpath.setNamespaceContext(new HTMLNameSpace());
String expression = "/html:html/html:head/html:title/text()";
String value = xpath.evaluate(query, expression);
Ответы
Ответ 1
К сожалению, нет. Несколько лет назад были некоторые разговоры об определении пространства имен по умолчанию для JxPath, но быстрый просмотр последних документов не означает, что что-то случилось. Возможно, вы захотите потратить еще некоторое время на просмотр документов.
Одна вещь, которую вы могли бы сделать, если вы действительно не заботитесь о пространствах имен, заключается в анализе документа без них. Просто опустите вызов, который вы сейчас делаете в DocumentBuilderFactory.setNamespaceAware().
Также обратите внимание, что ваш префикс может быть любым, что вы хотите; он не должен соответствовать префиксу в документе экземпляра. Таким образом, вы можете использовать h
, а не html
, и минимизировать визуальный беспорядок префикса.
Ответ 2
Я действительно не пробовал это, но, согласно документации NamespaceContext, контекст пространства имен с префиксом "" (строка emtpy) считается пространством имен по умолчанию.
Я был слишком быстр на этом. Оценщик XPath не вызывает NamespaceContext для разрешения префикса ", если префикс вообще не используется в выражении XPath" /html/head/title/text () ". Теперь я перехожу к XML-деталям, о которых я не уверен на 100%, но используя выражение типа" /: html/: head/: title/text() "работает с Sun JDK 1.6.0_16 и запрашивается NamespaceContext для разрешения пустого префикса (" "). Это действительно правильное и ожидаемое поведение или ошибка в Xalan?
Ответ 3
Я знаю, что этот вопрос старый, но я просто потратил 3 часа на поиск попытки решить эту проблему, и ответ @kdgregorys помог мне многое. Я просто хотел точно указать, что я сделал, используя kdgregorys в качестве руководства.
Проблема в том, что XPath в java даже не ищет пространство имен, если у вас нет префикса в вашем запросе, поэтому для сопоставления запроса с конкретным пространством имен вам нужно добавить префикс к запросу. Я использовал произвольный префикс для сопоставления имени схемы. В этом примере я буду использовать пространство и запрос OP и префикс abc
. Ваше новое выражение будет выглядеть так:
String expression = "/abc:html/abc:head/abc:title/text()";
Затем сделайте следующее
1) Убедитесь, что ваш документ установлен в пространство имен.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
2) Внедрите NamespaceContext
, который разрешит ваш префикс. Это я взял из другого сообщения в SO и немного изменил
.
public class NamespaceResolver implements NamespaceContext {
private final Document document;
public NamespaceResolver(Document document) {
this.document = document;
}
public String getNamespaceURI(String prefix) {
if(prefix.equals("abc")) {
// here is where you set your namespace
return "http://www.w3.org/1999/xhtml";
} else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return document.lookupNamespaceURI(null);
} else {
return document.lookupNamespaceURI(prefix);
}
}
public String getPrefix(String namespaceURI) {
return document.lookupPrefix(namespaceURI);
}
@SuppressWarnings("rawtypes")
public Iterator getPrefixes(String namespaceURI) {
// not implemented
return null;
}
}
3) При создании объекта XPath задайте свой NamespaceContext.
xPath.setNamespaceContext(new NamespaceResolver(document));
Теперь, независимо от того, что представляет собой префикс схемы, вы можете использовать свой собственный префикс, который будет отображаться в правильной схеме. Таким образом, ваш полный код с использованием класса выше будет выглядеть примерно так.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
Document document = factory.newDocumentBuilder().parse(sourceDocFile);
XPathFactory xPFactory = XPathFactory.newInstance();
XPath xPath = xPFactory.newXPath();
xPath.setNamespaceContext(new NamespaceResolver(document));
String expression = "/abc:html/abc:head/abc:title/text()";
String value = xpath.evaluate(query, expression);