Update XML attribute value in document tree - java

I am not too sure why i cannot modify an attribute to my xml. The code below i used to get the read the attributes from the XML. Pulls the attributes without any issues.
document = documentBuilder.parse(file);
NodeList sessionNodelist = document.getElementsByTagName("session");
if (sessionNodelist.getLength() > 0)
{
Element sessionElement = (Element) sessionNodelist.item(0);
String timeout = sessionElement.getAttribute("timeout");
String warning = sessionElement.getAttribute("warning");
}
Now when i go to set them, it doesn't work and I am not too sure why. The code is below. it's the exact same code i used to pull the atribles, but instead of the getAttribute i used setAttribute which takes two parameters. setAttribute(String name, String Value).
document = documentBuilder.parse(file);
NodeList sessionNodelist = document.getElementsByTagName("session");
if (sessionNodelist.getLength() > 0)
{
Element sessionElement = (Element) sessionNodelist.item(0);
sessionElement.setAttribute("timeout","12");
sessionElement.setAttribute("warning", "10");
}
Any ideas?

You need to write the document tree back to the XML file. See this page for how to write a DOM tree to a file.
You would use a javax.xml.transform.Transformer to write the object into the file as follows:
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(file);
transformer.transform(source, result);

Related

How to Parse Complete XML into a string using DOM PARSER?

For example:
If I pass tagValue=1 then it should return complete xml1 as a string to me String input is in some function.
String input = "<1><xml1></xml1></1><2><xml2></xml2><2>.......<10000><xml10000></xml10000></10000‌​>";
String output = "<xml1></xml1>"; // for tagValue=1;
If the xml has a root element then it is doable
1. Parse the XML using dom parser.
2. Iterate through each node
3. Find the desired node.
4. Write the node in a different xml using transform
Sample code
Step 1: I used XML as a string, you can read from file.
DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(uri));
Document doc = dBuilder.parse(is);
Iterate through each node
if (doc.hasChildNodes()) {
printNote(doc.getChildNodes(), doc);
}
Please put in your logic to iterate thorugh the nodes and find the right child node which you want to process.
Write back as xml. Here assumption is that tempNode is the one you want to write as XML.
TransformerFactory tFactory =
TransformerFactory.newInstance();
Transformer transformer;
try {
transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(tempNode);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
You are not parsing XML, you are parsing a String, a replace should be enough in your particular case
String input = "<xml1><note><to>Tove</to><from>Jani</from<heading>Reminder</heading><body>Don't forget me this weekend</body></note><xml1>";
input = input.replace("<xml1>", "");

Delete an xml Element and copy the same element in a new xml -- in java

I am having some problem in deleting and copying the same xml element. The problem is I have 2 xml files and after comparing both I want to delete the element(s) those are only in file1 and at the same copy I want to copy these elements in a newly generated xml. I can delete the elements but I am not able to copy them in another xml file.
Here is the code:
for (Map.Entry<String, Element> entry : Map1.entrySet()) {
String key = entry.getKey();
if (!Map2.containsKey(key)) {
Map1.remove(key);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc= builder.newDocument();
Element rootElement =
doc.createElementNS("", "missing");
doc.appendChild(rootElement);
//here i want to copy the deleted element in new xml file.
//rootElement.appendChild(Map1.get(key));
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(doc);
StreamResult newXml = new StreamResult(new File("C:/user/desktop/Output.xml"));
transformer.transform(source, newXml);
}
}
Shift the part where Map1.remove(key); to the end of the code. Your rootElement.appendChild(Map1.get(key)) would not work because key is no longer in Map1 after you removed it.

java xml document.getTextContent() stays empty

I'm trying to build an xml document in a JUnit test.
doc=docBuilder.newDocument();
Element root = doc.createElement("Settings");
doc.appendChild(root);
Element label0 = doc.createElement("label_0");
root.appendChild(label0);
String s=doc.getTextContent();
System.out.println(s);
Yet the document stays empty (i.e. the println yields null.) I don'thave a clue why that is. The actual problem is that a subsequent XPath expression throws the error: Unable to evaluate expression using this context.
The return value of getTextContent on Document is defined to null- See Node.
To retreive the text contents call getTextNode on the root element
I imagine you want to serialize the document to pass it to the test case.
To do this you have to pass your document to an empty XSL transformer, like this:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);
See also: How to pretty print XML from Java?

Adding namespace to an already created XML document

I am creating a W3C Document object using a String value. Once I created the Document object, I want to add a namespace to the root element of this document. Here's my current code:
Document document = builder.parse(new InputSource(new StringReader(xmlString)));
document.getDocumentElement().setAttributeNS("http://com", "xmlns:ns2", "Test");
document.setPrefix("ns2");
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
Source src = new DOMSource(document);
Result dest = new StreamResult(new File("c:\\xmlFileName.xml"));
aTransformer.transform(src, dest);
What I use as input:
<product>
<arg0>DDDDDD</arg0>
<arg1>DDDD</arg1>
</product>
What the output should look like:
<ns2:product xmlns:ns2="http://com">
<arg0>DDDDDD</arg0>
<arg1>DDDD</arg1>
</ns2:product>
I need to add the prefix value and namespace also to the input xml string. If I try the above code I am getting this exception:
NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
Appreciate your help!
Since there is not an easy way to rename the root element, we'll have to replace it with an element that has the correct namespace and attribute, and then copy all the original children into it. Forcing the namespace declaration is not needed because by giving the element the correct namespace (URI) and setting the prefix, the declaration will be automatic.
Replace the setAttribute and setPrefix with this (line 2,3)
String namespace = "http://com";
String prefix = "ns2";
// Upgrade the DOM level 1 to level 2 with the correct namespace
Element originalDocumentElement = document.getDocumentElement();
Element newDocumentElement = document.createElementNS(namespace, originalDocumentElement.getNodeName());
// Set the desired namespace and prefix
newDocumentElement.setPrefix(prefix);
// Copy all children
NodeList list = originalDocumentElement.getChildNodes();
while(list.getLength()!=0) {
newDocumentElement.appendChild(list.item(0));
}
// Replace the original element
document.replaceChild(newDocumentElement, originalDocumentElement);
In the original code the author tried to declare an element namespace like this:
.setAttributeNS("http://com", "xmlns:ns2", "Test");
The first parameter is the namespace of the attribute, and since it's a namespace attribute it need to have the http://www.w3.org/2000/xmlns/ URI. The declared namespace should come into the 3rd parameter
.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns2", "http://com");
Bellow approach also works for me, but probably should not use in performance critical case.
Add name space to document root element as attribute.
Transform the document to XML string. The purpose of this step is to make the child element in the XML string inherit parent element namespace.
Now the xml string have name space.
You can use the XML string to build a document again or used for JAXB unmarshal, etc.
private static String addNamespaceToXml(InputStream in)
throws ParserConfigurationException, SAXException, IOException,
TransformerException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
/*
* Must not namespace aware, otherwise the generated XML string will
* have wrong namespace
*/
// dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(in);
Element documentElement = document.getDocumentElement();
// Add name space to root element as attribute
documentElement.setAttribute("xmlns", "http://you_name_space");
String xml = transformXmlNodeToXmlString(documentElement);
return xml;
}
private static String transformXmlNodeToXmlString(Node node)
throws TransformerException {
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
StringWriter buffer = new StringWriter();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(node), new StreamResult(buffer));
String xml = buffer.toString();
return xml;
}
Partially gleaned from here, and also from a comment above, I was able to get it to work (transforming an arbitrary DOM Node and adding a prefix to it and all its children) thus:
private String addNamespacePrefix(Document doc, Node node) throws TransformerException {
Element mainRootElement = doc.createElementNS(
"http://abc.de/x/y/z", // namespace
"my-prefix:fake-header-element" // prefix to "register" it with the DOM so we don't get exceptions later...
);
List<Element> descendants = nodeListToArrayRecurse(node.getChildNodes()); // for some reason we have to grab all these before doing the first "renameNode" ... no idea why ...
mainRootElement.appendChild(node);
doc.renameNode(node, "http://abc.de/x/y/z", "my-prefix:" + node.getNodeName());
descendants.stream().forEach(c -> doc.renameNode(c, "http://abc.de/x/y/z", "my-prefix:" + c.getNodeName()));
}
private List<Element> nodeListToArrayRecurse(NodeList entryNodes) {
List<Element> allEntries = new ArrayList<>();
for (int i = 0; i < entryNodes.getLength(); i++) {
Node child = entryNodes.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
allEntries.add((Element) child);
allEntries.addAll(nodeListToArray(child.getChildNodes())); // recurse
} // ignore other [i.e. text] nodes https://stackoverflow.com/questions/14566596/loop-through-all-elements-in-xml-using-nodelist
}
return allEntries;
}
If it helps anybody. I then convert it to string, then manually remove the extra header and closing lines. What a pain, I must be doing something wrong...
This seems to be working for me, and it's much simpler than those answers provided:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(new File(filename));
document.getDocumentElement().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:yourNamespace", "http://whatever/else");

How to insert tag in xml file

I have a XML document, i want to insert more number of tag. example
<data>
<tag1>1St tag</tag1>
<tag2>2nd tag</tag2>
<tag3>NewTag</tag3>
<tag4>4th tag</tag4>
</data>
I have tried to insert the data, but whenever i insert the data the inserting element occurred at once
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setIgnoringComments(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new File("File.xml"));
NodeList nodes = doc.getElementsByTagName("tag4");
Text a = doc.createTextNode("value");
Element p = doc.createElement("tag3");
p.appendChild(a);
for (int i = 0; i < nodes.getLength(); i++) {
nodes.item(i).getParentNode().insertBefore(p, nodes.item(i));
}
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlOutput = result.getWriter().toString();
System.out.println(xmlOutput);
System.out.println("Done");
This code is adding new element but whenever i insert new tag it rewrite the new tag name into existing tag. How to rectify the issue. To be simple i want to insert more tag in XML file.
// Add a text node to the element
element.appendChild(doc.createTextNode("D"));
// Add a text node to the beginning of the element
element.insertBefore(doc.createTextNode("A"), element.getFirstChild());
// Add a text node before the last child of the element
element.insertBefore(doc.createTextNode("C"), element.getLastChild());
// Add another element after the first child of the root element
Element element2 = doc.createElement("item");
element.insertBefore(element2, element.getFirstChild().getNextSibling());
// Add a text node in front of the new item element
element2.getParentNode().insertBefore(doc.createTextNode("B"), element2);
Sample piece of code which will be helpful for you to add

Categories