Java Spring中解析XML返回值为null 求推荐解决方法
Hey there! The null values you're hitting are almost definitely caused by the XML namespace (http://tempuri.org/Response.xsd) in your response. Most Java XML parsers don't handle namespaces by default, so you have to explicitly account for them to pull out element values correctly. Let's go through the most recommended approaches to fix this:
First, here's your response XML for reference:
<?xml version="1.0" encoding="UTF-8"?> <Response xmlns="http://tempuri.org/Response.xsd"> <ResponseStatusDescription /> <EntityPaymentReceiptNumber /> <Description>Test</Description> <OperationName>CheckPayment</OperationName> <BankID>39</BankID> <EntityPaymentDate /> <CheckPaymentID>188721103486</CheckPaymentID> <ResponseStatusCode>INFO2</ResponseStatusCode> </Response>
1. JAXB (Java's Standard XML Binding)
JAXB is the go-to standard for mapping XML to Java objects. The key here is to explicitly declare the namespace in your entity class.
Step 1: Create the Java Entity Class
import jakarta.xml.bind.annotation.XmlRootElement; import jakarta.xml.bind.annotation.XmlElement; // Map the root element and its namespace @XmlRootElement(name = "Response", namespace = "http://tempuri.org/Response.xsd") public class Response { private String description; private String operationName; private String bankID; private String checkPaymentID; private String responseStatusCode; // JAXB requires a no-arg constructor public Response() {} // Annotate each field with the same namespace @XmlElement(namespace = "http://tempuri.org/Response.xsd") public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @XmlElement(name = "OperationName", namespace = "http://tempuri.org/Response.xsd") public String getOperationName() { return operationName; } public void setOperationName(String operationName) { this.operationName = operationName; } @XmlElement(name = "BankID", namespace = "http://tempuri.org/Response.xsd") public String getBankID() { return bankID; } public void setBankID(String bankID) { this.bankID = bankID; } @XmlElement(name = "CheckPaymentID", namespace = "http://tempuri.org/Response.xsd") public String getCheckPaymentID() { return checkPaymentID; } public void setCheckPaymentID(String checkPaymentID) { this.checkPaymentID = checkPaymentID; } @XmlElement(name = "ResponseStatusCode", namespace = "http://tempuri.org/Response.xsd") public String getResponseStatusCode() { return responseStatusCode; } public void setResponseStatusCode(String responseStatusCode) { this.responseStatusCode = responseStatusCode; } }
Step 2: Parse the XML
import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.Unmarshaller; import java.io.StringReader; public class JaxbParser { public static void main(String[] args) { String xmlResponse = "YOUR_XML_RESPONSE_STRING"; // Replace with your actual XML try { JAXBContext jaxbContext = JAXBContext.newInstance(Response.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); // Parse from string Response response = (Response) unmarshaller.unmarshal(new StringReader(xmlResponse)); // Now you can access values without nulls System.out.println("Description: " + response.getDescription()); System.out.println("CheckPaymentID: " + response.getCheckPaymentID()); System.out.println("ResponseStatusCode: " + response.getResponseStatusCode()); } catch (Exception e) { e.printStackTrace(); } } }
Note for Java 9+: JAXB is no longer included in the default JDK. Add this Maven dependency to your project:
<dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>4.0.0</version> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>4.0.0</version> <scope>runtime</scope> </dependency>
2. DOM Parsing (Manual Approach)
If you prefer a more hands-on approach, DOM parsing works well for small XML payloads. The critical step here is enabling namespace awareness.
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.StringReader; public class DomParser { public static void main(String[] args) { String xmlResponse = "YOUR_XML_RESPONSE_STRING"; String namespaceUri = "http://tempuri.org/Response.xsd"; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // Enable namespace support (this is the key fix!) factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new StringReader(xmlResponse)); Element root = doc.getDocumentElement(); // Use getElementsByTagNameNS to target elements in the correct namespace NodeList descriptionNodes = root.getElementsByTagNameNS(namespaceUri, "Description"); if (descriptionNodes.getLength() > 0) { String description = descriptionNodes.item(0).getTextContent(); System.out.println("Description: " + description); } NodeList checkPaymentIdNodes = root.getElementsByTagNameNS(namespaceUri, "CheckPaymentID"); if (checkPaymentIdNodes.getLength() > 0) { String checkId = checkPaymentIdNodes.item(0).getTextContent(); System.out.println("CheckPaymentID: " + checkId); } // Repeat for other elements as needed } catch (Exception e) { e.printStackTrace(); } } }
3. Jackson XML (Alternative for Jackson Users)
If you already use Jackson for JSON processing, you can leverage its XML extension for seamless parsing.
Step 1: Add Dependency
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.15.2</version> <!-- Use the latest stable version --> </dependency>
Step 2: Create Entity Class
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; @JacksonXmlRootElement(localName = "Response", namespace = "http://tempuri.org/Response.xsd") public class JacksonResponse { @JacksonXmlProperty(localName = "Description", namespace = "http://tempuri.org/Response.xsd") private String description; @JacksonXmlProperty(localName = "CheckPaymentID", namespace = "http://tempuri.org/Response.xsd") private String checkPaymentID; @JacksonXmlProperty(localName = "ResponseStatusCode", namespace = "http://tempuri.org/Response.xsd") private String responseStatusCode; // No-arg constructor, getters, and setters public JacksonResponse() {} // Getters and setters here... }
Step 3: Parse the XML
import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class JacksonXmlParser { public static void main(String[] args) { String xmlResponse = "YOUR_XML_RESPONSE_STRING"; try { XmlMapper xmlMapper = new XmlMapper(); JacksonResponse response = xmlMapper.readValue(xmlResponse, JacksonResponse.class); System.out.println("Description: " + response.getDescription()); System.out.println("CheckPaymentID: " + response.getCheckPaymentID()); } catch (Exception e) { e.printStackTrace(); } } }
Key Takeaway
The root cause of your null values is almost certainly that your parser wasn't accounting for the XML namespace. All these solutions explicitly handle the namespace, which will resolve the issue. JAXB is the standard choice for most Java projects, while DOM or Jackson XML work great for specific use cases.
内容的提问来源于stack exchange,提问作者Rodrigue Abou Naoum

