首页 > 解决方案 > 使用 xpath 编辑 xml 上的值会导致 java 中的 nullpointerexception

问题描述

我们正在尝试使用 Java 在以下 xml 文件中编辑 number、dateFrom 和 dateTo:

<?xml version="1.0" encoding="UTF-8"?>
<urn:receive
        xmlns:urn="urn:xxx"
        xmlns:ns="xxx"
        xmlns:ns1="xxx"
        xmlns:urn1="urn:xxx">
    <ns:info>
        <ns:TransaktionIdentifikator>xxx-xxx-xxx-xxx-xxx</ns:TransaktionIdentifikator>
        <ns:TransaktionTid>2015-11-22T12:00:00.146+02:00</ns:TransaktionTid>
    </ns:info>
    <urn:give>
        <urn:giveNumber>
           <ns1:number>12345678</ns1:number>
        </urn:giveNumber>
        <urn:giveDates>
            <urn1:dateFrom>2021-07-01</urn1:dateFrom>
            <urn1:dateTo>2021-09-30</urn1:dateTo>
        </urn:giveDates>
    </urn:give>
</urn:receive>

我们使用 xpath 解析 xml 文件,然后使用以下代码行使用转换器更新 xml 文件:

public class test {

    public void receiveFunc() {
        String serviceResponse = "";
        String tests = "12344321";
        try {

            // our XML file for this example
            File xmlFile = new File("{name}.xml");

            DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
            DocumentBuilder b = f.newDocumentBuilder();
            Document doc = b.parse(xmlFile);
            doc.getDocumentElement().normalize();

            XPath xPath = XPathFactory.newInstance().newXPath();

            Node SENummer = (Node) xPath                
               .compile("/urn:receive/urn:give/urn:giveNumber/ns1:number")
               .evaluate(doc, XPathConstants.NODE);

            SENummer.setTextContent(tests);

            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 (Exception e) {
        e.printStackTrace();
    }
  }
}

请注意,在上面的示例中,应该使用值为“12344321”的字符串 test 更新该数字,但这不会发生,并且我们会收到一个空指针异常。我们认为异常是因为这条线引起的:

Node SENummer = (Node) xPath
     .compile("/urn:receive/urn:give/urn:giveNumber/ns1:number")
     .evaluate(doc, XPathConstants.NODE); 

也许它没有正确解决。在我们找出导致空指针异常的原因之后,dateTo 和 dateFrom 应该很容易更新。

堆栈跟踪:

java.lang.NullPointerException
    at dk.skat.rsu.b2b.sample.test.receiveFunc(test.java:173)
    at dk.skat.rsu.b2b.sample.mvc.ServiceTestAction.execute(ServiceTestAction.java:62)
    at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)
    at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)
    at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
    at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
    at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:305)
    at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
    at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
    at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:852)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
    at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:206)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:219)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
    at org.eclipse.jetty.server.Server.handle(Server.java:530)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:347)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:256)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:382)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:708)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:626)
    at java.lang.Thread.run(Thread.java:748)## Heading ##

标签: javaxmlxpath

解决方案


给定您的 XML,最短的代码是利用 DOM 文档的查找方法来动态启动命名空间上下文:

    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setNamespaceAware(true);

    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

    Document document = documentBuilder.parse("sample1.xml");

    XPath xpath = XPathFactory.newInstance().newXPath();

    xpath.setNamespaceContext(new NamespaceContext() {
        @Override
        public String getNamespaceURI(String prefix) {
            return document.lookupNamespaceURI(prefix);
        }

        @Override
        public String getPrefix(String namespaceURI) {
            return document.lookupPrefix(namespaceURI);
        }

        @Override
        public Iterator getPrefixes(String namespaceURI) {
            return null;
        }
    });


    Node SENummer = (Node)xpath.evaluate("/urn:receive/urn:give/urn:giveNumber/ns1:number", document, XPathConstants.NODE);

推荐阅读