I would like to replace the existing elements inthe xml tag with the new ones.
Sample XML is as follows:
<Dr.Watson>
<Bugs>
<Bug Name="Bug.add --> AAAAAAAAAAAA">
<criteria>
<includeFilterSets>
<filterSet>
<filter>
<filterName>PRODUCT_NAME</filterName>
<operator>
<name>Equals</name>
</operator>
<value>Dr.Watson</value>
</filter>
</filterSet>
</includeFilterSets>
<grouping>
<groupBy>
<name>STATUS</name>
</groupBy>
</grouping>
<caseSensitive>false</caseSensitive>
<entityToSearch>
<name>BUG</name>
</entityToSearch>
</criteria>
</Bug>
</Bugs>
</Dr.Watson>
Code so far i have :
XmlDocument doc = new XmlDocument();
doc.LoadXml(FilePath_EXPRESS_API_InputFile);
XmlNodeList nodelist = doc.SelectNodes("/Dr.Watson/Bugs/Bug");
//create node and add value
//Console.WriteLine(mxpwr.Value);
XmlNode node = doc.CreateNode(XmlNodeType.Element, "grouping", null);
XmlNode node11 = doc.CreateNode(XmlNodeType.Element, "groupBy", null);
XmlNode node12 = doc.CreateNode(XmlNodeType.Element, "name", null);
//Create Title Node
XmlNode Test_11 = doc.CreateElement("grouping");
XmlNode Test_22 = doc.CreateElement("groupBy");
XmlNode Test_44 = doc.CreateElement("name");
//add value for it
Test_11.InnerText = ("");
Test_22.InnerText = ("");
Test_44.InnerText = ("");
//create Url node
//XmlNode Test_445 = doc.CreateElement("sai");
Test_44.InnerText = ("STATE");
//add to parent node
Test_11.AppendChild(Test_22);
Test_22.AppendChild(Test_44);
//add to elements collection
doc.DocumentElement.AppendChild(Test_11);
Test_11.AppendChild(Test_22);
Test_22.AppendChild(Test_44);
Please suggest and help me as i am new to c# for xml scenarios.Thanks.Also, please note that i dont want to save these edits and want to use the edited xml runtime for the execution of APIs.
To replace a node via the XML-DOM API (XmlDocument et al):
Get an instance of XmlNode (or a subclass), parent, representing the parent element of the node you want to replace.
Use parent.RemoveChild to remove the old node.
Use parent.AppendChild to add the new node.
(As an alternative to #3 use parent.InsertAfter or parent.InsertBefore and a reference to another child to place the new node amongst other existing children.)
You code in the question appears to be constructing a new XML document from scratch: why would you want to replace a nodeājust create the right one first time. To modify an existing XML document use one of the static XmlDocument.Load methods to load and parse the existing document, use the various search and navigation methods to get the reference in #1 above, then apply the above steps, and finally save as normal.
Related
I'm trying to make a copy of a XML node and all their child nodes but different XML parent node name, but is throwing me an error, this is the xml file:
<Servers>
<MyServer>
<Host>0.0.0.0</Host>
<Port>12</Port>
<User>USER</User>
</MyServer>
</Servers>
What I'm trying to do is a copy of MyServer with all their child nodes and values but different name... something like this
<Servers>
<MyServer>
<Host>0.0.0.0</Host>
<Port>12</Port>
<User>USER</User>
</MyServer>
<MyCopyofMyServer>
<Host>0.0.0.0</Host>
<Port>12</Port>
<User>USER</User>
</MyCopyofMyServer>
</Servers>
What I did was this:
public void CopyInterface(string NewServer, string ServerToCopy)
{
xmldoc.Load(XMLInterfacesFile);
XmlNode NodeToCopy = xmldoc.SelectSingleNode("Servers/" + ServerToCopy);
XmlNode deep = NodeToCopy.CloneNode(true);
deep.InnerXml = deep.InnerXml.Replace(ServerToCopy, NewServer);
xmldoc.AppendChild(deep); //Throwing an exception here!
xmldoc.Save(XMLInterfacesFile);
}
Exception: This document already has a 'DocumentElement' node.
Any Idea?
The line
xmldoc.AppendChild(deep);
tries to append an element to an XmlDocument. This means that it is trying to add a root level element. The issue is that your document already has root level element (Servers) and it cannot add another one, so you get an exception.
Another issue with your code is that in line
deep.InnerXml = deep.InnerXml.Replace(ServerToCopy, NewServer);
you are attempting to replace the name of the server with the new name. Unfortunatelly InnerXml looks like this:
<Host>0.0.0.0</Host>
<Port>12</Port>
<User>USER</User>
so your server name is never replaced.
To fix the issues you can try different approach:
// Fint the node you want to replace
XmlNode NodeToCopy = xmldoc.SelectSingleNode("Servers/" + ServerToCopy);
// Create a new node with the name of your new server
XmlNode newNode = xmldoc.CreateElement(NewServer);
// set the inner xml of a new node to inner xml of original node
newNode.InnerXml = NodeToCopy.InnerXml;
// append new node to DocumentElement, not XmlDocument
xmldoc.DocumentElement.AppendChild(newNode);
This should give you the result you need
I wanted to add a xmlNode in a parent but at the top/beginning. Is there a variant of XMLNode.AppendChild() that i can use?
As far as I understand your question you are probably looking for the XmlNode.PrependChild() method.
Example:
XmlDocument doc = new XmlDocument();
XmlNode root = doc.DocumentElement;
//Create a new node.
XmlElement node = doc.CreateElement("price");
//Add the node to the document.
root.PrependChild(node);
MSDN documentation
I believe the question is asking how to add a node to the beginning of the XML file. I did that in the following manner:
// This is the main xml document
XmlDocument document = new XmlDocument();
// This part is creation of RootNode, however you want
XmlNode RootNode = document.CreateElement("Comments");
document.AppendChild(RootNode);
//Adding first child node as usual
XmlNode CommentNode1 = document.CreateElement("UserComment");
RootNode.AppendChild(commentNode1);
//Now create a child node and add it to the beginning of the XML file
XmlNode CommentNode2 = document.CreateElement("UserComment");
RootNode.InsertBefore(commentNode2, RootNode.FirstChild);
I have the following XML
<ROOT>
<FSM338_Container>
<FSM338_Details>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<CASHBREAK>199</CASHBREAK>
<CASHLUNCH>199</CASHLUNCH>
</FSM338_Details>
<FSM338_Details>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<CASHBREAK>199</CASHBREAK>
<CASHLUNCH>199</CASHLUNCH>
</FSM338_Details>
</FSM338_Container>
<BillingReport>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<gaindacd>1</gaindacd>
<docnum>07000F</docnum>
</BillingReport>
<DataElements>
<unitid>12345</unitid>
<fbocost>0.00</fbo>
</DataElements>
</ROOT>
I need to load the xml doc and add in several elements whenever I find the element named "Uic" . In short if I find "Uic" add in the element <someElement>my stuff here</someElement> at the same level as UIC at all locations.
I'Ve used
XmlDocument xDoc = new XmlDocument();
xDoc.Load(#"path_to_xml.xml");
list = xDoc.GetElementsByTagName("Uic");
I used insertBefore to add in my element but I can get it to copy to only the first element
You can use SelectNodes() method of XmlNode which accepts xpath expression.
XmlNodeList nodes = xDoc.DocumentElement.SelectNodes("Uic");
foreach(XmlNode node in nodes) {
XmlElement element = xDoc.CreateElement("SomeElement");
element.InnerText = "anything";
node.ParentNode.AppendChild(element);
}
I have this code below. I want to add a new node in it to hold more user records and if I want I can remove them. Can anyone help me?
string filename = "text.xml";
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("Login");
XmlElement id = doc.CreateElement("passWord");
root.SetAttribute("userName", nameTxb.Text);
id.SetAttribute("passWord", passwordTxb.Text);
XmlElement name = doc.CreateElement("UserName");
XmlElement passd = doc.CreateElement("PassWord");
name.InnerText = nameTxb.Text;
passd.InnerText = passwordTxb.Text;
root.AppendChild(name);
root.AppendChild(passd);
doc.AppendChild(root);
doc.Save(filename);
MessageBox.Show("Created SuccesFully!");
this.Close();
Your XML document is stored in variable doc. You may use doc.SelectNodes() to select specified nodes using XPATH. You may also iterate over selected nodes and append childs, remove childs etc.
var nodes = doc.SelectNodes("xpath");
foreach(XmlNode node in nodes)
{
//
}
This will remove an element. You can keep using SelectSingleNode() to move down through the branches of the xml. element can also be selected that way - for this example, just consider it an arbitrary starting point.
someElement.RemoveChild(oDoc.SelectSingleNode("Parent").SelectSingleNode("Child"));
As far as I know, you can also use the same method at the XmlDocument level too.
Hope this helps.
I'm currently working with an XML request, and am trying to create a Reply Document that has multiple child nodes of the same name in the call, so what I'm trying to return is:
<Reply Document>
<ConfirmationItem name = "One">
<ItemDetail />
</ConfirmationItem>
<ConfirmationItem name = "Two">
<ItemDetail />
</ConfirmationItem>
...
<ConfirmationItem name = "Twenty">
<ItemDetail />
</ConfirmationItem>
</Reply Document>
I did a bit of research and found this thread: XmlReader AppendChild is not appending same child value in which the accepted answer was that the OP had to create new Elements to be able to append to the end instead of overwrite the first.
My original code is below, it creates the XmlNode from the incoming Request and appends the result to the XmlDocument itself:
//p_transdoc is the XmlDocument that holds all the items to process.
XmlNodeList nodelst_cnfrm = p_transdoc.SelectNodes("//OrderRequest");
foreach (XmlNode node in nodelst_cnfrm)
{
//this is just an XML Object
XmlNode node_cnfrm_itm = this.CreateElement("ConfirmationItem");
node_cnfrm_itm.Attributes.Append(this.CreateAttribute("name")).InnerText = p_transdoc.Attributes["name"].InnerText;
XmlNode node_itmdtl = this.CreateElement("ItemDetail");
node_cnfrm_itm.AppendChild(node_itmdtl);
//xml_doc is the return XML request
xml_doc.AppendChild(node_cnfrm_itm);
}
So after reading that thread and the answer, I tried to change the code to use a new XmlElement each pass through.
//p_transdoc is the XmlDocument that holds all the items to process.
XmlNodeList nodelst_cnfrm = p_transdoc.SelectNodes("//OrderRequest");
foreach (XmlNode node in nodelst_cnfrm)
{
XmlElement node_cnfrm_itm = new XmlElement();
node_cnfrm_itm = this.CreateElement("ConfirmationItem");
node_cnfrm_itm.Attributes.Append(this.CreateAttribute("name")).InnerText = p_transdoc.Attributes["name"].InnerText;
XmlElement node_itmdtl = new XmlElement();
node_itmdtl = this.CreateElement("ItemDetail");
node_cnfrm_itm.AppendChild(node_itmdtl);
//xml_doc is the return XML request
xml_doc.AppendChild(node_cnfrm_itm);
}
But not only does that not work, it returns a server error. So I've come to you for help. Right now this code is just returning one ConfirmationItem. How would I be able to append the ConfirmationItem to the end of the Document instead of overwrite it, to be able to return as many as were sent in?
(I should point out that this code has been heavily formatted for ease of readability, simplicity, and to reduce clutter. Any typographical errors are purely because of the Asker's internal failure at effective proofreading).
Assuming xml_doc is the xml with the ConfirmationItems you need to create the XmlElements with the new XmlDocument. XmlDocument.CreateElement. Hence I use the Linq extension method OfType<>() here to only return the XmlNode objects of the type XmlElement.
// dummy data
XmlDocument p_transdoc = new XmlDocument();
p_transdoc.LoadXml(#"
<root name='rootAttribute'>
<OrderRequest name='one' />
<OrderRequest name='two' />
<OrderRequest name='three' />
</root>
");
XmlDocument xml_doc = new XmlDocument();
xml_doc.LoadXml("<ReplyDocument />");
foreach (var node in p_transdoc.SelectNodes("//OrderRequest").OfType<XmlElement>())
{
XmlElement node_cnfrm_itm = xml_doc.CreateElement("ConfirmationItem");
node_cnfrm_itm = xml_doc.DocumentElement.AppendChild(node_cnfrm_itm) as XmlElement;
node_cnfrm_itm.SetAttribute("name", node.GetAttribute("name"));
XmlElement node_itmdtl = xml_doc.CreateElement("ItemDetail");
node_itmdtl = node_cnfrm_itm.AppendChild(node_itmdtl) as XmlElement;
}
The method CreateElement returns an XmlElement so you can use the methods SetAttribute and GetAttribute.
The code: p_transdoc.Attributes["name"].InnerText doesn't seem right. If you want to get the attributes for the root element of the document you need to type: p_transdoc.DocumentElement.GetAttribute("name")
IMO this is MUCH easier if you're using Linq to XML.
In Linq to XML this would be similar to (some variables have different names):
// dummy data
var transDoc = XDocument.Parse(#"
<root name='rootAttribute'>
<OrderRequest name='one' />
<OrderRequest name='two' />
<OrderRequest name='three' />
</root>");
var xmlDoc = XDocument.Parse("<ReplyDocument />");
xmlDoc.Root.Add(
transDoc.Root.Elements("OrderRequest").Select(o =>
new XElement("ConfirmationElement",
new XAttribute("name", (string)o.Attribute("name")),
new XElement("ItemDetail"))));
Both examples output:
<ReplyDocument>
<ConfirmationElement name="one">
<ItemDetail />
</ConfirmationElement>
<ConfirmationElement name="two">
<ItemDetail />
</ConfirmationElement>
<ConfirmationElement name="three">
<ItemDetail />
</ConfirmationElement>
</ReplyDocument>