從 Java 中的 SOAP 訊息中取得特定部分
1. 概述
在設計用於資料交換的 API 時,我們經常採用 REST 或 SOAP 架構方法。在使用 SOAP 協定的情況下,有時我們可能需要從 SOAP 訊息中提取一些特定資料以進行進一步處理。
在本教程中,我們將學習如何用 Java 取得 SOAP 訊息的特定部分。
2. SOAPMessage
類
在深入研究之前,讓我們先簡單檢查一下[SOAPMessage](https://jakarta.ee/specifications/platform/10/apidocs/jakarta/xml/soap/soapmessage)
類別的結構,它表示所有 SOAP 訊息的根類別:
此類別由兩個主要部分組成-SOAP 部分和選用附件部分。前者包含 SOAP 信封,它保存我們收到的實際訊息。此外,信封本身由標頭和正文元素組成。
從 Java 11 開始,Java EE(包括 JAX-WS 和 SAAJ 模組)已從 JDK 中刪除,並且不再是標準發行版的一部分。要使用 Jakarta EE 9 及更高版本成功處理 SOAP 訊息,我們需要在pom.xml
中加入Jakarta SOAP with Attachment API和Jakarta SOAP Implements依賴項:
<dependency>
<groupId>jakarta.xml.soap</groupId>
<artifactId>jakarta.xml.soap-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.messaging.saaj</groupId>
<artifactId>saaj-impl</artifactId>
<version>3.0.3</version>
</dependency>
3. 工作範例
接下來,我們建立一條將在本教學課程中使用的 XML 訊息:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:be="http://www.baeldung.com/soap/">
<soapenv:Header>
<be:Username>baeldung</be:Username>
</soapenv:Header>
<soapenv:Body>
<be:ArticleRequest>
<be:Article>
<be:Name>Working with JUnit</be:Name>
</be:Article>
</be:ArticleRequest>
</soapenv:Body>
</soapenv:Envelope>
4. 從 SOAP 訊息中取得標頭和正文
接下來,讓我們看看如何從 SOAP 訊息中提取標頭和正文元素。
根據SOAPMessage
類別層次結構,要取得實際的 SOAP 訊息,我們首先需要取得 SOAP 部分,然後取得信封:
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("soap-message.xml");
SOAPMessage soapMessage = MessageFactory.newInstance().createMessage(new MimeHeaders(), inputStream);
SOAPPart part = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = part.getEnvelope();
現在,要取得 header 元素,我們可以呼叫getHeader()
方法:
SOAPHeader soapHeader = soapEnvelope.getHeader();
同樣,我們可以透過呼叫getBody()
方法來提取 body 元素:
SOAPBody soapBody = soapEnvelope.getBody();
5. 從 SOAP 訊息中取得特定元素
現在我們已經討論了檢索基本元素,接下來我們將探討如何從 SOAP 訊息中提取特定部分。
5.1.按標籤名稱取得元素
我們可以使用getElementsByTagName()
方法來取得特定元素。該方法傳回一個NodeList
。此外, Node
是所有 DOM 元件的主要資料類型。換句話說,所有的元素、屬性和文字內容都被認為是Node
類型。
讓我們從 XML 中提取Name
元素:
@Test
void whenGetElementsByTagName_thenReturnCorrectBodyElement() throws Exception {
SOAPEnvelope soapEnvelope = getSoapEnvelope();
SOAPBody soapBody = soapEnvelope.getBody();
NodeList nodes = soapBody.getElementsByTagName("be:Name");
assertNotNull(nodes);
Node node = nodes.item(0);
assertNotNull(node);
assertEquals("Working with JUnit", node.getTextContent());
}
這裡要注意的是,我們需要將命名空間前綴傳遞給方法才能使其正常運作。
同樣,我們可以使用相同的方法從 SOAP 標頭取得元素:
@Test
void whenGetElementsByTagName_thenReturnCorrectHeaderElement() throws Exception {
SOAPEnvelope soapEnvelope = getSoapEnvelope();
SOAPHeader soapHeader = soapEnvelope.getHeader();
NodeList nodes = soapHeader.getElementsByTagName("be:Username");
assertNotNull(nodes);
Node node = nodes.item(0);
assertNotNull(node);
assertEquals("baeldung", node.getTextContent());
}
5.2.迭代子節點
從特定元素獲取值的另一種方法是迭代子節點。
讓我們看看如何迭代 body 元素的子節點:
@Test
void whenGetElementUsingIterator_thenReturnCorrectBodyElement() throws Exception {
SOAPEnvelope soapEnvelope = getSoapEnvelope();
SOAPBody soapBody = soapEnvelope.getBody();
NodeList childNodes = soapBody.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if ("Name".equals(node.getLocalName())) {
String name = node.getTextContent();
assertEquals("Working with JUnit", name);
}
}
}
5.3.使用 XPath
接下來,讓我們看看如何使用 XPath 提取元素。簡單來說,XPath 是用來描述 XML 部分的語法。此外,它還可以與 XPath 表達式一起使用,我們可以使用 XPath 表達式在特定條件下檢索元素。
首先,讓我們建立一個新的 XPath 實例:
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
為了有效地處理命名空間,讓我們定義命名空間上下文:
xpath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if ("be".equals(prefix)) {
return "http://www.baeldung.com/soap/";
}
return null;
}
// other methods
});
這樣,XPath 就知道在哪裡可以找到我們的資料。
接下來,我們定義檢索Name
元素值的 XPath 表達式:
XPathExpression expression = xpath.compile("//be:Name/text()");
在這裡,我們使用路徑表達式和返回節點文字內容的text()
函數的組合創建了 XPath 表達式。
最後,我們呼叫evaluate()
方法來檢索匹配表達式的結果:
String name = (String) expression.evaluate(soapBody, XPathConstants.STRING);
assertEquals("Working with JUnit", name);
此外,我們可以建立一個忽略名稱空間的表達式:
@Test
void whenGetElementUsingXPathAndIgnoreNamespace_thenReturnCorrectResult() throws Exception {
SOAPBody soapBody = getSoapBody();
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
XPathExpression expression = xpath.compile("//*[local-name()='Name']/text()");
String name = (String) expression.evaluate(soapBody, XPathConstants.STRING);
assertEquals("Working with JUnit", name);
}
我們在表達式中使用local-name()
函數來忽略名稱空間。因此,表達式選擇具有本機名稱Name
任何元素,而不考慮命名空間前綴。
六,結論
在本文中,我們學習如何使用 Java 從 SOAP 訊息中取得特定部分。
總而言之,有多種方法可以從 SOAP 訊息中檢索某些元素。我們探索了一些方法,例如透過標籤名稱搜尋元素、迭代子節點以及使用 XPath 表達式。
與往常一樣,完整的程式碼範例可以在 GitHub 上取得。