Ваш XML-ввод на самом деле имеет два пространства имен.
Пространство имен по умолчанию
Первое - это пространство по умолчанию, объявленное так:
<semseg:Envelope ... xmlns="http://another-random-URL" ...
Является значением по умолчанию,любой элемент XML, у которого нет пространства имен, принадлежит этому пространству имен по умолчанию.
пространство имен semseg
Определено так:
<semseg:Envelope xmlns:semseg="http://a-random-URL" ...
Значение каждого элемента XML с префиксом semseg
принадлежит этому пространству имен.
Перевод ваших требований
Итак, вы нацелены на выражение XPath, которое будет нацелено на
- любой элемент
Triangle
(без префикса, так что фактически преобразуется в любой Triangle
элемент из http://another-random-URL
пространства имен ). - Это прямой дочерний элемент корневого
semseg:Enveloppe
элемента (который фактически преобразуется в корневой элемент локального имени Enveloppe
, принадлежащий пространству имен "http://a -random-URL " ).
Программирование в XPath.
Мы создаем NamespaceContext, который описывает, какие пространства имен мы работаем.ng with: Я определяю префиксы, с которыми я хочу работать, и сопоставляю их с пространствами имен.Эти префиксы будут использоваться движком XPath.Я сопоставляю:
- Префикс
main
к пространству имен http://a-random-URL
- Префикс
secondary
к пространству имен http://another-random-URL
Использованиеэто отображение, которое я определил, я могу перевести ваше требование к этому XPath:
/main:Envelope/secondary:Triangle
И это работает:
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
xPath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if ("main".equals(prefix)) {
return "http://a-random-URL";
}
if ("secondary".equals(prefix)) {
return "http://another-random-URL";
}
return null;
}
@Override
public String getPrefix(String namespaceURI) {
// This should be implemented but I'm lazy and this sample works without it
return null;
}
@Override
public Iterator getPrefixes(String namespaceURI) {
// This should be implemented but I'm lazy and this sample works without it
return null;
}
});
XPathExpression xpr = xPath.compile("/main:Envelope/secondary:Triangle");
NodeList nodes = (NodeList)xpr.evaluate(doc, XPathConstants.NODESET);
System.out.println(nodes.getLength());
Выходы:
1
Здесь яреализовали очень тупой контекст пространства имен, но если у вас есть Spring, CXF, guava (я думаю) или другие доступные платформы, у вас часто есть что-то вроде SimpleNamespaceContext
или MapBasedNamespaceContext
, которые, вероятно, являются лучшими вариантами.