Merge nodes of the same kind to a single node - c#

I'm trying to merge 2 Nodes of the same kind into a single Node
So by having both Nodes like this
<Clubs>
<SPE>Accepted</Community>
<SCU>Accepted</SCU>
</Clubs>
and this
<Clubs>
<BUS>Declined</BUS>
</Clubs>
it will become like this
<Clubs>
<SPE>Accepted</SPE>
<SCU>Accepted</SCU>
<BUS>Declined</BUS>
</Clubs>
How could i achieve such thing?

This might help you
XmlDocument myDocument = new XmlDocument();
myDocument.Load(XMLFile);
var NodeToadd = myDocument.ChildNodes.OfType<XmlElement>().Where(nodeVariant => nodeVariant.Name == "Clubs").SelectMany(o => o.ChildNodes.OfType<XmlElement>()).ToList();
var nodeToDelete = myDocument.ChildNodes.OfType<XmlElement>().Where(nodeVariant => nodeVariant.Name == "Clubs");
foreach (var m in nodeToDelete)
{
myDocument.RemoveChild(m);
}
XmlNode newNode = myDocument.CreateElement("Clubs");
foreach(var m in NodeToadd)
{
newNode.AppendChild(m);
}
myDocument.AppendChild(newNode);
myDocument.Save(XMLFile);

Related

How to check if an XML node exists in the children of another node?

I want to add an XmlNode to another XmlNode if it doesn't contain this node (the comparison should be based on the node name and its contents)
System.Xml.XmlDocument doc;
...
XmlNode newNode = doc.CreateElement(name);
newNode.InnerXml = something
XmlNode parentNode = doc.GetElementsByTagName(parentName);
if (parentNode.???? (newNode))
{
parentNode.AppendChild(newNode);
}
How can I check this existence? parentNode.ChildNodes doesn't have a Contain method.
I think this will do the trick:
private void doSomething()
{
XmlDocument doc = new XmlDocument();
XmlNode newNode = doc.CreateElement("name");
newNode.InnerXml = "something";
XmlNode parentNode = doc.GetElementsByTagName("parentName")[0];
// I just stuck an index on end of above line...
// Note that GetElementsByTagName returns an XmlNodeList
int huh = 0;
foreach (XmlNode n in parentNode.ChildNodes)
{
// If I understood you correctly, you want these checks?
if (n.InnerXml == newNode.InnerXml && n.Name == newNode.Name) huh++;
}
if (huh == 0) parentNode.AppendChild(newNode);
}
You could do this using LINQ to XML making use of the XNode.DeepEquals method to compare your child nodes for equality. An example might look like this - the duplicateChild will not be added but newChild will be:
var doc = new XDocument(
new XElement("parent",
new XElement("child", 1)));
var parent = doc.Descendants("parent").Single();
var duplicateChild = new XElement("child", 1);
var newChild = new XElement("child", 2);
if (!parent.Elements().Any(e => XNode.DeepEquals(e, duplicateChild)))
{
parent.Add(duplicateChild);
}
if (!parent.Elements().Any(e => XNode.DeepEquals(e, newChild)))
{
parent.Add(newChild);
}
A demo here: https://dotnetfiddle.net/1t4Q1b

Loop through XML with XmlDocument

I'm new to using Linq and XMLDocument.
I have a simple XML file and I want to loop through all of the elements and print the tag and value. I don't want to use the XML Tags when looping through. this is what I have so far.
XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Step1>One
<Step2>Two
<Step3>Three
<Step4>Four
</Step4>
</Step3>
</Step2>
</Step1>
C# Code
private void StartIt()
{
System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
xd.Load(#"C:\Projects\GetXML\testLayers.xml");
XmlNodeList nl = xd.SelectNodes("Layer1");
foreach (XmlNode xnode in nl)
{
Console.WriteLine(xnode.Name + " = " + xnode.InnerText); // + " " + xnode.InnerXml);
}
}
Results:
Step1 = One
Two
Three
Four
What I want:
Step1 = One
Step2 = Two
Step3 = Three
Step4 = Four
Any suggestions?
With a little help of Linq,
XmlDocument doc = new XmlDocument();
doc.Load(fname);
var nodes = doc.SelectNodes("//*[text()]")
.Cast<XmlNode>()
.Select(n => new {
Name= n.Name,
Value = n.SelectSingleNode("text()").Value
})
.ToList();
// System.Xml.XmlDocument version
XmlDocument xd = new XmlDocument();
xd.Load(#"C:\Projects\GetXML\testLayers.xml");
foreach (XmlElement step in xd.SelectNodes("//*"))
{
Console.WriteLine("{0} = {1}", step.Name,
step.SelectSingleNode("text()").Value);
}
// System.Xml.Linq.XDocument version
XDocument xdLinq = XDocument.Load(#"C:\Projects\GetXML\testLayers.xml");
foreach (XElement step in xdLinq.XPathSelectElements("//*"))
{
Console.WriteLine("{0} = {1}", step.Name,
step.Nodes().Where(n => n.NodeType == XmlNodeType.Text).FirstOrDefault());
}
You can do the same using LINQ to XML and XDocument class:
var xDoc = XDocument.Load("Input.txt");
foreach (var e in xDoc.Descendants())
{
Console.WriteLine("{0} = {1}", e.Name, e.Nodes().OfType<XText>().First().Value.Trim());
}

Renaming xmlnodes using c# dynamically

I am using the below code to rename the xmlnode name dynamically. It's looping though the xml just fine, but it does not change the node name. Please help me to do this.
Sample XML doucment
- <NewDataSet>
- <Table5>
<FLD_ID>62</FLD_ID>
<FLD_DATE>2013-03-12</FLD_DATE>
<FLD_MOD_DATE>2013-04-05</FLD_MOD_DATE>
<FLD_DESC>New Creation</FLD_DESC>
</Table5>
- </NewDataSet>
Needed XML DOCUMENT
- <rows>
- <row>
<cell>62</cell>
<cell>2013-03-12</cell>
<cell>2013-04-05</cell>
<cell>New Creation</cell>
</row>
- </rows>
My code is here
XmlNode PackageListNode = hst_doc.SelectSingleNode("NewDataSet");
XmlNodeList PackageNodeList = PackageListNode.SelectNodes("Table5");
foreach (XmlNode node in PackageNodeList)
{
node.Name.Replace("Table5", "row");
foreach (XmlNode ls in node)
{
ls.Name.Replace(ls.Name, "cell");
}
}
As you can't replace element names in an XmlDocument...
...a replacement approach for your specific situation:
string srcXML = "<NewDataSet><Table5><FLD_ID>62</FLD_ID><FLD_DATE>2013-03-12</FLD_DATE><FLD_MOD_DATE>2013-04-05</FLD_MOD_DATE><FLD_DESC>New Creation</FLD_DESC></Table5></NewDataSet>";
var doc = new XmlDocument();
doc.LoadXml(srcXML);
XmlNode oldRoot = doc.SelectSingleNode("NewDataSet");
XmlNode newRoot = doc.CreateElement("rows");
doc.ReplaceChild(newRoot, oldRoot);
foreach (XmlNode childNode in oldRoot.ChildNodes)
{
newRoot.AppendChild(childNode.CloneNode(true));
}
XmlNodeList PackageNodeList = newRoot.SelectNodes("Table5");
foreach (XmlNode node in PackageNodeList)
{
var newNode = doc.CreateElement("row");
newRoot.ReplaceChild(newNode, node);
foreach (XmlNode childNode in node.ChildNodes)
{
var clonedChildNode = childNode.CloneNode(true);
newNode.AppendChild(clonedChildNode);
var newChildNode = doc.CreateElement("cell");
newNode.ReplaceChild(newChildNode, clonedChildNode);
foreach (XmlNode childChildNode in clonedChildNode.ChildNodes)
{
newChildNode.AppendChild(childChildNode.CloneNode(true));
}
}
}
Debug.Print(doc.OuterXml);
Embrace LINQ, embrace it!
// load the document from a file
var doc = XDocument.Load(xmlPath);
var root = doc.Root;
// replace the root element with a new element
root.ReplaceWith(
// create a new element with
// the name "rows" with new children
new XElement("rows",
// replace all child elements of
// the root with new elements
root.Elements().Select(table =>
// replace the current element with a new element
// with the name "row" with the new children
new XElement("row",
// replace all child elements of the
// current element with new elements
table.Elements().Select(field =>
// replace the current element with a new element
// with the name "cell" with the same value
new XElement("cell",
(string)field
)
)
)
)
)
);
// save the document back to the file
doc.Save(xmlPath);
String.Replace returns a new string, so of course one would love to:
node.Name = node.Name.Replace("Table5", "row");
which might as well be
node.Name = "row";
however, if you look at the documentation it says that XmlNode.Name is purely a 'getter' and not a 'setter', so maybe you'll need to create whole new nodes to replace them, it depends on the actual implementation, since XmlNode is an abstract class.
for (int i = 0; i < PackageNodeList.Count; ++i) XmlNode node in PackageNodeList)
{
XmlNode replacementNode = new XmlNode("row");
foreach (XmlNode ls in node)
{
XmlNode newCell = new XmlNode("cell");
newCell.Value = ls.Value;
replacementNode.AppendChild(newCell);
}
PackageNodeList[i] = replacementNode
PackageNodeList[i].ParentNode.ReplaceChild(PackageNodeList[i], replacementNode);
}

How to update the XMLDocument using c#?

I want to update the xml document and i need to return the updated xml in string. I am trying like below. when i save the document it expects the file name. but i dont want to save this as file. i just want to get the updated xml in string.
string OldXml = #"<Root>
<Childs>
<first>this is first</first>
<second>this is second </second>
</Childs
</Root>";
XmlDocument NewXml = new XmlDocument();
NewXml.LoadXml(OldXml );
XmlNode root = NewXml.DocumentElement;
XmlNodeList allnodes = root.SelectNodes("*");
foreach (XmlNode eachnode in allnodes)
{
if (eachnode.Name == "first")
{
eachnode.InnerText = "1";
}
}
NewXml.Save();
string newxml = NewXml.OuterXml;
You don't need to call Save method because string is immutable, your problem is in root.SelectNodes("*"), it just get child nodes, not all level of nodes. You need to go one more level:
foreach (XmlNode eachnode in allnodes)
{
var firstNode = eachnode.ChildNodes.Cast<XmlNode>()
.SingleOrDefault(node => node.Name == "first");
if (firstNode != null)
{
firstNode.InnerText = "1";
}
}
string newxml = NewXml.OuterXml;
It would be strongly recommended using LINQ to XML, it's simpler:
var xDoc = XDocument.Parse(OldXml);
foreach (var element in xDoc.Descendants("first"))
element.SetValue(1);
string newXml = xDoc.ToString();
Your iteration never reaches a node called "first". Else it would work fine without saving the NewXml.
You could however use a XElement and iterate over all descendants.
string OldXml = #"<Root>
<Childs>
<first>this is first</first>
<second>this is second </second>
</Childs>
</Root>";
var NewXml = XElement.Parse(OldXml);
foreach (var node in NewXml.Descendants())
{
if (node.Name.LocalName == "first")
{
node.Value = "1";
}
}
var reader = NewXml.CreateReader();
reader.MoveToContent();
string newxml = reader.ReadInnerXml();

Xml node reading for each loop

I am trying to loop through an Xml file and display the value for account in a message.
XmlNodeList nodeList = testDoc.SelectNodes("/details/row/var");
foreach (XmlNode no in nodeList)
{
XmlNode node = testDoc.SelectSingleNode("/details/row/var[#name='account']");
test.actual = node.Attributes["value"].Value;
MessageBox.Show(test.account);
}
The message box is currently displaying the first record repeatidly, how can I get to the next record?
Thanks for your input in advance.
You are repeatedly assigning node with the same element from testDoc. It is not clear what test.account is (perhaps a mistype for test.actual)?
no is the variable which will iterate the contents of nodeList - I imagine you intended to use that.
EDIT following edit of OP
Now you've shown us what nodeList is, I suspect you want to do something like this instead :
XmlNodeList nodeList = testDoc.SelectNodes("/details/row/var[#name='account']");
foreach (XmlNode no in nodeList)
{
test.actual = no.Attributes["value"].Value;
...
XmlDocument doc = new XmlDocument();
doc.Load("d:\\test.xml");
XmlNodeList node = doc.GetElementsByTagName("w:r");
foreach (XmlNode xn in node)
{
try
{
if (xn["w:t"].InnerText != null)
{
if (xn["w:t"].InnerText == "#")
{
string placeHolder = xn["w:t"].InnerText;
foreach (XmlNode a in node)
{
if (a["w:t"].InnerText != "#")
{
string placeHolder1 = a["w:t"].InnerText;
}
}
}
}
}
catch (Exception e)
{
Console.Write(e);
}
}
Here is the sample for parent node value to get information of the child nodes.here i am using the ReportItems ParentNode and Print only image child nodes.
xmldoc.Load(rdlFile);
StringBuilder sb=new StringBuilder();
XmlNode node = xmldoc.GetElementsByTagName("ReportItems")[0];
XmlNodeList list = node.ChildNodes;
atributes=new string[node.ChildNodes.Count];
int l = 0;
for (int j = 0; j < node.ChildNodes.Count; j++)
{
if (list[j].Name == "Image")
{
XmlAttributeCollection att = list[j].Attributes;
atributes[l] = att[0].Value.ToUpper();
}
l++;
}
for (int i = 0; i < node.ChildNodes.Count; i++)
{
if (searchText.Text.ToUpper() == atributes[i])
{
XmlNodeList lastlist = node.ChildNodes;
XmlNodeList endlist = lastlist[i].ChildNodes;
for (int k = 0; k < endlist.Count; k++)
{
sb.Append(endlist[k].Name+" - "+ endlist[k].InnerText);
sb.Append("\n"+"\n");
}
}
}
let me know if you have doubt..
Try this,
XmlDocument xdoc = new XDocument();
xdoc.Load("*/File/*");
string xmlcontents = xdoc.InnerXml;
var xpath = "(/details/row/var[#name='account'])";
XmlNodeList lists = xdoc.DocumentElement.SelectNodes(xpath);
foreach (XmlNode _node in lists)
{
string _nodeValue = _node.InnerText;
MessageBox.Show(_nodeValue);
}
Try the following:
//Create an xml reader;
XmlDocument _xmlDocument = new XmlDocument();
_xmlDocument.Load(/*File Name here*/);
//Select the element with in the xml you wish to extract;
XmlNodeList _nodeList = _xmlDocument.SelectNodes("/details/row/var[#name='account']");
//Display the values in the node list to the screen;
foreach (XmlNode _node in _nodeList)
{
String _nodeValue = _node.InnerText.ToString();
MessageBox.Show(_nodeValue.ToString());
}
I'm not 100% sure, but you may need to use recursion. If not, it should just look like this:
XmlDocument doc = //etc..
foreach(XmlNode node in doc.ChildNodes)
{
if(node.Name == "account")
{
MessageBox.Show(node.Value);
}
}
You shouldn't spend time with reading the xml node by node. Try Deserialization:

Categories

Resources