Im trying to use the ReplaceChild function. the code works, and no exceptions are thrown, but when I print XML to the screen it seems as if the function didnt work. the original node is the but not the new one.
private void convertClubComp(XmlDocument doc)
{
XmlNode sessionNode = doc.SelectSingleNode("Session");
XmlNode clubsNode = doc.CreateNode(XmlNodeType.Element, "Clubs", "");
XmlNode playerNode = sessionNode.SelectSingleNode("Players").SelectSingleNode("Player");
XmlNode groupNode = sessionNode.SelectSingleNode("Players").SelectSingleNode("Player").SelectSingleNode("Groups");
Console.WriteLine(playerNode.Name);
clubsNode = doc.ImportNode(groupNode, true);
playerNode.ReplaceChild(clubsNode, sessionNode.SelectSingleNode("Players").SelectSingleNode("Player").SelectSingleNode("Groups"));
Console.WriteLine(clubsNode.FirstChild.FirstChild.Name);
Console.WriteLine("!"+playerNode.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.Name);
}
Thanks
Ok, what's happening is when you do the ImportNode() it is replacing your reference to the new node you created with a clone of the other node. I think what you're looking for is something along the lines of this:
private void convertClubComp(XmlDocument doc)
{
XmlNode sessionNode = doc.SelectSingleNode("Session");
XmlNode playerNode = sessionNode.SelectSingleNode("Players").SelectSingleNode("Player");
XmlNode groupNode = playerNode.SelectSingleNode("Groups");
Console.WriteLine(playerNode.Name);
XmlNode clubsNode = doc.CreateElement("Clubs", "");
foreach (XmlNode child in groupNode.ChildNodes)
{
clubsNode.AppendChild(child.CloneNode(true));
}
foreach (XmlAttribute attribute in groupNode.Attributes)
{
clubsNode.Attributes.Append((attribute.Clone() as XmlAttribute));
}
playerNode.ReplaceChild(clubsNode, groupNode);
Console.WriteLine(clubsNode.FirstChild.FirstChild.Name);
Console.WriteLine("!" + playerNode.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.Name);
}
On a separate note, don't use SelectSingleNode() or SelectNodes() if you already have a reference. It's really poor practice and in larger systems can kill your performance.
Related
This code works but I want to understand why I don't have the pass the modified XmlDocument back to the caller - a code review I guess ;). I assume that these operations within XmlNode are using "by Ref" internally to operate on the document. I can see that working but I just want to make sure I understand this correctly. I have not found any documentation that addresses this specifically - probably because it is so obvious. So help me out here fellow devs. This is all happening by Ref and I don't have to worry about passing the modified XmlDocument back to the caller correct? Also, is this thread safe? I am using this code as part of a service app.
public void AddNewElement(XmlDocument doc, string elementName)
{
XmlNode selectedNode = doc.SelectSingleNode("//" + elementName);
if (selectedNode == null)
{
var childNodes = doc.LastChild.LastChild.ChildNodes;
XmlNode appendNode = childNodes.Item(childNodes.Count - 1);
XmlNode newNode = appendNode.AppendChild(doc.CreateElement(elementName));
newNode.InnerText = str64;
}
}
I have created a program in C# which adds and deletes data in an XML file.
Adding new data works totally fine, however on deleting the data, data gets deleted but empty tags still remain in the xml file.
How do I remove them? please help
The code is as follows:
private void deleteall_Click(object sender, EventArgs e) // delete single record button
{
XmlDocument xdata = new XmlDocument();
XmlNode xnode = xdata.SelectSingleNode("Information/Database");
xdata.Load("C:\\Users\\son14344\\Documents\\Visual Studio 2010\\Projects\\project.xml");
XmlNodeList oNodeList;
oNodeList = xdata.SelectNodes("Information/Database");
string s;
s = Convert.ToString(textBox1.Text);
try
{
foreach (XmlElement Oelement in oNodeList)
{
if (Oelement.SelectSingleNode("Database_Name").InnerText == s)
{
//Oelement.ParentNode.RemoveChild(Oelement);
Oelement.RemoveAll();
}
xdata.Save("C:\\Users\\son14344\\Documents\\Visual Studio 2010\\Projects\\project.xml");
//}
}
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
}
Try
Oelement.ParentNode.RemoveChild(Oelement);
instead of
Oelement.RemoveAll();
You have to capture the node that meets your condition.
Inside your if condition
XmlNode node = Oelement.SelectSingleNode("Database_Name");
XmlNode parent = node.ParentNode;
// remove the child node
parent.RemoveChild(node);
I have an XML file that collects information with Button_Click, so it starts off empty.
XML Sample
<marina>
<dockone>
</dockone>
<docktwo>
</docktwo>
</marina>
When I submit information from a textbox, a new XmlNode is created called slipone, and another XmlNode called reg is nested within that.
XML Sample 2
<marina>
<dockone>
<slipone>
<reg>12345</reg>
<slipone>
</dockone>
<docktwo>
</docktwo>
</marina>
I have attempted to create an if/else statement that will add a new XmlNode called sliptwo, with reg still nested within it, if slipone already has text, like so:
<marina>
<dockone>
<slipone>
<reg>12345</reg>
<slipone>
<sliptwo>
<reg>67890</reg>
<sliptwo>
</dockone>
<docktwo>
</docktwo>
</marina>
However the closest I have gotten is another XMlnode is still created, however it labels itself as slipone, and I am not sure what I am doing wrong:
<marina>
<dockone>
<slipone>
<reg>12345</reg>
<slipone>
<slipone>
<reg>67890</reg>
<slipone>
</dockone>
<docktwo>
</docktwo>
</marina>
This is an example of what I have been playing around with. Ignore the operators as I have resorted to trial and error but still have gotten nowhere. Please help!
C# Example
XmlDocument XmlDocObj1 = new XmlDocument();
XmlDocObj1.Load(Server.MapPath("~/App_Data/SlipData.xml"));
XmlNode rootnode1 = XmlDocObj1.SelectSingleNode("marina/dockone");
XmlNode dockone = rootnode1.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "slipone", ""));
XmlNode docktwo = rootnode1.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "sliptwo", ""));
XmlNode dockthree = rootnode1.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "slipthree", ""));
if (regfinal.Text != dockone.InnerText)
{
dockone.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "Reg", "")).InnerText = regfinal.Text;
XmlDocObj1.Save(Server.MapPath("/App_Data/SlipData.xml"));
}
else if (regfinal.Text == dockone.InnerText)
{
docktwo.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "Reg", "")).InnerText = regfinal.Text;
XmlDocObj1.Save(Server.MapPath("/App_Data/SlipData.xml"));
}
Your logic isn't going to do what I think you are saying since the only time (regfinal.Text != dockone.InnerText) will evaluate to false is when you enter nothing in your text control.
I believe you might mean to say if dockone exists then create another node called docktwo. This will require you to change your logic.
Some very simple code to get you a bit farther down the path. Not intended to be perfect or solve all problems...
private void button1_Click(object sender, EventArgs e)
{
XmlDocument XmlDocObj1 = new XmlDocument();
XmlDocObj1.Load(AppDomain.CurrentDomain.BaseDirectory.ToString()+"test.xml");
XmlNode rootnode1 = XmlDocObj1.SelectSingleNode("marina/dockone");
XmlNode dockone = rootnode1.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "slipone", ""));
XmlNode docktwo = rootnode1.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "sliptwo", ""));
XmlNode dockthree = rootnode1.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "slipthree", ""));
//jsh: old logic
//if (textBox1.Text != dockone.InnerText)
//new logic to test whether we have already created the dockone node which should only occur once
//you already have the logic for selecting the dockone node above...now just test if you already have it.
//NOTE: you may actually want a switch statement given that you avhe dockone, docktwo, and dockthree or at least another
// if statement to see if docktwo has been created and thus creaste dockthree.
if (rootnode1 == null )
{
dockone.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "Reg", "")).InnerText = textBox1.Text;
XmlDocObj1.Save(AppDomain.CurrentDomain.BaseDirectory.ToString() + "test.xml");
}
//else if (textBox1.Text == dockone.InnerText) jsh: old logic
else
{
docktwo.AppendChild(XmlDocObj1.CreateNode(XmlNodeType.Element, "Reg", "")).InnerText = textBox1.Text;
XmlDocObj1.Save(AppDomain.CurrentDomain.BaseDirectory.ToString() + "test.xml");
}
}
I'm trying to update an existing XML file, but always when I update it adding new tags the xmlns="" attribute mysteriously appears in all tags and I didn't find a way to remove it.
private static void EditarXML(string path, List<SiteUrl> listaUrls, bool indice, string loc)
{
XmlDocument documentoXML = new XmlDocument();
documentoXML.Load(path);
XmlNode sitemap = documentoXML.CreateElement("sitemap");
XmlNode xloc = documentoXML.CreateElement("loc");
xloc.InnerText = loc;
sitemap.AppendChild(xloc);
XmlNode lastmod = documentoXML.CreateElement("lastmod");
lastmod.InnerText = DateTime.Now.ToShortDateString();
sitemap.AppendChild(lastmod);
documentoXML.DocumentElement.AppendChild(sitemap);
}
Any help or ideas would be appreciated.
This will happen with the parent node you are appending to has a namespace, but you don't specify it in the CreateElement() call.
To handle this, you can get the namespace from the DocumentElement, like this (my sample just creates the document in memory, but the principle is the same), and pass it to CreateElement().
if (x.DocumentElement != null) {
var xmlns = (x.DocumentElement.NamespaceURI);
var sitemap = x.CreateElement("sitemap", xmlns);
var xloc = x.CreateElement("loc", xmlns);
xloc.InnerText = "Hello";
sitemap.AppendChild(xloc);
var lastmod = x.CreateElement("lastmod", xmlns);
lastmod.InnerText = DateTime.Now.ToShortDateString();
sitemap.AppendChild(lastmod);
x.DocumentElement.AppendChild(sitemap);
}
Console.WriteLine(x.InnerXml);
Output
<test xmlns="jdphenix"><sitemap><loc>Hello</loc><lastmod>4/20/2015</lastmod></sitemap></test>
Note that if I did not pass the parent namespace to each CreateElement() call, the children of that call would have the blank xmlns.
// incorrect - appends xmlns=""
if (x.DocumentElement != null) {
var sitemap = x.CreateElement("sitemap");
var xloc = x.CreateElement("loc");
xloc.InnerText = "Hello";
sitemap.AppendChild(xloc);
var lastmod = x.CreateElement("lastmod");
lastmod.InnerText = DateTime.Now.ToShortDateString();
sitemap.AppendChild(lastmod);
x.DocumentElement.AppendChild(sitemap);
}
Console.WriteLine(x.InnerXml);
Output
<test xmlns="jdphenix"><sitemap xmlns=""><loc>Hello</loc><lastmod>4/20/2015</lastmod></sitemap></test>
Related reading: Why does .NET XML append an xlmns attribute to XmlElements I add to a document? Can I stop it?
How to prevent blank xmlns attributes in output from .NET's XmlDocument?
I'm having a little problem formatting my xml file using C# code in a Windows Form app. Here is the code i'm using for this project:
private void btnSend_Click(object sender, EventArgs e)
{
string _name = tbName.ToString();
string _st = tbSt.ToString();
string _dx = tbDx.ToString();
string _iq = tbIq.ToString();
string _filename = #"c:\Add.xml";
if (File.Exists(_filename))
{
XDocument xDoc = XDocument.Load(_filename);
xDoc.Root.Add(new XElement("character",
new XElement("name", _name),
new XElement("st", _st),
new XElement("dx", _dx),
new XElement("iq", _iq)
));
xDoc.Save(_filename);
}
else if (!File.Exists(_filename))
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode productsNode = doc.CreateElement("characters");
doc.AppendChild(productsNode);
XmlNode productNode = doc.CreateElement("character");
productsNode.AppendChild(productNode);
XmlNode nmNode = doc.CreateElement("name");
nmNode.AppendChild(doc.CreateTextNode(_name));
productNode.AppendChild(nmNode);
XmlNode stNode = doc.CreateElement("st");
stNode.AppendChild(doc.CreateTextNode(_st));
productNode.AppendChild(stNode);
XmlNode dxNode = doc.CreateElement("dx");
dxNode.AppendChild(doc.CreateTextNode(_dx));
productNode.AppendChild(dxNode);
XmlNode iqNode = doc.CreateElement("iq");
iqNode.AppendChild(doc.CreateTextNode(_iq));
productNode.AppendChild(iqNode);
doc.Save(#"c:\Add.xml");//must have to save
}
}
The problem is that my .xml file comes out with the whole TextBox class prefix attached such as this:
...
- <character>
<name>System.Windows.Forms.TextBox, Text: bob</name>
<st>System.Windows.Forms.TextBox, Text: 10</st>
<dx>System.Windows.Forms.TextBox, Text: 12</dx>
<iq>System.Windows.Forms.TextBox, Text: 08</iq>
</character>
I'd like to have it look like this:
- <character>
<name>bob</name>
<st>10</st>
<dx>12</dx>
<iq>08</iq>
</character>
If any of you fine knowledgeable folks could lend a hand (or point me a link) I'd appreciate it. I did comb through the Google but nothing turned up with this specific odd problem. Many thanks for any help you can offer.
The obvious I did not see. Thanks to those who may respond. Now that I post it, it is obvious.
Changing
string _name = tbName.ToString();
simply to
string _name = tbName.Text;
of course fixed the problem. Hope this may help someone else.