英文:
Get value from non valid SOAP 1.1 Message with Java
问题
My previous question was closed and marked as a duplicate, but the suggested answer does not answer my problem, and as suggested, I'm asking a new question.
Let's work with the suggested answer.
Here's the code:
String strMsg = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">"+
" <soap:Header>"+
" <context xmlns=\"urn:zimbra\"/>"+
" </soap:Header>"+
" <soap:Body>"+
" <soap:Fault>"+
" <soap:Code>"+
" <soap:Value>soap:Sender</soap:Value>"+
" </soap:Code>"+
" <soap:Reason>"+
" <soap:Text>no valid authtoken present</soap:Text>"+
" </soap:Reason>"+
" <soap:Detail>"+
" <Error xmlns=\"urn:zimbra\">"+
" <Code>service.AUTH_REQUIRED</Code>"+
" <Trace>qtp1027591600-6073:1588614639199:4eacbd0257a457b6</Trace>"+
" </Error>"+
" </soap:Detail>"+
" </soap:Fault>"+
" </soap:Body>"+
"</soap:Envelope>";
InputStream is = new ByteArrayInputStream(strMsg.getBytes());
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(is);
// Envelope
xsr.nextTag();
QName name = xsr.getName();
// Header
xsr.nextTag();
name = xsr.getName();
// Context
xsr.nextTag();
name = xsr.getName();
// Context again
xsr.nextTag();
name = xsr.getName();
// Header again
xsr.nextTag();
name = xsr.getName();
// Body
xsr.nextTag();
name = xsr.getName();
// Fault
xsr.nextTag();
name = xsr.getName();
/* IM COMMENTING THE FOLLOWING CODE BECAUSE I'M INTERESTED IN THE FAULT CONTENT
* AND EVEN IF IT TRY TO GO DEEPER I CAN'T GO PASS "VALUE" NODE
*
// Code
xsr.nextTag();
name = xsr.getName();
// Value
xsr.nextTag();
name = xsr.getName();
// throws exception, no more elements for some reason
xsr.nextTag();
name = xsr.getName();
*/
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter stringWriter = new StringWriter();
transformer.transform(new StAXSource(xsr), new StreamResult(stringWriter));
StringReader sr = new StringReader(stringWriter.toString());
JAXBContext jaxbContext = JAXBContext.newInstance(Fault.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Fault fault = (Fault) unmarshaller.unmarshal(sr); // THROWS EXCEPTION
// "unexcpected element (URI:\"http://www.w3.org/2003/05/soap-envelope\", local:\"Fault\"). Expected elements are <{}Fault>
My Fault class:
@XmlRootElement(name = "Fault")
@XmlAccessorType(XmlAccessType.FIELD)
public static class Fault {
@XmlElement(name = "Code")
private String code;
@XmlElement(name = "Reason")
private String reason;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}
I suspected it wasn't going to work, since the elements directly inside "Fault" don't have values themselves, they have more elements inside, and also, all elements are prefixed with "soap". My envelope isn't exactly structured as the one in the suggested answer.
But still, I couldn't fetch the "Fault" node, as an exception was thrown:
unexcpected element (URI:"http://www.w3.org/2003/05/soap-envelope", local:"Fault"). Expected elements are <{}Fault>
I'm interested in getting the value of:
<soap:Text>no valid authtoken present</soap:Text>
Also, this is only for this type of error, there might be other errors. Also, when the answer is positive, I get a whole different response.
What I'm really interested in is finding a way to explore the envelope in the following way:
// pseudo code
(envelope->body->fault->reason->text != null) {reasonText = envelope->body->fault->reason->text)
But whatever way I'm able to reach Reason->Text will do. Then I can adapt the script to other bodies.
Thank you in advance.
英文:
My previous question was closed and marked as duplicate, but the suggested asnwer does not answer my problem, and as suggested, I'm asking a new question.
Let's work with the suggested answer.
Here's the code:
String strMsg = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">" +
" <soap:Header>" +
" <context xmlns=\"urn:zimbra\"/>" +
" </soap:Header>" +
" <soap:Body>" +
" <soap:Fault>" +
" <soap:Code>" +
" <soap:Value>soap:Sender</soap:Value>" +
" </soap:Code>" +
" <soap:Reason>" +
" <soap:Text>no valid authtoken present</soap:Text>" +
" </soap:Reason>" +
" <soap:Detail>" +
" <Error xmlns=\"urn:zimbra\">" +
" <Code>service.AUTH_REQUIRED</Code>" +
" <Trace>qtp1027591600-6073:1588614639199:4eacbd0257a457b6</Trace>" +
" </Error>" +
" </soap:Detail>" +
" </soap:Fault>" +
" </soap:Body>" +
"</soap:Envelope>";
InputStream is = new ByteArrayInputStream(strMsg.getBytes());
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(is);
//Envelope
xsr.nextTag();
QName name = xsr.getName();
//Header
xsr.nextTag();
name = xsr.getName();
//Context
xsr.nextTag();
name = xsr.getName();
//Context again
xsr.nextTag();
name = xsr.getName();
//Header again
xsr.nextTag();
name = xsr.getName();
//Body
xsr.nextTag();
name = xsr.getName();
//Fault
xsr.nextTag();
name = xsr.getName();
/* IM COMMENTING THE FOLLOWING CODE BECAUSE I'M INTERESTED IN THE FAULT CONTENT
* AND EVEN IF IT TRY TO GO DEEPER I CAN'T GO PASS "VALUE" NODE
*
//Code
xsr.nextTag();
name = xsr.getName();
//Value
xsr.nextTag();
name = xsr.getName();
//throws exception, no more elements for some reason
xsr.nextTag();
name = xsr.getName();
*/
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringWriter stringWriter = new StringWriter();
transformer.transform(new StAXSource(xsr), new StreamResult(stringWriter));
StringReader sr = new StringReader(stringWriter.toString());
JAXBContext jaxbContext = JAXBContext.newInstance(Fault.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Fault fault = (Fault) unmarshaller.unmarshal(sr); //THROWS EXCEPTION
//"unexcpected element (URI:"http://www.w3.org/2003/05/soap-envelope", local:"Fault"). Expected elements are <{}Fault>
My Fault class:
@XmlRootElement(name = "Fault")
@XmlAccessorType(XmlAccessType.FIELD)
public static class Fault {
@XmlElement(name = "Code")
private String code;
@XmlElement(name = "Reason")
private String reason;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}
I suspected it wasn't going to work, since the elements directly inside "Fault" don't have values themselves, they have more elements inside, and also all elements are prefixed with "soap", my envelope isn't exactly structured as the one in the suggested answer.
But still, I couldn't fetch the "Fault" node, as an exception was thrown:
unexcpected element (URI:"http://www.w3.org/2003/05/soap-envelope", local:"Fault"). Expected elements are <{}Fault>
I'm interested in getting the value of:
<soap:Text>no valid authtoken present</soap:Text>"
Also, this is only for this type of error, there might be other errors, also, when the answer is positive, I get a whole different response.
What I'm really insterested in is, finding a way to explore the envelope in the following way:
//pseudo code
(envelope->body->fault->reason->text != null) {reasonText = envelope->body->fault->reason->text)
But whatever way I'm able to reach Reason->Text will do, then I can adapt script to other bodies.
Thank you in advance.
答案1
得分: 2
一个朋友不想在这里回答,找到了解决方案,甚至更好的是,他使用了我想要的方法找到了解决方案:
```//伪代码
(envelope->body->fault->reason->text != null) {reasonText = envelope->body->fault->reason->text)
对于将来遇到此问题的其他人,以下是解决方案:
String strMsg = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">" +
" <soap:Header>" +
" <context xmlns=\"urn:zimbra\"/>" +
" </soap:Header>" +
" <soap:Body>" +
" <soap:Fault>" +
" <soap:Code>" +
" <soap:Value>soap:Sender</soap:Value>" +
" </soap:Code>" +
" <soap:Reason>" +
" <soap:Text>no valid authtoken present</soap:Text>" +
" </soap:Reason>" +
" <soap:Detail>" +
" <Error xmlns=\"urn:zimbra\">" +
" <Code>service.AUTH_REQUIRED</Code>" +
" <Trace>qtp1027591600-6073:1588614639199:4eacbd0257a457b6</Trace>" +
" </Error>" +
" </soap:Detail>" +
" </soap:Fault>" +
" </soap:Body>" +
"</soap:Envelope>";
strMsg = strMsg.replaceAll("soap:",""); //不太正规,但可行。
is = new ByteArrayInputStream(strMsg.getBytes());
InputSource xml = new InputSource(is);
XPath xPath = XPathFactory.newInstance().newXPath();
Object exprEval = xPath.compile("/Envelope/Body/Fault/Reason/Text/text()").evaluate(xml, XPathConstants.STRING);
if ( exprEval != null ) {
System.out.println( "故障原因文本:" + exprEval );
// 此处打印了预期的内容:
// 故障原因文本:no valid authtoken present
}
就是这样。
<details>
<summary>英文:</summary>
A friend of mine who didn't want to answer here, found a solution, and even better, he found it using the way I wanted to:
//pseudo code
(envelope->body->fault->reason->text != null) {reasonText = envelope->body->fault->reason->text)
For anyone else in the futures who stumbles upon this problem, here it is a solution:
String strMsg = "<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">" +
" <soap:Header>" +
" <context xmlns="urn:zimbra"/>" +
" </soap:Header>" +
" <soap:Body>" +
" <soap:Fault>" +
" <soap:Code>" +
" <soap:Value>soap:Sender</soap:Value>" +
" </soap:Code>" +
" <soap:Reason>" +
" <soap:Text>no valid authtoken present</soap:Text>" +
" </soap:Reason>" +
" <soap:Detail>" +
" <Error xmlns="urn:zimbra">" +
" <Code>service.AUTH_REQUIRED</Code>" +
" <Trace>qtp1027591600-6073:1588614639199:4eacbd0257a457b6</Trace>" +
" </Error>" +
" </soap:Detail>" +
" </soap:Fault>" +
" </soap:Body>" +
"</soap:Envelope>";
strMsg = strMsg.replaceAll("soap:",""); //Had to replace soap:, not fancy but it works.
is = new ByteArrayInputStream(strMsg.getBytes());
InputSource xml = new InputSource(is);
XPath xPath = XPathFactory.newInstance().newXPath();
Object exprEval = xPath.compile("/Envelope/Body/Fault/Reason/Text/text()").evaluate(xml, XPathConstants.STRING);
if ( exprEval != null ) {
System.out.println( "Fault reason text: " + exprEval );
// This prints what's expected:
// Fault reason text: no valid authtoken present
}
There you go.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论