Java使用XPath修改XML节点值时出现NullPointerException问题求助
问题根因
空指针异常核心原因是Java XPath默认无法直接解析带自定义命名空间的XML,代码存在两处关键缺失:
- 没有开启DOM解析器的命名空间感知能力
- 没有给XPath实例注册命名空间前缀与对应URI的映射规则
这就导致写好的XPath路径无法匹配到对应节点,evaluate方法返回null,后续调用SENummer.setTextContent(tests)时触发空指针。
修复步骤
1. 开启命名空间感知
创建DocumentBuilderFactory后立即开启命名空间支持:
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); f.setNamespaceAware(true); // 新增这行,必须开启才能处理带命名空间的XML
2. 实现自定义命名空间上下文
自定义NamespaceContext实现类,绑定XML中用到的前缀和对应URI:
class CustomNamespaceContext implements NamespaceContext { @Override public String getNamespaceURI(String prefix) { switch (prefix) { case "urn": return "urn:xxx"; case "ns1": return "xxx"; case "urn1": return "urn:xxx"; default: return XMLConstants.NULL_NS_URI; } } @Override public String getPrefix(String namespaceURI) { return null; // 不需要用到可以不实现 } @Override public Iterator<String> getPrefixes(String namespaceURI) { return null; // 不需要用到可以不实现 } }
3. 给XPath设置命名空间上下文
创建XPath实例后绑定自定义上下文:
XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new CustomNamespaceContext()); // 新增这行
4. 补充节点非空判断
拿到节点后先判断是否为null,避免异常:
Node SENummer = (Node) xPath.compile("/urn:receive/urn:give/urn:giveNumber/ns1:number").evaluate(doc, XPathConstants.NODE); if (SENummer != null) { SENummer.setTextContent(tests); }
dateFrom、dateTo的更新逻辑
两个字段的XPath路径分别为:
- dateFrom:
/urn:receive/urn:give/urn:giveDates/urn1:dateFrom - dateTo:
/urn:receive/urn:give/urn:giveDates/urn1:dateTo
和number字段的修改逻辑一致,直接复用上下文即可。
完整修复代码
import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.io.File; import java.io.IOException; import java.util.Iterator; public class test { static class CustomNamespaceContext implements NamespaceContext { @Override public String getNamespaceURI(String prefix) { switch (prefix) { case "urn": return "urn:xxx"; case "ns1": return "xxx"; case "urn1": return "urn:xxx"; default: return XMLConstants.NULL_NS_URI; } } @Override public String getPrefix(String namespaceURI) {return null;} @Override public Iterator<String> getPrefixes(String namespaceURI) {return null;} } public void receiveFunc() { String tests = "12344321"; String newDateFrom = "2024-01-01"; String newDateTo = "2024-03-31"; try { File xmlFile = new File("{name}.xml"); DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); f.setNamespaceAware(true); DocumentBuilder b = f.newDocumentBuilder(); Document doc = b.parse(xmlFile); doc.getDocumentElement().normalize(); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new CustomNamespaceContext()); // 更新number Node numberNode = (Node) xPath.compile("/urn:receive/urn:give/urn:giveNumber/ns1:number").evaluate(doc, XPathConstants.NODE); if (numberNode != null) { numberNode.setTextContent(tests); } // 更新dateFrom Node dateFromNode = (Node) xPath.compile("/urn:receive/urn:give/urn:giveDates/urn1:dateFrom").evaluate(doc, XPathConstants.NODE); if (dateFromNode != null) { dateFromNode.setTextContent(newDateFrom); } // 更新dateTo Node dateToNode = (Node) xPath.compile("/urn:receive/urn:give/urn:giveDates/urn1:dateTo").evaluate(doc, XPathConstants.NODE); if (dateToNode != null) { dateToNode.setTextContent(newDateTo); } Transformer tf = TransformerFactory.newInstance().newTransformer(); tf.setOutputProperty(OutputKeys.INDENT, "yes"); tf.setOutputProperty(OutputKeys.METHOD, "xml"); tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); DOMSource domSource = new DOMSource(doc); StreamResult sr = new StreamResult(new File("{name}.xml")); tf.transform(domSource, sr); } catch (ParserConfigurationException | IOException | SAXException | XPathExpressionException | TransformerException e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Buster3650
相关产品推荐
相关产品推荐

