18

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!!!

wattostudios
  • 8,666
  • 13
  • 43
  • 57
doro
  • 785
  • 3
  • 11
  • 23

5 Answers5

38

Using Document.renameNode:

NodeList nodes = document.getElementsByTagName("tag1");
for (Node eachNode: nodes) {
  document.renameNode(eachNode, null, "reallyCoolTag");
}
Sudip Bhandari
  • 2,165
  • 1
  • 27
  • 26
McDowell
  • 107,573
  • 31
  • 204
  • 267
2

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.

McDowell
  • 107,573
  • 31
  • 204
  • 267
  • If you also need to run java code to run the style sheet, it may be better to use only java to solve the problem. In doing so, you limit the technologies involved, disk access and disk dependencies. You may prefer style sheets when there are several changes to make and they are more heterogeneous. I Suggest Using Document.renameNode – Jean-Philippe Mar 19 '19 at 18:30
0

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.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • I've tried that before, but it didn't work. Maybe I am doing it wrong? If the node I want to rename is 'nodes.item(i)' and the root-element is called root, how exactly am I doing that? I've tried: nodes.item(i).setName(newValue) ... but eclipse wants me to add a cast ... – doro Aug 19 '09 at 14:01
  • It does work; it just doesn't change the file on disk. You need to save the document in RAM somewhere to see the effect. – Aaron Digulla Aug 19 '09 at 14:33
  • see above, eclipse wants me to add a cast ... I guess, the method is not supposed to work that way ... and as you can see above I am saving the changes I want to make :( – doro Aug 20 '09 at 06:36
  • Sorry, I didn't mean the root element but the element(s) you want renamed. There is really no need to copy the children. Just search for the elements you want renamed and call setName() on them. – Aaron Digulla Aug 20 '09 at 07:50
0

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());
Grzegorz Rożniecki
  • 27,415
  • 11
  • 90
  • 112
Moro
  • 2,088
  • 6
  • 25
  • 34
  • Maybe I should get a new eclipse or it really doesn't know 'addContent' :( – doro Aug 19 '09 at 14:06
  • sorry, I was using JDOM. By org.w3c: you can use nodes.item(i).getChildNodes(); //return list of child then loop on them using appendChild(Element); //to append each child – Moro Aug 19 '09 at 14:30
0

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.

ZZ Coder
  • 74,484
  • 29
  • 137
  • 169
  • aside from that the suggested methods did not work ... I had to loop through the children of the node and add em ... but you are right, it isn't valid the way I put it. – doro Aug 19 '09 at 14:52