从功能上讲,两个块应该是相同的
<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名称空间中的元素?
答案 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可能不是最糟糕的事情:))