The following is a generic sample SOAP request for .NET web service I'm supposed to invoke from my java web app开发者_开发技巧:
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<setAMRequestData xmlns="http://tempuri.org/">
<id>int</id>
</setAMRequestData>
</soap:Body>
</soap:Envelope>
I am able to generate something similar from java console application using this code segment:
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
...
SOAPConnectionFactory sfc = SOAPConnectionFactory.newInstance();
SOAPConnection connection = sfc.createConnection();
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage sm = mf.createMessage();
SOAPHeader sh = sm.getSOAPHeader();
SOAPBody sb = sm.getSOAPBody();
sh.detachNode();
QName bodyName = new QName("http://tempuri.org/", "setAMRequestData", XMLConstants.DEFAULT_NS_PREFIX);
SOAPBodyElement bodyElement = sb.addBodyElement(bodyName);
QName n = new QName("id");
SOAPElement quotation = bodyElement.addChildElement(n);
quotation.addTextNode("121152");
The result is the following XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<setAMRequestData xmlns="http://tempuri.org/">
<id>121152</id>
</setAMRequestData>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
This invokes the service. Next, I used soapUI to try to invoke this service, and it generated soap message from WSDL like this (it differs from the previous in the namespace declaration in envelope, and prefixes):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:setAMRequestData>
<tem:id>?</tem:id>
</tem:setAMRequestData>
</soapenv:Body>
</soapenv:Envelope>
This also works from soapUI. But finally, when I tried to recreate this form of soap message using this code sequence:
// factories and stuff, like in the example above
SOAPPart part = sm.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
envelope.addNamespaceDeclaration("tem", "http://tempuri.org/");
SOAPHeader sh = sm.getSOAPHeader();
SOAPBody sb = sm.getSOAPBody();
sh.detachNode();
QName bodyName = new QName(null, "setAMRequestData", "tem");
SOAPBodyElement bodyElement = sb.addBodyElement(bodyName);
QName n = new QName(null, "id", "tem");
SOAPElement quotation = bodyElement.addChildElement(n);
quotation.addTextNode("7028");
I got the following exception in line SOAPElement quotation = bodyElement.addChildElement(n);:
org.w3c.dom.DOMException: NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
No matter what I tried, I simply couldn't set "tem" prefix for the id element... What is going on here?
Thanks.
You are binding a namespace uri to a prefix and later try to create an element with the same prefix but with a null namespace uri:
envelope.addNamespaceDeclaration("tem", "http://tempuri.org/");
...
QName bodyName = new QName(null, "setAMRequestData", "tem");
An element is identified by the combination of namespace uri and local name. To solve this problem you have to specify the namespace on each element you create:
QName bodyName = new QName("http://tempuri.org/", "setAMRequestData", "tem");
...
QName n = new QName("http://tempuri.org/", "id", "tem");
Don't get all worked up because the XML coming out of your app doesn't look exactly the same (especially with namespace prefixes) as the request made by SoapUI. Paste your code into a SoapUI request, right-click, re-format, and see if SoapUI understands your stuff (and if you have the pro version, check it in form and outline views). If it looks ok, fire it off and see if you get the same response as the native (soapUI) request. If so, you're good to go. If, however, things are in the wrong place, namespaces are mangled, SoapUI can't render your XML, then you've got some tweaking to do in your code.
精彩评论