Why XPath.evaluate is returning NULL?

java, xml, xpath

Solution

xmlns="http://maven.apache.org/POM/4.0.0"

means that the un-prefixed element names in the XML file are in this namespace. In XPath 1.0 unprefixed node names always refer to nodes in no namespace, so `/project/parent/version` correctly matches nothing.

To match namespaced nodes in XPath you need to bind a prefix to the namespace URI and then use that prefix in the expression. For `javax.xml.xpath` this means creating a `NamespaceContext`. Unfortunately there are no default implementations of this interface in the standard Java library, but the Spring framework provides a SimpleNamespaceContext that you can use

XPath xpath = xPathfactory.newXPath();
SimpleNamespaceContext nsCtx = new SimpleNamespaceContext();
xpath.setNamespaceContext(nsCtx);
nsCtx.bindNamespaceUri("pom", "http://maven.apache.org/POM/4.0.0");

// ...
Node node = (Node)xpath.evaluate("/pom:project/pom:parent/pom:version/text()", source, XPathConstants.NODE);

That said, you'll still need to do a bit more work to actually modify the file, as you're currently loading it and modifying the DOM but then not saving the modified DOM anywhere.

An alternative approach might be to use XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                xmlns:pom="http://maven.apache.org/POM/4.0.0">
  <xsl:param name="newVersion" />

  <!-- identity template - copy input to output unchanged except when
       overridden -->
  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <!-- override for the version value -->
  <xsl:template match="pom:version/text()">
    <xsl:value-of select="$newVersion" />
  </xsl:template>
</xsl:stylesheet>

Then you can use the `Transformer` API to call this stylesheet with an appropriate parameter

StreamSource xslt = new StreamSource(new File("transform.xsl"));
Transformer transformer = TransformerFactory.newInstance().newTransformer(xslt);
transformer.setParameter("newVersion", newValue);
StreamSource input = new StreamSource(new File("C:\\pom.xml"));
StreamResult output = new StreamResult(new File("C:\\updated-pom.xml"));
transformer.transform(input, output);

Problem

When I use below code to modify an xml file I receive this error : ``` Exception in thread "main" java.lang.NullPointerException at ModifyXMLFile.updateFile(ModifyXMLFile.java:44) at ModifyXMLFile.main(ModifyXMLFile.java:56) ``` The error occurs at line : node.setTextContent(newValue); Am I not using xpath correctly ? Here is the code and the xml file I'm attempting to update ``` import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; 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.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.apache.commons.io.FileUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class ModifyXMLFile { public void updateFile(String newValue){ XPathFactory xPathfactory = XPathFactory.newInstance(); XPath xpath = xPathfactory.newXPath(); try { File f = new File("C:\\pom.xml"); InputStream in = new FileInputStream(f); InputSource source = new InputSource(in); Node node = (Node)xpath.evaluate("/project/parent/version/text()", source, XPathConstants.NODE); node.setTextContent(newValue); } catch (XPathExpressionException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } } public static void main(String argv[]) { new ModifyXMLFile().updateFile("TEST"); } } ``` xml file : ``` <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>testgroup</groupId> <artifactId>testartifact</artifactId> <version>update</version> </parent> </project> ```

Original source