I have an XML:
<?xml version="1.0" encoding="UTF-8"?>
<songs>
<song>
<title>Gracious</title>
<artist>Ben Howard</artist>
<genre>Singer/Songwriter</genre>
</song>
<song>
<title>Only Love</title>
<artist>Ben Howard</artist>
<genre>Singer/Songwriter</genre>
</song>
<song>
<title>Bad Blood</title>
<artist>Bastille</artist>
<genre>N/A</genre>
</song>
<song>
<title>Keep Your Head Up</title>
<artist>Ben Howard</artist>
<genre>Singer/Songwriter</genre>
</song>
<song>
<title>Intro</title>
<artist>Alt-J</artist>
<genre>Alternative</genre>
</song>
</songs>
and my Java code is:
public static void deleteSong(Song song) {
String songTitle = song.getTitle();
String songArtist = song.getArtist();
String songGenre = song.getGenre();
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
File file = new File("songs.xml");
Document doc = db.parse(file);
NodeList songList = doc.getElementsByTagName("song");
if (songList != null && songList.getLength() > 0) {
for (int i = 0; i < songList.getLength(); i++) {
Node node = songList.item(i);
Element e = (Element) node;
NodeList nodeList = e.getElementsByTagName("title");
String title = nodeList.item(0).getChildNodes().item(0)
.getNodeValue();
nodeList = e.getElementsByTagName("artist");
String artist = nodeList.item(0).getChildNodes().item(0)
.getNodeValue();
nodeList = e.getElementsByTagName("genre");
String genre = nodeList.item(0).getChildNodes().item(0)
.getNodeValue();
System.out.println(title + " Title");
System.out.println(songTitle + " SongTitle");
if (title.equals(songTitle)) {
if (artist.equals(songArtist)) {
if (genre.equals(songGenre)) {
doc.getFirstChild().removeChild(node);
}
}
}
}
}
MainDisplay.main(null);
} catch (Exception e) {
System.out.println(e);
}
}
The song to be deleted is passed into the method and then compared to the songs in the xml file. However, if the song matches a song in the xml, it isn't deleted? No exceptions come up.
You need to remove relevant node, in you code you are removing node of firstchild which seems to be incorrect.
And write back your changes to the file.
if (title.equals(songTitle) && artist.equals(songArtist) && genre.equals(songGenre) ) {
node.getParentNode().removeChild(node);
}
// write back to xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filepath));
transformer.transform(source, result);
From what I see, you are only reading the documents. At some point, you will have to flush the changes back to the XML file.
Related
I have a xml with following scheme structure
<test>
<testcase classname="TestsQuarantine.CreateUsers" name="Administrator"/>
<testcase classname="TestsQuarantine.Login" name="documentMailQuarantine"/>
<testcase classname="TestsClerk.CreateUsers" name="John"/>
</test>
I need to reorganize it to
<test>
<testsuite name="Quarantine">
<testcase classname="TestsQuarantine.CreateUsers" name="Administrator"/>
<testcase classname="TestsQuarantine.Login" name="documentMailQuarantine"/>
</testsuite>
<testsuite name="Clerk">
<testcase classname="TestsClerk.CreateUsers" name="John"/>
</testsuite>
</test>
At this point I'm reading the file to NodeList, iterate through it, create new root and try to switch it with original to achieve the structure that I need but I get following error
HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it
is not permitted.
happening in line that performs switch of roots and I'm out of ideas why it is so.. Here is my code:
File file = new File(fullPath);
List<Element> clerk = null,
quara = null,
misc = null;
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(file);
NodeList nodes = doc.getElementsByTagName("test");
Element root = doc.getDocumentElement(),
newRoot = doc.createElement("test");
clerk = new ArrayList<Element>();
quara = new ArrayList<Element>();
misc = new ArrayList<Element>();
for(int i=0; i < nodes.getLength(); i++) {
Element node = (Element) nodes.item(i);
if(node.getAttribute("classname").contains("Clerk")) {
clerk.add(node);
} else if(node.getAttribute("classname").contains("Quarantine")) {
quara.add(node);
} else {
misc.add(node);
}
}
if(clerk.isEmpty() == false) {
Element clerkSuite = doc.createElement("testsuite");
clerkSuite.setAttribute("name", "Clerk");
for(Element el : clerk) {
clerkSuite.appendChild(el);
}
newRoot.appendChild(clerkSuite);
}
if(quara.isEmpty() == false) {
Element quaraSuite = doc.createElement("testsuite");
quaraSuite.setAttribute("name", "Quarantine");
for(Element el : quara) {
quaraSuite.appendChild(el);
}
newRoot.appendChild(quaraSuite);
}
if(misc.isEmpty() == false) {
Element miscSuite = doc.createElement("testsuite");
miscSuite.setAttribute("name", "Miscellaneous");
for(Element el : misc) {
miscSuite.appendChild(el);
}
newRoot.appendChild(miscSuite);
}
root.getParentNode().replaceChild(newRoot, root);
DOMSource original = new DOMSource(doc);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
StreamResult overritten = new StreamResult(fullPath);
transformer.transform(original, overritten);
} catch (Exception e) {
e.printStackTrace();
}
What do I have to change to make it work?
Your iteration over testcase nodes is incorrect. I changed that fragment to below one and Your code is working:
Node testNode = doc.getDocumentElement();
NodeList testCases= testNode.getChildNodes();
for(int i=0; i < testCases.getLength(); i++) {
Node n = testCases.item(i);
if (!(n instanceof Text)) {
Element testCase = (Element) n;
if (testCase.getAttribute("classname").contains("Clerk")) {
clerk.add(testCase);
} else if (testCase.getAttribute("classname").contains("Quarantine")) {
quara.add(testCase);
} else {
misc.add(testCase);
}
}
}
I have a document data.xml you can find below. The writeXML function is use for set node value.
I try to use targetNode.setTextContent(strValue), strValue = "400.00" to update node P2, but I only got null in my xml, the node P2 always null, never update by .setTextContent().
My selenium version is 2.40.0
public void writeXML(String strTestName, String strTargetNode, String strValue) throws Exception{
report= new ReportGen();
//get data.xml path
String path = System.getProperty("user.dir") + "\\data.xml";
Document document = load(path);
//get root node
Element root = document.getDocumentElement();
// System.out.println("The root node is:"+root.getTagName());
NodeList nl = root.getChildNodes();
NodeList cnl = null;
org.w3c.dom.Node targetNode = null;
String logStr = null;
String strNodeName = null;
int length = nl.getLength();
try{
for(int i=0; i<length;i++){
targetNode = nl.item(i);
if(targetNode!=null && targetNode instanceof Element && targetNode.getNodeName().equals(strTestName)){
if(targetNode.hasChildNodes()){
cnl = targetNode.getChildNodes();
break;
}else{
assert false;
}
}
}
length = cnl.getLength();
for(int i=0; i<length;i++){
targetNode = cnl.item(i);
strNodeName =targetNode.getNodeName();
if(targetNode!=null&&strNodeName.equals(strTargetNode)){
targetNode.setTextContent(strValue);
break;
}
}
}catch(Exception exception){
logStr=exception.getMessage();
assert false;
}
}
Below is my data.xml
<SF>
<TC03>
<KAM></KAM>
<PartnerName></PartnerName>
<Product></Product>
<P2></P2>
<P4></P4>
<P5></P5>
</TC03>
</SF>
coluld anyone give any suggestion?
You have to save file back, once you have changed node values with setTextContent
add something like this at the end of your code
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(document);
OutputStream stream = new FileOutputStream(fXmlFile);
StreamResult sresult = new StreamResult(stream);
transformer.transform(source, sresult);
class HtmlTagmodifier {
public String htmlFileWriter(String cfile, String Listname, String Nodename, String nodevalue) {
try {
File fhtmlFile = new File(cfile);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fhtmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName(Listname);
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
eElement.getElementsByTagName(Nodename).item(0).setTextContent(nodevalue);
}
}
Source source = new DOMSource(doc);
Result htmlresult = new StreamResult(fhtmlFile);
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(source, htmlresult);
result2 = "Success";
} catch (Exception e) {
e.printStackTrace();
log.error("Error in html file writing " + e.toString());
JOptionPane.showMessageDialog(null, "Error in html file writing " + e.toString());
result2 = "Failed";
}
return result2;
}
public static void main(String[] args) {
HtmlTagmodifier.htmlfilewriter("test.html", "details", "customername", "customernamexxxxxx");
}
}
Output:
when i use this method to modify the tag values of html,tag name is changed successfully but meta data tag is added again in the html
please give me suggestion.
I have an XML file and I need to delete a specific node. The node to be deleted will be defined dynamically based on the logic. I have been searching in internet for a solution but couldn't delete my node still. am getting error - NOT_FOUND_ERR: An attempt is made to reference a node in a context where it does not exist
Below is a sample XML File. I need to delete the node <NameValuePairs> which has <name>Local Variables</name>. Below is my sample XML Files Java Code
Sample XML File
<?xml version="1.0" encoding="UTF-8"?>
<DeploymentDescriptors xmlns="http://www.tibco.com/xmlns/dd">
<name>Test</name>
<version>1</version>
<DeploymentDescriptorFactory>
<name>RepoInstance</name>
</DeploymentDescriptorFactory>
<DeploymentDescriptorFactory>
<name>NameValuePairs</name>
</DeploymentDescriptorFactory>
<NameValuePairs>
<name>Global Variables</name>
<NameValuePair>
<name>Connections1</name>
<value>7222</value>
<requiresConfiguration>true</requiresConfiguration>
</NameValuePair>
<NameValuePair>
<name>Connections2</name>
<value>7222</value>
<requiresConfiguration>true</requiresConfiguration>
</NameValuePair>
</NameValuePairs>
<NameValuePairs>
<name>Local Variables</name>
<NameValuePair>
<name>Connections3</name>
<value>8222</value>
<requiresConfiguration>true</requiresConfiguration>
</NameValuePair>
<NameValuePair>
<name>Connections3</name>
<value>8222</value>
<requiresConfiguration>true</requiresConfiguration>
</NameValuePair>
</NameValuePairs>
</DeploymentDescriptors>
Java Code
File fDestFile = new File("myfile.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document oDoc3 = dBuilder.parse(fDestFile);
NodeList oDestFlowList = oDoc3.getElementsByTagName("NameValuePairs");
for (int m = 0; m < oDestFlowList.getLength(); m++) {
NodeList oDestchildList = oDestFlowList.item(m).getChildNodes();
for (int n = 0; n < oDestchildList.getLength(); n++) {
Node oDestchildNode = oDestchildList.item(n);
if ("name".equals(oDestchildNode.getNodeName())) {
//oDestchildNode.getParentNode().removeChild(oDestchildNode); //Not Working
//oDoc3.getDocumentElement().removeChild(oDestchildNode); //Not Working
}
}
}
}
You need create a separate reference from the parent node as an Element so that you aren't referencing the node that you are removing:
File fDestFile = new File("src/myfile.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = null;
try {
dBuilder = dbFactory.newDocumentBuilder();
Document oDoc3 = null;
oDoc3 = dBuilder.parse(fDestFile);
NodeList oDestFlowList = oDoc3.getElementsByTagName("NameValuePairs");
// Loop through all 'NameValuePairs'
for (int m = oDestFlowList.getLength()-1; m >=0 ; m--) {
NodeList oDestchildList = oDestFlowList.item(m).getChildNodes();
// Loop through children of 'NameValuePairs'
for (int n = oDestchildList.getLength()-1; n >=0 ; n--) {
// Remove children if they are of the type 'name'
if(oDestchildList.item(n).getNodeName().equals("name")){
oDestFlowList.item(m).removeChild(oDestchildList.item(n));
// For debugging
System.out.println(oDestchildList.item(n).getNodeName());
}
}
}
Source source = new DOMSource(oDoc3);
Result result = new StreamResult(fDestFile);
Transformer transformer = null;
transformer = TransformerFactory.newInstance().newTransformer();
// Transform your XML document (i.e. save changes to file)
transformer.transform(source, result);
} catch (Exception e) {
// Catch the exception here
e.printStackTrace();
}
}
If you are still having issues, then I would think that it is an issue with the node types. This was working for me before I put the check in for 'oDestchildNode.getNodeType()' but I would look at what type of node you are returning and go from there.
Here is the final piece of code that finally worked
public static void main(String[] args) {
File fXmlSubFile = new File("Sub.xml");
File fXmlOriginalFile = new File("Original.xml");
File fDestFile = new File("myfile.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
FileChannel source = null;
FileChannel destination = null;
XPath xPath = XPathFactory.newInstance().newXPath();
try{
if (!fDestFile.exists()) {
fDestFile.createNewFile();
}
source = new FileInputStream(fXmlOriginalFile).getChannel();
destination = new FileOutputStream(fDestFile).getChannel();
if (destination != null && source != null) {
destination.transferFrom(source, 0, source.size());
}
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
dBuilder = dbFactory.newDocumentBuilder();
Document oSubDoc = dBuilder.parse(fXmlSubFile);
Document oDestDoc = dBuilder.parse(fDestFile);
oSubDoc.getDocumentElement().normalize();
oDestDoc.getDocumentElement().normalize();
String sDestExpression = "/DeploymentDescriptors/NameValuePairs";
String sSubExpression = "/NameValuePairs";
NodeList nodeDestList = (NodeList) xPath.compile(sDestExpression).evaluate(oDestDoc, XPathConstants.NODESET);
NodeList nodeSubList = (NodeList) xPath.compile(sSubExpression).evaluate(oSubDoc, XPathConstants.NODESET);
for (int i = nodeDestList.getLength()-1; i >=0 ; i--) {
Node oDestNode = nodeDestList.item(i);
if (oDestNode.getNodeType() == Node.ELEMENT_NODE) {
Element oDestElement = (Element) oDestNode;
for (int j =0; j<nodeSubList.getLength(); j++) {
Node oSubNode = nodeSubList.item(j);
if (oSubNode.getNodeType() == Node.ELEMENT_NODE) {
Element oSubElement = (Element) oSubNode;
if(oDestElement.getElementsByTagName("name").item(0).getTextContent().equals(oSubElement.getElementsByTagName("name").item(0).getTextContent())){
oDestNode.getParentNode().removeChild(oDestNode);
}
}
}
}
}
Source src = new DOMSource(oDestDoc);
Result result = new StreamResult(fDestFile);
Transformer transformer = null;
transformer = TransformerFactory.newInstance().newTransformer();
// Transform your XML document (i.e. save changes to file)
transformer.transform(src, result);
}catch(Exception ex){
System.out.println("error:"+ex.getMessage());
ex.printStackTrace();
}
}
I have xml documents that look like this:
<?xml version="1.0"?>
<root>
<success>true</success>
<note>
<note_id>32219</note_id>
<the_date>1336763490</the_date>
<member_id>108649</member_id>
<area>6</area>
<note>Note 123123123</note>
</note>
<note>
<note_id>33734</note_id>
<the_date>1339003652</the_date>
<member_id>108649</member_id>
<area>1</area>
<note>This is another note.</note>
</note>
<note>
<note_id>49617</note_id>
<the_date>1343050791</the_date>
<member_id>108649</member_id>
<area>1</area>
<note>this is a 3rd note.</note>
</note>
</root>
I would like to take that document, and get all of the <note> tags and convert them to a string, then pass them to my XML class and place the XML class into an array list. I hope that makes sense. So Here is the method that I am trying to use to get all of the <note> tags.
public ArrayList<XML> getNodes(String root, String name){
ArrayList<XML> elList = new ArrayList<>();
NodeList nodes = doc.getElementsByTagName(root);
for(int i = 0; i < nodes.getLength(); i++){
Element element = (Element)nodes.item(i);
NodeList nl = element.getElementsByTagName(name);
for(int c = 0; c < nl.getLength(); c++){
Element e = (Element)nl.item(c);
String xmlStr = this.nodeToString(e);
XML xml = new XML();
xml.parse(xmlStr);
elList.add(xml);
}
}
return elList;
}
private String nodeToString(Node node){
StringWriter sw = new StringWriter();
try{
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.transform(new DOMSource(node), new StreamResult(sw));
}catch(TransformerException te){
System.out.println("nodeToString Transformer Exception");
}
return sw.toString();
}
So, my question is, how can I get each <note> tag as a string? With the code I have now all I get back is null for String xmlStr = e.getNodeValue();.
Edit
I edited my main code, this seems to work.
Updated after clarification
You can find all the <note> elements using XPath.
This will allow you to isolate each node simply. You can then create a new document, based on the found nodes and transform it back to string
public class TestXML01 {
public static void main(String[] args) {
String xml = "<?xml version=\"1.0\"?>";
xml += "<root>";
xml += "<success>true</success>";
xml += "<note>";
xml += "<note_id>32219</note_id>";
xml += "<the_date>1336763490</the_date>";
xml += "<member_id>108649</member_id>";
xml += "<area>6</area>";
xml += "<note>Note 123123123</note>";
xml += "</note>";
xml += "<note>";
xml += "<note_id>33734</note_id>";
xml += "<the_date>1339003652</the_date>";
xml += "<member_id>108649</member_id>";
xml += "<area>1</area>";
xml += "<note>This is another note.</note>";
xml += "</note>";
xml += "<note>";
xml += "<note_id>49617</note_id>";
xml += "<the_date>1343050791</the_date>";
xml += "<member_id>108649</member_id>";
xml += "<area>1</area>";
xml += "<note>this is a 3rd note.</note>";
xml += "</note>";
xml += "</root>";
ByteArrayInputStream bais = null;
try {
bais = new ByteArrayInputStream(xml.getBytes());
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document xmlDoc = builder.parse(bais);
Node root = xmlDoc.getDocumentElement();
XPathFactory xFactory = XPathFactory.newInstance();
XPath xPath = xFactory.newXPath();
XPathExpression xExpress = xPath.compile("/root/note");
NodeList nodes = (NodeList) xExpress.evaluate(root, XPathConstants.NODESET);
System.out.println("Found " + nodes.getLength() + " note nodes");
for (int index = 0; index < nodes.getLength(); index++) {
Node node = nodes.item(index);
Document childDoc = builder.newDocument();
childDoc.adoptNode(node);
childDoc.appendChild(node);
System.out.println(toString(childDoc));
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
bais.close();
} catch (Exception e) {
}
}
}
public static String toString(Document doc) {
String sValue = null;
ByteArrayOutputStream baos = null;
OutputStreamWriter osw = null;
try {
baos = new ByteArrayOutputStream();
osw = new OutputStreamWriter(baos);
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.setOutputProperty(OutputKeys.METHOD, "xml");
tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
DOMSource domSource = new DOMSource(doc);
StreamResult sr = new StreamResult(osw);
tf.transform(domSource, sr);
osw.flush();
baos.flush();
sValue = new String(baos.toByteArray());
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
osw.close();
} catch (Exception exp) {
}
try {
baos.close();
} catch (Exception exp) {
}
}
return sValue;
}
}
This now outputs...
Found 3 note nodes
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<note>
<note_id>32219</note_id>
<the_date>1336763490</the_date>
<member_id>108649</member_id>
<area>6</area>
<note>Note 123123123</note>
</note>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<note>
<note_id>33734</note_id>
<the_date>1339003652</the_date>
<member_id>108649</member_id>
<area>1</area>
<note>This is another note.</note>
</note>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<note>
<note_id>49617</note_id>
<the_date>1343050791</the_date>
<member_id>108649</member_id>
<area>1</area>
<note>this is a 3rd note.</note>
</note>
Using XPath, the following code :
public class NotesExtractor {
public static List< String > getTextOf( Document doc, String tagName )
throws Exception
{
List< String > notes = new ArrayList<>();
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
NodeList xText =
(NodeList)xPath.evaluate(
"//" + tagName + "/text()", doc, XPathConstants.NODESET );
for( int i = 0; i < xText.getLength(); ++i ) {
Text textElt = (Text)xText.item( i );
String noteTxt = textElt.getTextContent().trim();
if( ! noteTxt.isEmpty())
{
notes.add( noteTxt.trim());
}
}
return notes;
}
public static void main( String[] args ) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringElementContentWhitespace( true );
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse( "Notes.xml" );
System.out.println( getTextOf( doc, "note" ));
}
outputs:
[Note 123123123, This is another note., this is a 3rd note.]