<root>
<program name="SomeProgramName">
<params>
<param name='name'>test</param>
<param name='name2'>test2</param>
</params>
</program>
</root>
I have the above xml doc. I need to change the value of test to a new value
I read in the xml doc as
String xmlfile = "path\\to\\file.xml"
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(xmlfile);
//get the params element
Node params = doc.getElementsByTagName("params").item(0);
//get a list of nodes in the params element
NodeList param = params.getChildNodes();
This is where I am stuck. I can't find a method to set the value of one of the param elements by the "name"
I'm using java 1.7
You'll need to type each Node to type Element to be able to set the text and attributes. You might want to look at XPath, which simplifies things like this.
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
public class Demo {
public static void main(String[] args) throws Exception {
String xmlfile = "src/forum17753835/file.xml";
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(xmlfile);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
Element element = (Element) xpath.evaluate("/root/program/params/param[#name='name2']", doc, XPathConstants.NODE);
System.out.println(element.getTextContent());
}
}
NodeList params = doc.getElementsByTagName("param");
for (int i = 0; i < params.getLength(); i++)
{
if (params.item(i).getAttributes().getNamedItem("name").getNodeValue().equals("name2"))
{
// do smth with element <param name='name2'>test2</param>
// that is params.item(i) in current context
}
}
Related
Thanks in advance.
I have a xml with 2 default namespace at rootlevel and then as element level.
<?xml version="1.0" encoding="UTF-8"?>
<Msg xmlns="http://www.geological.com">
<header>
<date>08-08-2021</date>
<jur>US</jur>
</header>
<Demographic xmlns="urn:com.test:009">
<geoData>
<id>DL89716</id>
<name>North</name>
</geoData>
</Demographic>
</Msg>
I am using Java DOM parser to read this xml and fetch value of "id".
Still I am getting value as null
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
dbFactory.setNamespaceAware(true);
document = dBuilder.parse(new InputSource(new StringReader(xmlPayLoad)));
document.normalize();
XPathEvaluator xPathObj = (XPathEvaluator)XPathFactory.newInstance(NamespaceConstant.OBJECT_MODEL_SAXON).newXPath();
xPathObj.setNamespaceContext(new MyNameSpace());
xPathObj.getStaticContext().setDefaultElementNamespace("http://www.geological.com");
XPathExpression expr = xPathObj.compile(xpath);
Object result = expr.evaluate(document, XPathConstants.NODESET);
NodeList nodeList = (NodeList) result;
private static class MyNameSpace implements NamespaceContext {
//The lookup for the namespace uris is delegated to the stored document.
public String getNamespaceURI(String prefix) {
if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return null;
} if("ns".equals(prefix)){
return "urn:com.test:009";
}
}
public String getPrefix(String namespaceURI) {
return sourceDocument.lookupPrefix(namespaceURI);
}
#SuppressWarnings("rawtypes")
public Iterator getPrefixes(String namespaceURI) {
return null;
}
}
Here is a fully functional example:
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
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.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class NamespacesExample {
private static String xmlPayLoad =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<Msg xmlns=\"http://www.geological.com\">\n" +
" <header>\n" +
" <date>08-08-2021</date>\n" +
" <jur>US</jur>\n" +
" </header>\n" +
" <Demographic xmlns=\"urn:com.test:009\">\n" +
" <geoData>\n" +
" <id>DL89716</id>\n" +
" <name>North</name>\n" +
" </geoData>\n" +
" </Demographic>\n" +
"</Msg>";
public static void main(String[] args) {
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = null;
dbFactory.setNamespaceAware(true);
dBuilder = dbFactory.newDocumentBuilder();
Document document = dBuilder.parse(new InputSource(new StringReader(xmlPayLoad)));
final Map<String, String> ns = new HashMap<>();
ns.put("geo", "http://www.geological.com");
ns.put("test", "urn:com.test:009");
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new MyNameSpace(ns));
XPathExpression expr = xpath.compile("/geo:Msg/test:Demographic/test:geoData/test:id/text()");
String result = (String) expr.evaluate(document, XPathConstants.STRING);
System.out.println("Result: " + result);
} catch (ParserConfigurationException | IOException | XPathExpressionException | SAXException e) {
e.printStackTrace();
}
}
private static class MyNameSpace implements NamespaceContext {
private final Map<String, String> ns;
MyNameSpace(Map<String, String> ns) {
this.ns = new HashMap<>(ns);
this.ns.put(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
this.ns.put(XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.XMLNS_ATTRIBUTE_NS_URI);
}
#Override
public String getNamespaceURI(String prefix) {
if(prefix == null) {
throw new IllegalArgumentException();
}
final String uri = ns.get(prefix);
return uri == null ? XMLConstants.NULL_NS_URI : uri;
}
#Override
public String getPrefix(String namespaceURI) {
throw new UnsupportedOperationException();
}
#Override
public Iterator getPrefixes(String namespaceURI) {
throw new UnsupportedOperationException();
}
}
}
Some remarks:
The order of these statements is significant. Otherwise there is no namespace awareness:
dbFactory.setNamespaceAware(true);
dBuilder = dbFactory.newDocumentBuilder();
Why do you use XPathEvaluator? There is no need for that. Using the interface XPath is enough.
What is NamespaceConstant.OBJECT_MODEL_SAXON? At least in this example, we don't need it.
With my generic NamespaceContext implementation you can use a simple Map<String, String> to define the namespace prefixes for XPATH evaluation.
Dedicated prefixes should be used for each namespace used in the XML, regardless of how the namespace is declared in the XML document.
Then you can use this XPATH expression to extract the id: /geo:Msg/test:Demographic/test:geoData/test:id/text()
Output is:
Result: DL89716
I would use //*:id as the path if you know there is a single id element you are looking for, or at least there are not several id elements from different namespaces and you want to select only those from one namespace.
If you only want to select those from one namespace (e.g. urn:com.test:009) then set that as the default namespace and you can simply use //id or //Demographic/geoData/id.
Only if you really need to select elements from different namespaces you need to bind prefixes.
With the Java 8 built-in JAXP XPathFactory and a not namespace aware DocumentBuilderFactory the following also works for me to select the id element node as then the default namespace declarations are ignored when building the DOM tree:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(false);
DocumentBuilder jaxpDocumentBuilder = documentBuilderFactory.newDocumentBuilder();
Document domDoc = jaxpDocumentBuilder.parse(new File("sample1.xml"));
XPathFactory jaxpXPathFactory = XPathFactory.newInstance();
Node resultDomNode = (Node)jaxpXPathFactory.newXPath().evaluate("/Msg/Demographic/geoData/id", domDoc, XPathConstants.NODE);
I think in your original code, once you build a namespace aware DOM, with your use of the Saxon API, you could get away with setting
xPathObj.getStaticContext().setUnprefixedElementMatchingPolicy(UnprefixedElementMatchingPolicy.ANY_NAMESPACE);
and not to set up any namespace context nor default element namespace.
The other way with Saxon 10 and XPath to match elements in any namespace with selectors like id I could find is to dive into its low-level API to mix it with the s9api:
Processor processor = new Processor(false);
DocumentBuilder docBuilder = processor.newDocumentBuilder();
XdmNode input = docBuilder.build(new File("sample1.xml"));
NodeInfo contextItem = input.getUnderlyingNode();
XPathEvaluator xpathEvaluator = new XPathEvaluator(processor.getUnderlyingConfiguration());
IndependentContext independentContext = new IndependentContext();
independentContext.setUnprefixedElementMatchingPolicy(UnprefixedElementMatchingPolicy.ANY_NAMESPACE);
xpathEvaluator.setStaticContext(independentContext);
XPathExpression expression = xpathEvaluator.createExpression("/Msg/Demographic/geoData/id");
NodeInfo resultInfo = (NodeInfo) expression.evaluateSingle(expression.createDynamicContext(contextItem));
XdmNode resultNode = new XdmNode(resultInfo);
System.out.println(resultNode);
<definitions>
<form name="enable">
<data1>...</data1>
<data2>...</data2>
<data3>...</data3>
</form>
<form>
<data1>...</data1>
<data2>...</data2>
<data3>...</data3>
</form>
...
</definitions>
I want to remove the definitions tag child elements(form) those are having the name attribute. For eg: in the above case, I want to remove the first form element from the document. How to do this in java?
The code that removes all forms that have the name attribute:
import java.io.File;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import org.w3c.dom.*;
public class XMLDemo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
Document document = dbf.newDocumentBuilder().parse(new File("input.xml"));
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
// Create XPathExpression object
XPathExpression expression = xpath.compile("/definitions/form[#name]");
// Evaluate expression result on XML document
NodeList nodes = (NodeList) expression.evaluate(document, XPathConstants.NODESET);
if (nodes.getLength() > 0) {
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
node.getParentNode().removeChild(node);
}
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.transform(new DOMSource(document), new StreamResult(System.out));
}
}
If you want to remove only forms with name = "enable" make this change:
// Create XPathExpression object
XPathExpression expression = xpath.compile("/definitions/form[contains(#name, 'enable')]");
I am using XPATH to parse xml document,please find the xml below
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<bookEvent>
<bookName>harry_potter</bookName>
<bookEntity>comic</bookEntity>
<bookEntityId>10987645</bookEntityId>
<bookParameter>
<name>Name1</name>
<value>value1</value>
</bookParameter>
<bookParameter>
<name>Name2</name>
<value>value2</value>
</bookParameter>
<bookParameter>
<name>Name3</name>
<value>value3</value>
</bookParameter>
<bookParameter>
<name>Name4</name>
<value>value4</value>
</bookParameter>
<bookParameter>
<name>Name5</name>
<value>value5</value>
</bookParameter>
</bookEvent>
</soap:Body>
</soap:Envelope>
Here I would like to convert BookParameters to Map like below
{"Name1":"value1","Name2":"value2" etc}
I have tried the below code and i can get a Map but not in the expected format,
try{
Map<String,String> eventParameters = new HashMap<>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("book.xml");
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
NodeList nodeList = (NodeList)xpath.compile("//bookEvent//eventParameter").evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if(node.hasChildNodes()) {
NodeList childNodes = node.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node childNode = childNodes.item(j);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(childNode.getNodeName()+"::"+childNode.getNodeValue()+"::"+childNode.getTextContent());
eventParameters.put(childNode.getTextContent(),childNode.getTextContent());
}
}
}
}
System.out.println("print map::"+eventParameters);
} catch (Exception e) {
e.printStackTrace();
}
The output looks like this
print map::{Name3=Name3, Name4=Name4, value5=value5, Name5=Name5, value2=value2, value1=value1, value4=value4, value3=value3, Name1=Name1, Name2=Name2}
Please somebody guide me to create a below map from the xml,Any help would be appreciable.
{"Name1":"value1","Name2":"value2" etc}
You can do it as a one-liner in XPath 3.1:
map:merge(//bookParameter!map{string(name): string(value)})
=> serialize(map{'method':'json'})
You can run XPath 3.1 from Java by installing Saxon-HE 9.8 (open source)
Use Below code :
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class ReadXMLFile {
public static Map<String,String> hMap = new LinkedHashMap<>();
public static void main(String argv[]) {
try {
File fXmlFile = new File("C:\\Users\\jaikant\\Desktop\\QUESTION.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("bookParameter");
for (int parameter = 0; parameter < nodeList.getLength(); parameter++) {
Node node = nodeList.item(parameter);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) node;
String name = eElement.getElementsByTagName("name").item(0).getTextContent();
String value = eElement.getElementsByTagName("value").item(0).getTextContent();
hMap.put(name, value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
hMap.forEach((h,k) -> {
System.out.println(h + ":" + k);
});
}
}
It will print exactly what you are looking for.
<?xml version="1.0" encoding="UTF-8"?>
<JDF DescriptiveName="DescriptiveName" ID="n0001" JobID="1101-CCC-0" JobPartID="1" ProjectID="">
<Comment Name="Materialnummer">XXXXXXX</Comment>
<NodeInfo LastEnd="2014-03-12T18:00:00+01:00">
<EmployeeRef rRef="EMPCSR"/>
</NodeInfo>
<CustomerInfo CustomerID="1740">
</CustomerInfo>
<ResourcePool>
</ResourcePool>
<ResourceLinkPool>
</ResourceLinkPool>
<JDF Category="FinalImaging" ID="n0002" Status="Waiting" Type="ProcessGroup" Types="XXX">
<ResourcePool>
</ResourcePool>
<ResourceLinkPool>
</ResourceLinkPool>
</JDF>
<JDF ID="n0002" Status="Waiting" Type="ProcessGroup" Types="PrePressPreparation">
<ResourcePool>
</ResourcePool>
<ResourceLinkPool>
</ResourceLinkPool>
</JDF>
</JDF>
How do I get the root element value. For this example I want to get the DescriptiveName,ID,JobID and ProjectID. I managed to read other values but stuck in root emlement. Please advice.
EDITED
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
//System.out.println("*************************");
String expression = "/JDF";
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
A sample here :
import java.io.File;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class Main {
public static void main(String[] argv) throws Exception{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setExpandEntityReferences(false);
Document doc = factory.newDocumentBuilder().parse(new File("filename"));
Element root = null;
NodeList list = doc.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i) instanceof Element) {
root = (Element) list.item(i);
break;
}
}
root = doc.getDocumentElement();
}
}
You can get the attributes from root object
I want to append an attribute an existing element in XML using Java. For example:
<employee>
<details name="Jai" age="25"/>
<details name="kishore" age="30"/>
</employee>
It want to add weight to it (assume that it is calculated and then appended in response). How can I append that to all items?
<details name="Jai" age="25" weight="55"/>
import org.w3c.dom.*;
import java.io.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
public class AddAndPrint {
public static void main(String[] args) {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse("/path/to/file.xml");
NodeList employees = document.getElementsByTagName("employee");
for (Node employee : employees) {
for (Node child : employee.getChildNodes() {
if ("details".equals(child.getNodeName()) child.setAttribute("weight", "150");
}
}
try {
Source source = new DOMSource(doc);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, result);
System.out.println(stringWriter.getBuffer().toString());
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
}
}
Here is a quick solution based on jdom:
public static void main(String[] args) throws JDOMException, IOException {
File xmlFile = new File("employee.xml");
SAXBuilder builder = new SAXBuilder();
Document build = builder.build(xmlFile);
XPath details = XPath.newInstance("//details");
List<Element> detailsNodes = details.selectNodes(build);
for (Element detailsNode:detailsNodes) {
detailsNode.setAttribute("weight", "70"); // static weight for demonstration
}
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.output(build, System.out);
}
First, we build a document (SAXBuilder), next we create a XPath expression for the details node, then we iterate through the elements for that expression and add the weight attribute.
The last two lines just verify that it's white magic :-)