Java читает элемент xml без префикса, но в рамках пространства имен - PullRequest
0 голосов
/ 14 мая 2010

Функционально два блока должны быть одинаковыми

<soapenv:Body>
  <ns1:login xmlns:ns1="urn:soap.sof.com">
    <userInfo>
      <username>superuser</username>
      <password>qapass</password>
    </userInfo>
  </ns1:login>
</soapenv:Body>

-----------------------

<soapenv:Body>
  <ns1:login xmlns:ns1="urn:soap.sof.com">
    <ns1:userInfo>
      <ns1:username>superuser</ns1:username>
      <ns1:password>qapass</ns1:password>
    </ns1:userInfo>
  </ns1:login>
</soapenv:Body>

Однако, как, когда я читаю с использованием AXIS2, а также проверил его с помощью java6, у меня возникла проблема.

 MessageFactory factory = MessageFactory.newInstance();
 SOAPMessage soapMsg = factory.createMessage(new MimeHeaders(), SimpleTest.class.getResourceAsStream("LoginSoap.xml"));

 SOAPBody body = soapMsg.getSOAPBody();

 NodeList nodeList = body.getElementsByTagNameNS("urn:soap.sof.com", "login");
 System.out.println("Try to get login element" + nodeList.getLength());  // I can get the login element

 Node item = nodeList.item(0);
 NodeList elementsByTagNameNS = ((Element)item).getElementsByTagNameNS("urn:soap.sof.com", "username");
 System.out.println("try to get username element " + elementsByTagNameNS.getLength());

Так что, если я заменим 2-й getElementsByTagNameNS на ((Element) item) .getElementsByTagName ("username"); я смогу получить элемент username. Разве имя пользователя не имеет пространства имен ns1, даже если у него нет префикса? Должен ли я следить за областью пространства имен для чтения элемента? Разве это не стало бы неприятным, если бы мои элементы XML были многоуровневыми? Есть ли обходной путь, где я могу прочитать элемент в пространстве имен ns1, не зная, определен ли префикс?

1 Ответ

1 голос
/ 14 мая 2010

Краткий ответ - нет, эти документы не совпадают.Пространство имен не наследуется элементами, и при установке префикса ваше пространство имен больше не функционирует как пространство имен по умолчанию для документа.

Эти два значения будут одинаковыми:

<soapenv:Body>
  <login xmlns="urn:soap.sof.com">
    <userInfo>
      <username>superuser</username>
      <password>qapass</password>
    </userInfo>
  </login>
</soapenv:Body>

-----------------------

<soapenv:Body>
  <ns1:login xmlns:ns1="urn:soap.sof.com">
    <ns1:userInfo>
      <ns1:username>superuser</ns1:username>
      <ns1:password>qapass</ns1:password>
    </ns1:userInfo>
  </ns1:login>
</soapenv:Body>

ДляБолее надежный способ чтения документа, возможно, вам стоит взглянуть на компиляцию некоторых операторов XPath.Проблемы с пространством имен являются лишь одной из проблем, связанных с использованием вспомогательных методов getElementsByTagName (NS).

- Правка -

Сам Xpath довольно прост.например, //userInfo выбрать все элементы userInfo на любом уровне.//login/userInfo выбрать все элементы userInfo, которые являются дочерними элементами входа в систему на любом уровне.Как и все остальное, становится сложнее, когда вы начинаете добавлять пространства имен.

private NamespaceContext ns = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
if (prefix.equals("urn") return "urn:soap.sof.com";
else return XMLConstants.NULL_NS_URI;
}
public String getPrefix(String namespace) {
throw new UnsupportedOperationException();
}
public Iterator getPrefixes(String namespace) {
throw new UnsupportedOperationException();
}};

XPathFactory xpfactory = XPathFactory.newInstance();
XPath xpath = xpfactory.newXPath();
xpath.setNamespaceContext(ns);
NodeList nodes = (NodeList) xpath.evaluate("//urn:userInfo|//userInfo", myDom, XPathConstants.NODESET);
//find all userInfo at any depth with either namespace.

Уже давно я использую JAXP, но я думаю, что это в основном правильно.Запуск xPath не медленный, но его компиляция идет.Вы можете скомпилировать их в XPathExpression для повышения производительности, но они не являются поточно-ориентированными, поэтому вы не можете просто кэшировать их в сервлете.Никогда не легко = /.

Если вы делаете много XML, я бы рекомендовал использовать Jaxen вместо JAXP.(С другой стороны, если вы делаете очень мало XML и он только один из внешнего интерфейса, возможно, getElementsByTagName не самая плохая вещь :))

...