Modify XML file with xPath - java

I want to modify an existing XML file using xPath. If the node doesn't exist, it should be created (along with it's parents if neccessary). An example:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<param0>true</param0>
<param1>1.0</param1>
</configuration>
And here are a couple of xPaths I want to insert/modify:
/configuration/param1/text() -> 4.0
/configuration/param2/text() -> "asdf"
/configuration/test/param3/text() -> true
The XML file should look like this afterwards:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<param0>true</param0>
<param1>4.0</param1>
<param2>asdf</param2>
<test>
<param3>true</param3>
</test>
</configuration>
I tried this:
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
try {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
Document doc = domFactory.newDocumentBuilder().parse(file.getAbsolutePath());
XPath xpath = XPathFactory.newInstance().newXPath();
String xPathStr = "/configuration/param1/text()";
Node node = ((NodeList) xpath.compile(xPathStr).evaluate(doc, XPathConstants.NODESET)).item(0);
System.out.printf("node value: %s\n", node.getNodeValue());
node.setNodeValue("4.0");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(doc), new StreamResult(file));
} catch (Exception e) {
e.printStackTrace();
}
The node is changed in the file after running this code. Exactly what I wanted. But if I use one of the below paths, node is null (and therefore a NullPointerException is thrown):
/configuration/param2/text()
/configuration/test/param3/text()
How can I change this code so that the node (and non existing parent nodes as well) are created?
EDIT: Ok, to clarify: I have a set of parameters that I want to save to XML. During development, this set can change (some parameters get added, some get moved, some get removed). So I basically want to have a function to write the current set of parameters to an already existing file. It should override the parameters that already exist in the file, add new parameters and leave old parameters in there.
The same for reading, I could just have the xPath or some other coordinates and get the value from the XML. If it doesn't exist, it returns the empty string.
I don't have any constraints on how to implement it, xPath, DOM, SAX, XSLT... It should just be easy to use once the functionality is written (like BeniBela's solution).
So if I have the following parameters to set:
/configuration/param1/text() -> 4.0
/configuration/param2/text() -> "asdf"
/configuration/test/param3/text() -> true
the result should be the starting XML + those parameters. If they already exist at that xPath, they get replaced, otherwise they get inserted at that point.

If you want a solution without dependencies, you can do it with just DOM and without XPath/XSLT.
Node.getChildNodes|getNodeName / NodeList.* can be used to find the nodes, and Document.createElement|createTextNode, Node.appendChild to create new ones.
Then you can write your own, simple "XPath" interpreter, that creates missing nodes in the path like that:
public static void update(Document doc, String path, String def){
String p[] = path.split("/");
//search nodes or create them if they do not exist
Node n = doc;
for (int i=0;i < p.length;i++){
NodeList kids = n.getChildNodes();
Node nfound = null;
for (int j=0;j<kids.getLength();j++)
if (kids.item(j).getNodeName().equals(p[i])) {
nfound = kids.item(j);
break;
}
if (nfound == null) {
nfound = doc.createElement(p[i]);
n.appendChild(nfound);
n.appendChild(doc.createTextNode("\n")); //add whitespace, so the result looks nicer. Not really needed
}
n = nfound;
}
NodeList kids = n.getChildNodes();
for (int i=0;i<kids.getLength();i++)
if (kids.item(i).getNodeType() == Node.TEXT_NODE) {
//text node exists
kids.item(i).setNodeValue(def); //override
return;
}
n.appendChild(doc.createTextNode(def));
}
Then, if you only want to update text() nodes, you can use it as:
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
Document doc = domFactory.newDocumentBuilder().parse(file.getAbsolutePath());
update(doc, "configuration/param1", "4.0");
update(doc, "configuration/param2", "asdf");
update(doc, "configuration/test/param3", "true");

Here is a simple XSLT solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="param1/text()">4.0</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<param2>asdf</param2>
<test><param3>true</param3></test>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<configuration>
<param0>true</param0>
<param1>1.0</param1>
</configuration>
the wanted, correct result is produced:
<configuration>
<param0>true</param0>
<param1>4.0</param1>
<param2>asdf</param2>
<test><param3>true</param3></test>
</configuration>
Do Note:
An XSLT transformation never "updates in-place". It always creates a new result tree. Therefore, if one wants to modify the same file, typically the result of the transformation is saved under another name, then the original file is deleted and the result is renamed to have the original name.

I've created a small project for using XPATH to create/update XML: https://github.com/shenghai/xmodifier
the code to change your xml is like:
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(xmlfile);
XModifier modifier = new XModifier(document);
modifier.addModify("/configuration/param1", "asdf");
modifier.addModify("/configuration/param2", "asdf");
modifier.addModify("/configuration/test/param3", "true");
modifier.modify();

I would point you to a new/novel way of doing what you described, by using VTD-XML... there are numerous reasons why VTD-XML is far better than all other solutions provided for this question... here are a few links ...
Simplify XML processing with vtd-xml
Manipulate XML the Ximple Way
Processing XML with Java – A Performance Benchmark
dfs
import com.ximpleware.*;
import java.io.*;
public class modifyXML {
public static void main(String[] s) throws VTDException, IOException{
VTDGen vg = new VTDGen();
if (!vg.parseFile("input.xml", false))
return;
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/configuration/param1/text()");
XMLModifier xm = new XMLModifier(vn);
// using XPath
int i=ap.evalXPath();
if(i!=-1){
xm.updateToken(i, "4.0");
}
String s1 ="<param2>asdf</param2>/n<test>/n<param3>true</param3>/n</test>";
xm.insertAfterElement(s1);
xm.output("output.xml");
}
}

Related

How to get relative depth of XML element using XPATH

I am trying to find the relative depth of given XML element from specific element in the given XML file, I tried to use XPATH but I'm not very familiar with XML parsing and I'm not getting the desired result. I need as well to ignore the data elements while counting.
Below is the code that I have written and the sample XML file.
E.g. the depth of NM109_BillingProviderIdentifier from TS837_2000A_Loop element is 4.
The parent nodes are: TS837_2000A_Loop < NM1_SubLoop_2 < TS837_2010AA_Loop < NM1_BillingProviderName
as NM109_BillingProviderIdentifier is a child of NM1_BillingProviderName and thus the relative depth of NM1_BillingProviderName from TS837_2000A_Loop is 4 (including TS837_2000A_Loop).
package com.xmlexamples;
import java.io.File;
import java.io.FileInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
public class XmlParser {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new FileInputStream(new File("D://sample.xml")));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
String expression;
expression = "count(NM109_BillingProviderIdentifier/preceding-sibling::TS837_2000A_Loop)+1";
Double d = (Double) xpath.compile(expression).evaluate(doc, XPathConstants.NUMBER);
System.out.println("position from TS837_2000A_Loop " + d);
}
}
<?xml version='1.0' encoding='UTF-8'?>
<X12_00501_837_P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<TS837_2000A_Loop>
<NM1_SubLoop_2>
<TS837_2010AA_Loop>
<NM1_BillingProviderName>
<NM103_BillingProviderLastorOrganizationalName>VNA of Cape Cod</NM103_BillingProviderLastorOrganizationalName>
<NM109_BillingProviderIdentifier>1487651915</NM109_BillingProviderIdentifier>
</NM1_BillingProviderName>
<N3_BillingProviderAddress>
<N301_BillingProviderAddressLine>8669 NORTHWEST 36TH ST </N301_BillingProviderAddressLine>
</N3_BillingProviderAddress>
</TS837_2010AA_Loop>
</NM1_SubLoop_2>
</TS837_2000A_Loop>
</X12_00501_837_P>
The pivotal method for getting the depth of any node is by counting its ancestors (which include the parent, the parent of the parent etc):
count(NM109_BillingProviderIdentifier/ancestor-or-self::*)
This will give you the count up to the root. To get the relative count, i.e. from anything other than the root, assuming the names do not overlap, you can do this:
count(NM109_BillingProviderIdentifier/ancestor-or-self::*)
- count(NM109_BillingProviderIdentifier/ancestor::TS837_2000A_Loop/ancestor::*)
Depending on whether the current, or the base element should be included in the count, use the ancestor-or-self or ancestor axis.
PS: you should probably thank Pietro Saccardi for so kindly making your post and your huge (4kB on one line..) sample XML readable.

is there any way other than using Xpath for this?

hello guys i'am writing this program:
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class DOMbooks {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
File file = new File("books-fixed.xml");
Document doc = docBuilder.parse(file);
NodeList list = doc.getElementsByTagName("*");
int bookCounter = 1;
for (int i = 1; i < list.getLength(); i++) {
Element element = (Element)list.item(i);
String nodeName = element.getNodeName();
if (nodeName.equals("book")) {
bookCounter++;
System.out.println("BOOK " + bookCounter);
String isbn = element.getAttribute("sequence");
System.out.println("\tsequence:\t" + isbn);
}
else if (nodeName.equals("author")) {
System.out.println("\tAuthor:\t" + element.getChildNodes().item(0).getNodeValue());
}
else if (nodeName.equals("title")) {
System.out.println("\tTitle:\t" + element.getChildNodes().item(0).getNodeValue());
}
else if (nodeName.equals("publishYear")) {
System.out.println("\tpublishYear:\t" + element.getChildNodes().item(0).getNodeValue());
}
else if (nodeName.equals("genre")) {
System.out.println("\tgenre:\t" + element.getChildNodes().item(0).getNodeValue());
}
}
}
}
i want to print all the data about the "Science Fiction" books.. i know i should use Xpath but it's stuck, with too much errors... any suggestions?
assuming that i have this table and i only want to select science fiction books with all their info
<book sequence="5">
<title>Aftershock</title>
<auther>Robert B. Reich</auther>
<publishYear>2010</publishYear>
<genre>Economics</genre>
</book>
- <book sequence="6">
<title>The Time Machine</title>
<auther>H.G. Wells</auther>
<publishYear>1895</publishYear>
<genre>Science Fiction</genre>
assuming i have this table i only want to print the Science Fiction books with all their info...
i want to print all the data about the "Science Fiction" books.. i know i should use Xpath but it's stuck,
I assume you'd mean that you want all the books for which genre == "Science Fiction", right? In that case, XPath is really much simpler than whatever you were trying in Java (you don't show the root note, so I'll start with '//', which selects at any depth):
//book[genre = 'Science Fiction']
XSLT approach to simplify things
Now, having another look at your code, it looks like you want to print each and every element, including the element's name. This is more trivially done in XSLT:
<!-- every XSLT 1.0 must start like this -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- you want text -->
<xsl:output method="text" />
<!-- match any science fiction book (your primary goal) -->
<xsl:template match="book[genre = 'Science Fiction']">
<xsl:text>BOOK </xsl:text>
<xsl:value-of select="position()" />
<!-- send the children and attribute to be processed by templates -->
<xsl:apply-templates select="#sequence | *" />
</xsl:template>
<!-- "catch" any elements or attributes under <book> -->
<xsl:template match="book/* | book/#*">
<!-- a newline and a tab per line-->
<xsl:text>
</xsl:text>
<!-- and the name of the element or attribute -->
<xsl:value-of select="local-name()" />
<!-- another tab, plus contents of the element or attribute -->
<xsl:text> </xsl:text>
<xsl:value-of select="." />
</xsl:template>
<!-- make sure that other values are ignored, but process children -->
<xsl:template match="node()">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
You can use this code, which is significantly shorter (if you ignore the comments and whitespace) and (arguably, once you get the hang of it) more readable than your original code. To use it:
Store it as books.xsl
Then, simply use this (copied and changed from here):
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
public class TestMain {
public static void main(String[] args) throws IOException, URISyntaxException, TransformerException {
TransformerFactory factory = TransformerFactory.newInstance();
Source xslt = new StreamSource(new File("books.xsl"));
Transformer transformer = factory.newTransformer(xslt);
Source text = new StreamSource(new File("books-fixed.xml"));
transformer.transform(text, new StreamResult(new File("output.txt")));
}
}
XPath 2.0
If you can use Saxon in Java, the above becomes a one-liner with XPath 2.0 and you don't even need XSLT:
for $book in //book[genre = 'Science Fiction']
return (
'BOOK',
count(//book[genre = 'Science Fiction'][. << $book]) + 1,
for $tag in $book/(#sequence | *)
return $tag/local-name(), ':', string($tag)
)

Extract a block of XML into another XML file in java

I have a XML file called word.xml containing
<A>
<Answer>How was you day</Answer>
<Question>Happy day </Question>
<Biased> good morning </Biased>
<abc>..............</abc>
.
. // few more tags here
.
</A>
Now i want to extract another XML file called word1.xml containing part of word1.xml
<A>
<Answer>How was you day</Answer>
<Question>Happy day </Question>
</A>
Java Code which I tried so far
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
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 void main(String args[]) {
try {
File stocks = new File("word.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(stocks);
doc.getDocumentElement().normalize();
System.out.println("root of xml file" + doc.getDocumentElement().getNodeName());
NodeList nodes = doc.getElementsByTagName("A");
System.out.println("==========================");
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
System.out.println("i value---"+i);
System.out.println(nodes.getLength());
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
System.out.println(element.getTextContent());
//element.getElementsByTagName(name)
File statText = new File(i+".txt");
FileOutputStream is = new FileOutputStream(statText);
OutputStreamWriter osw = new OutputStreamWriter(is);
Writer w = new BufferedWriter(osw);
w.write("<Answer>");
w.write(element.getElementsByTagName("Answer").item(0).getTextContent());
w.write("</Answer>");
w.write("Question");
w.write(element.getElementsByTagName("Question").item(0).getTextContent());
w.write("</Question>");
w.close();
}
}
}
catch (Exception ex) {
ex.printStackTrace();
}
private static String getValue(String tag, Element element) {
NodeList nodes = element.getElementsByTagName(tag).item(0).getChildNodes();
Node node = (Node) nodes.item(0);
return node.getNodeValue();
}
}
}
I just want to include tags in my results. This is the DIRTY way of doing. Can you please suggest me the best way.Need help. Thanks in advance.
If Java is not a mandatory constraint here, you can achieve this by using XSLT. It's pretty easy to follow. You can find some guidance here: Link
An example of my own practice:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="//title">
<article>
<title>
<xsl:value-of select="./name/>
<xsl:text> : </xsl:text>
<xsl:value-of select = "./number/>
</title>
<references>
<xsl:value-of select = "reference"/>
</references>
</article>
</xsl:for-each>
</xsl:template>
Hope it helps!
Just like BeginnerJava explained XSL is the most appropriate technology here as you are transforming one XML tree to another XML tree and XSL is meant for that.
in XSL the code needed to achieve what you describe would be (I skipped some bits):
<xsl:template match="A">
<xsl:copy>
<xsl:apply-templates select="Answer|Question"/>
</xsl:copy>
</xsl:template>
You can invoke XSL transfomation from you Java code or from command line like this:
java net.sf.saxon.Transform [options] source-document stylesheet [ params…]
Parse the xml into DOM using a DocumentParser. remove the elements that you don't need from the resulting Document. write the modified Document to a new File using a Transformer. (note, the details for each of these steps can be found in any of the thousands of java xml tutorials online).

Selecting xml raw text

Given xml like this:
<container>
<item>
<xmlText>
<someTag>
<otherTag>
Text
</otherTag>
</someTag>
</xmlText>
</item>
<container>
I would like to select all text that is under item/xmlText. I would like to print all the content of this node with tags (someTag, otherTag).
I would prefer to handle with this with XPath, but this is part of Java program, so if there is such mechanism I could take it as well.
Use XSLT for this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select="/container/item/xmlText/node()"/>
</xsl:template>
</xsl:stylesheet>
When this is applied on the provided XML document (corrected to be well-formed !!!):
<container>
<item>
<xmlText>
<someTag>
<otherTag>
Text
</otherTag>
</someTag>
</xmlText>
</item>
</container>
the wanted, correct result is produced:
<someTag>
<otherTag>
Text
</otherTag>
</someTag>
When this is your Element retrieved with XPath
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
Element element = (Element) xpath.evaluate(
"/container/item/xmlText", document, XPathConstants.NODE);
Then, you can do something along these lines:
java.io.ByteArrayOutputStream data =
new java.io.ByteArrayOutputStream();
java.io.PrintStream ps = new java.io.PrintStream(data);
// These classes are part of Xerces. But you will find them in your JDK,
// as well, in a different package. Use any encoding here:
org.apache.xml.serialize.OutputFormat of =
new org.apache.xml.serialize.OutputFormat("XML", "ISO-8859-1", true);
org.apache.xml.serialize.XMLSerializer serializer =
new org.apache.xml.serialize.XMLSerializer(ps, of);
// Here, serialize the element that you obtained using your XPath expression.
serializer.asDOMSerializer();
serializer.serialize(element);
// The output stream now holds serialized XML data, including tags/attributes...
return data.toString();
UPDATE
This would be more concise, rather than using Xerces internals. It's the same as Dimitre's solution, just not with an XSLT stylesheet but all in Java:
ByteArrayOutputStream out = new ByteArrayOutputStream();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
Source source = new DOMSource(element);
Result target = new StreamResult(out);
transformer.transform(source, target);
return out.toString();

Changing node name of xml-node with Java

I have following scenario: I have a XML-Document, e.g. like this
<someRootElement>
<tag1>
<tag2
someKey=someValue
someKey2=someValue2
/>
<tag3/>
<tag4
newKey=newValue
newKey2=newValue2
/>
</tag1>
</someRootElement>
Now I want the parent tag1 to be called reallyCoolTag without losing the childnodes.
I tried the following, but it unfortunately doesn't work as I wish it would (but I do know why, b/c it is missing something, I guess):
// the new element:
Element neu = doc.createElement( newValue );
// append it to the root:
root.appendChild( neu );
// get all the child nodes:
NamedNodeMap nnm = nodes.item(i).getAttributes();
for( int dg = 0; dg < nnm.getLength(); dg++ ){
neu.setAttribute( nnm.item( dg ).getNodeName(),
nnm.item( dg ).getNodeValue() );
}
//---------------------------------------------------------
// HERE I GUESS I AM MISSING THE PART WHERE THE CHILD NODES
// ARE BEING APPENDED TO THE NEW NODE?????
//---------------------------------------------------------
// nodes.item(i) := the old value (nodes := is a NodeList
root.replaceChild( neu, nodes.item(i));
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource( doc );
StreamResult result = new StreamResult( xml );
transformer.transform( source, result );
nodes.item( i ).getParentNode().removeChild( nodes.item(i) );
Now this does work to a certain extend, as I mentioned, I guess I am missing the part where the child nodes are being appened, but what I actually wanted to know is, whether there is a really short way to rename the parent node without having to copy everything and replace the whole thing?
Thnx in advance!!!
Using Document.renameNode:
NodeList nodes = document.getElementsByTagName("tag1");
for (Node eachNode: nodes) {
document.renameNode(eachNode, null, "reallyCoolTag");
}
You could use an XSL Transformation (XSLT) for this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="*"> <!-- match anything -->
<xsl:copy>
<xsl:copy-of select="#*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="tag1"> <!-- switch the element name -->
<xsl:element name="reallyCoolTag">
<xsl:copy-of select="#*" />
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This can be used with the javax.xml.transform package (Java 1.4 and above):
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer(new StreamSource(
new File("RenameTag.xslt")));
transformer
.transform(new DOMSource(document), new StreamResult(System.out));
See DOMResult if you want a Document as the output.
Your tag1 is invalid. It doesn't have closing >. Also the attributes should be quoted. It should look like this,
<someRootElement>
<tag1>
<tag2
someKey="someValue"
someKey2="someValue2"
/>
<tag3/>
<tag4
newKey="newValue"
newKey2="newValue2"
/>
</tag1>
</someRootElement>
Try with the corrected XML. It should work.
Just call setName("reallyCoolTag") on the element(s) you want to rename. There is no need to copy the children around; the name attribute of an element is a mutable field.
As you did get the attributes:
NamedNodeMap nnm = nodes.item(i).getAttributes();
and you added these attributes to the new element,
You should get the children of nodes.item(i) and set them in the new node.
You can use for ex.:
neu.addContent(nodes.item(i).getChildren());

Categories

Resources