Java读取没有前缀但在命名空间范围内的xml元素

时间:2010-05-13 22:02:26

标签: java web-services soap axis2

从功能上讲,两个块应该是相同的

<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());

因此,如果我用((Element)item).getElementsByTagName(“username”);替换第二个getElementsByTagNameNS,我可以获取用户名元素。用户名是否具有ns1名称空间,即使它没有前缀?我想跟踪读取元素的命名空间范围吗?如果我的xml元素深入很多,它会不会变得讨厌?是否有一种解决方法,我可以在不知道是否定义了前缀的情况下读取ns1名称空间中的元素?

1 个答案:

答案 0 :(得分:1)

简短的回答是否定的,那些文件不一样。名称空间不是由元素继承的,在设置前缀时,您的名称空间不再作为文档的默认名称空间。

这两个是相同的:

<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以获得性能,但这些不是线程安全的,因此您不能将它们缓存在servlet上。永远不容易= /。

如果您正在使用大量XML,我建议使用Jaxen而不是JAXP。 (另一方面,如果你只做很少的XML而且它只是前端的一个,也许getElementsByTagName可能不是最糟糕的事情:))