XML represantation of treeview nodes - c#

I am trying to import and export to treeview from XML file. But i am having this issue. sample treeview have one root node and two child nodes of same parent. The codes i am using for exporting and importing doesn't work. When I export the treeview the saved XML file is like this:
<?xml version="1.0" encoding="utf-8" ?>
<AAA>
BBBCCC</AAA>
When I import that xml file to treeview it look like this after import xml to treeview . Codes that i am using for export and import are:
//Open the XML file, and start to populate the treeview
private void populateTreeview()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "Open XML Document";
dlg.Filter = "XML Files (*.xml)|*.xml";
dlg.FileName = Application.StartupPath + "\\..\\..\\example.xml";
if (dlg.ShowDialog() == DialogResult.OK)
{
try
{
//Just a good practice -- change the cursor to a
//wait cursor while the nodes populate
this.Cursor = Cursors.WaitCursor;
//First, we'll load the Xml document
XmlDocument xDoc = new XmlDocument();
xDoc.Load(dlg.FileName);
// Now, clear out the treeview,
// and add the first (root) node
treeView1.Nodes.Clear();
treeView1.Nodes.Add(new TreeNode(xDoc.DocumentElement.Name));
TreeNode tNode = new TreeNode();
tNode = (TreeNode)treeView1.Nodes[0];
// We make a call to addTreeNode,
// where we'll add all of our nodes
addTreeNode(xDoc.DocumentElement, tNode);
// Expand the treeview to show all nodes
treeView1.ExpandAll();
}
catch(XmlException xExc)
{
// Exception is thrown is there is an error in the Xml
MessageBox.Show(xExc.Message);
}
catch(Exception ex) //General exception
{
MessageBox.Show(ex.Message);
}
finally
{
this.Cursor = Cursors.Default; //Change the cursor back
}
}
}
// This function is called recursively until all nodes are loaded
private void addTreeNode(XmlNode xmlNode, TreeNode treeNode)
{
XmlNode xNode;
TreeNode tNode;
XmlNodeList xNodeList;
if (xmlNode.HasChildNodes) // The current node has children
{
xNodeList = xmlNode.ChildNodes;
for(int x = 0; x <= xNodeList.Count - 1; x++)
{
// Loop through the child nodes
xNode = xmlNode.ChildNodes[x];
treeNode.Nodes.Add(new TreeNode(xNode.Name));
tNode = treeNode.Nodes[x];
addTreeNode(xNode, tNode);
}
}
else //No children, so add the outer xml (trimming off whitespace)
treeNode.Text = xmlNode.OuterXml.Trim();
}
private XmlTextWriter xr;
public void exportToXml2(TreeView tv, string filename)
{
xr = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
xr.WriteStartDocument();
//Write our root node
xr.WriteStartElement(treeView1.Nodes[0].Text);
foreach (TreeNode node in tv.Nodes)
{
saveNode2(node.Nodes);
}
//Close the root node
xr.WriteEndElement();
xr.Close();
}
private void saveNode2(TreeNodeCollection tnc)
{
foreach (TreeNode node in tnc)
{
// If we have child nodes, we'll write
// a parent node, then iterate over
// the children
if (node.Nodes.Count > 0)
{
xr.WriteStartElement(node.Text);
saveNode2(node.Nodes);
xr.WriteEndElement();
}
else //No child nodes, so we just write the text
{
xr.WriteString(node.Text);
}
}
}
Where is the problem?

You are using language other than English . please convert and save .
var text = File.ReadAllText(file, Encoding.GetEncoding(codePage));
how-to-read-text-files-with-ansi-encoding-and-non-english-letters
File.WriteAllText(filepath, filetext, Encoding.Unicode);
or
new System.IO.StreamWriter(new FileStream(file_name,FileMode.OpenOrCreate),Encoding.ASCII);
read-write-text-file-ansi-utf8-unicode
how-to-convert-utf7-string-into-ansi-in-csharp

The code is fine. The xml should look like this
<?xml version="1.0" encoding="utf-8" ?>
<AAA>
<BBB/>
<CCC/>
</AAA>

ok, I modified a few lines and I managed what i want to.
Firstly, I add char array for special characters. And use them for trim() function.
private void addTreeNode(XmlNode xmlNode, TreeNode treeNode)
{
**char[] karakter = new char[] { '<', '>', '/' };**
XmlNode xNode;
TreeNode tNode;
XmlNodeList xNodeList;
if (xmlNode.HasChildNodes) //The current node has children
{
xNodeList = xmlNode.ChildNodes;
for (int x = 0; x <= xNodeList.Count - 1; x++)
{
xNode = xmlNode.ChildNodes[x];
treeNode.Nodes.Add(new TreeNode(xNode.Name));
tNode = treeNode.Nodes[x];
addTreeNode(xNode, tNode);
}
}
else
{
treeNode.Text = xmlNode.OuterXml.Trim(**karakter**);
}
secondly, if there is no child nodes I used WriteRaw method instead of WriteString method.Because special characters are replaced by WriteString method.
private void saveNode2(TreeNodeCollection tnc)
{
foreach (TreeNode node in tnc)
{
if (node.Nodes.Count > 0)
{
xr.WriteStartElement(node.Text);
saveNode2(node.Nodes);
xr.WriteEndElement();
}
else
{
**xr.WriteRaw($"<{node.Text}/>");**
}
}
But when I try to save treeview with two roots, It doesn't write the last root. Any opinion? Childs of last root is written as childs of first root. Other then that codes work.

Related

Console is able to display all imported XML data but cannot send all information to text file

I have the following code that gathers all elements and attributes from an XML file and sends to the Console. This works without issue.
I want to send the data to a text file, but only the first line or last line show up. Does anyone have any suggestions for having the data sent to a txt file?
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);
XmlNode rootNode = xmlDoc.DocumentElement;
DisplayNodes(rootNode);
Console.ReadLine();
void DisplayNodes(XmlNode node)
{
//Print the node type, node name and node value of the node
if (node.NodeType == XmlNodeType.Text)
{
Console.WriteLine(node.Value.TrimStart());
}
else
{
Console.WriteLine(node.Name.TrimStart());
}
//Print attributes of the node
if (node.Attributes != null)
{
XmlAttributeCollection attrs = node.Attributes;
foreach (XmlAttribute attr in attrs)
{
Console.WriteLine(attr.Name + " " + attr.Value + "\n");
}
}
XmlNodeList children = node.ChildNodes;
foreach (XmlNode child in children)
{
DisplayNodes(child);
}
}
You can use the static methods in the File class to write to a text file very easily, since it wraps the stream creation for you.
First, we could re-write your method above to return a List<string>, which then could be written to the console or a file, or anything else:
public static List<string> GetNodeInfo(XmlNode node)
{
if (node == null) return new List<string>();
var nodes = new List<string>
{
node.NodeType == XmlNodeType.Text
? node.Value.TrimStart()
: node.Name.TrimStart()
};
if (node.Attributes != null)
{
nodes.AddRange(node.Attributes.Cast<XmlAttribute>()
.Select(attribute => $"{attribute.Name} {attribute.Value}\n"));
}
nodes.AddRange(node.ChildNodes.Cast<XmlNode>().SelectMany(GetNodeInfo));
return nodes;
}
Now, we can use this method to get the node information and then write it to whatever we want:
List<string> nodeInfo = GetNodeInfo(myNode);
// Write it to the console:
Console.WriteLine(string.Join(Environment.NewLine, nodeInfo));
// Write it to a file:
File.WriteAllLines(myFilePath, nodeInfo);
I just found the answer to my question. I used the following:
using (FileStream f = new FileStream(fileName, FileMode.Append, FileAccess.Write))
using (StreamWriter s = new StreamWriter(f))
For each Console.Writline change to
s.WriteLine

parsing old xml to make a new one-document already has a root node c#

I have a XML file that is uploaded in a treeView and I have to make a new XML by treating old nodes as text and wrapping them with new tags and then saving it all into a file.I have to keep in mind which nodes are the child nodes and give them element tags.
private void saveNode(TreeNode node, XmlNode xnode,XmlDocument xmlDoc1)
{
foreach (TreeNode tnode in treeView1.Nodes)
{
xnode.AppendChild(xmlDoc1.CreateNode(XmlNodeType.Text, tnode.Text, tnode.Text));
XmlNode rootNode = xmlDoc1.CreateElement("category");
XmlAttribute oid = rootNode.Attributes.Append(xmlDoc1.CreateAttribute("oid"));
oid.Value = Guid.NewGuid().ToString();
xmlDoc1.AppendChild(rootNode);
XmlElement dr = (XmlElement)rootNode.AppendChild(xmlDoc1.CreateElement("name"));
dr.AppendChild(xmlDoc1.CreateTextNode("Model"));
XmlElement com = (XmlElement)rootNode.AppendChild(xmlDoc1.CreateElement("comment"));
XmlElement condition = (XmlElement)rootNode.AppendChild(xmlDoc1.CreateElement("condition"));
xmlDoc1.AppendChild(rootNode);
saveNode(tnode, xnode,xmlDoc1);
if (node.NextNode != null)
{
foreach (TreeNode tn in treeView1.Nodes)
{
XmlNode root1 = xmlDoc1.CreateElement("elements");
root1.AppendChild(xmlDoc1.CreateNode(XmlNodeType.Text, tnode.Text, "elements"));
root1.InnerText = tnode.Text;
saveNode(tn, xnode, xmlDoc1);
}
}
else {
foreach (TreeNode tn in treeView1.Nodes)
{
XmlNode root1 = xmlDoc1.CreateElement("elements");
root1.AppendChild(xmlDoc1.CreateNode(XmlNodeType.Text, tnode.Text, "elements"));
saveNode(tn, xnode, xmlDoc1);
}
}
}
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
XmlDocument xmlDoc1 = new XmlDocument();
XmlNode xroot = xmlDoc1.CreateElement("model");
XmlAttribute oid = xroot.Attributes.Append(xmlDoc1.CreateAttribute("oid"));
oid.Value = Guid.NewGuid().ToString();
xmlDoc1.AppendChild(xroot);
XmlElement dr = (XmlElement)xroot.AppendChild(xmlDoc1.CreateElement("name"));
dr.AppendChild(xmlDoc1.CreateTextNode("Model"));
XmlElement com = (XmlElement)xroot.AppendChild(xmlDoc1.CreateElement("comment"));
XmlElement condition = (XmlElement)xroot.AppendChild(xmlDoc1.CreateElement("condition"));
XmlElement el = (XmlElement)xroot.AppendChild(xmlDoc1.CreateElement("element"));
try
{
foreach (TreeNode tn in treeView1.Nodes)
{
saveNode(tn, xroot,xmlDoc1);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
saveFileDialog1.Filter = "Text Files (*.xml)|*.xml";
saveFileDialog1.AddExtension = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
xmlDoc1.Save(saveFileDialog1.FileName);
}
}

Get innertext from XML tags?

I am trying to populate an array with the inner text or value of a XML tag. I can loop though the nodes of the tag i am just having an issue pulling out the stored value.
I am looping though the child nodes of the Properties Tag, XML at bottom of Question.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("C://Users//Shaun//Documents//Visual Studio 2010//Projects//LightStoneTestService//LightStoneTestService//FileTest//Testdo.xml");
//XmlNodeList dataNodes = xmlDoc.SelectNodes("//Properties");
XmlNodeList oXMlNodeList = xmlDoc.GetElementsByTagName("Properties");
for (int Count = 0; Count < 27; Count++)
{
foreach (XmlNode node in oXMlNodeList)
{
int Max = node.ChildNodes.Count;
foreach (XmlNode childNode in node.ChildNodes) //For each child node in FieldData
{
if (ArrayProperties[Count].LightStoneTag == childNode.Name)
{
ArrayProperties[Count].Value = node.SelectSingleNode(ArrayProperties[Count].LightStoneTag).InnerText;
}
}
}
}
***** My Xml file looks as follows:
<NewDataSet>
<RequestData xmlns="RequestData">
<Req_ID>3204eba5-07f4-4e83-8b46-d89fa1d70bf6</Req_ID>
</RequestData>
<Properties xmlns="Properties">
<sr_id>19374324</sr_id>
<prop_id>9841107</prop_id>
<DEED_ID>21</DEED_ID>
<PROPTYPE_ID>2</PROPTYPE_ID>
<SS_ID>2315</SS_ID>
<NAD_ID>3048001</NAD_ID>
<property_type>SS</property_type>
<PROVINCE>GA</PROVINCE>
<MUNICNAME>CITY OF JOHANNESBURG</MUNICNAME>
<DEEDTOWN>ALLENS NEK</DEEDTOWN>
<SECTIONAL_TITLE>SS GREENHILLS</SECTIONAL_TITLE>
<UNIT>15</UNIT>
<TownShip>ALLENS NEK</TownShip>
<Purchase_Price>236500</Purchase_Price>
<Purchase_Date>20031020</Purchase_Date>
<Bond_Number>SB37369/2006</Bond_Number>
<Township_alt>ALLEN'S NEK EXT 32</Township_alt>
<RE>false</RE>
</Properties>
</NewDataSet>
It's the namespace issue. Add this portion of code before the for loop:
NameTable nt = new NameTable();
nt.Add("Properties");
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
nsmgr.AddNamespace("ns1", "Properties");
Change the line where you retrieve InnerText to:
ArrayProperties[Count].Value = node
.SelectSingleNode(
String.Concat("//ns1:", ArrayProperties[Count].LightStoneTag),
nsmgr)
.InnerText;

C# : Modify a xml node

i have that xml file :
<?xml version="1.0" encoding="utf-8"?>
<reminders>
<reminder>
<Title>Alarm1</Title>
<Description>Desc1</Description>
<Time>03/07/2012 10:11AM</Time>
<snooze>1</snooze>
<repeat>None</repeat>
</reminder>
</reminders>
And i want to modify the innertext from Alarm1 to another value so i wrote that code which actually duplicate the entire node .
XmlDocument xml = new XmlDocument();
xml.Load("0.xml");
XmlNodeList elements = xml.SelectNodes("//reminders");
foreach (XmlNode element in elements)
{
if (element.InnerText == "Alarm1")
{
XmlNode newvalue = xml.CreateElement("MODIFIED");
element.ReplaceChild(newvalue, element);
xml.Save("0.xml");
}
}
And then tried another code :
foreach (XmlElement element in xml.SelectNodes("//reminder"))
{
if (element.InnerText == "Alarm1")
{
XmlNode newvalue = xml.CreateElement("MODIFIED");
element.ReplaceChild(newvalue, element);
xml.Save("0.xml");
}
}
But also doesn`t work....
EDIT 1 : [Figured out a new code]
XmlDocument xml = new XmlDocument();
xml.Load("0.xml");
foreach (XmlElement element in xml.SelectNodes("//reminder"))
{
foreach (XmlElement element1 in element)
{
if (element.SelectSingleNode("//Title").InnerText == "Alarm1")
{
XmlNode newvalue = xml.CreateElement("MODIFIED");
element.ReplaceChild(newvalue, element1);
xml.Save("0.xml");
}
}
}
But it made the Alarm1 becomes
<MODIFIED />
EDIT 2 : [I SOLVED IT :D]
Okay here is the code i could figure out :
XmlDocument xml = new XmlDocument();
xml.Load("0.xml");
foreach (XmlElement element in xml.SelectNodes("//reminder"))
{
foreach (XmlElement element1 in element)
{
if (element.SelectSingleNode("//Title").InnerText == "Alarm1")
{
MessageBox.Show(element1.InnerText);
XmlNode newvalue = xml.CreateElement("Title");
newvalue.InnerText = "MODIFIED";
element.ReplaceChild(newvalue, element1);
xml.Save("0.xml");
}
}
}
I`ll really appreciate your helps and thanks.
Try this:
xml.SelectSingleNode("//reminder/Title").InnerText = "NewValue";
Your foreach line is simply looping through a list of elements called "reminders", not it's child nodes.
Take a look at this xpath tutorial for more information:
http://www.w3schools.com/xpath/xpath_intro.asp
If you want to use linq with xml (I find it the best way) then you will want to use the System.Xml.Linq namespace. The classes in that namespace are all prefixed with just X not Xml. The functionality in this namespace is newer, better and much easier to manipulate with Linq.
var xml = XDocument.Load("0.xml");
var alarm1 = xml.Descendants("reminder")
.Single(r => r.Element("Title") == "Alarm1");
This code will give you a variable, alarm1 that is the reminder that has a title node of "Alarm1."
From that point its not clear to me exactly what you want to modify. If you just want to change the title then ...
alarm1.Element("Title").Value = "MODIFIED";
xml.Save("0.xml");
XDocument doc = XDocument.Load("0.xml");
IEnumerable<XElement> rech =
from el in doc.Root.Elements("reminder")
where (string)el.Element("Title") == "Alarm1"
select el;
if (rech.Count() != 0)
{
foreach (XElement el in rech)
{
el.Element("Title").SetValue("NEW TITLE");
}
}
doc.Save("0.xml");
XDocument xDoc = XDocument.Load(.....);
xDoc.Descendants("Title").First().Value = "New Value";
xDoc.Save(...)
XmlDocument xml = new XmlDocument();
xml.Load(...);
var newTitle = "MODIFIED";
var title_node = xml.GetElementsByTagName("Title");
if(!string.IsNullOrEmpty(newTitle) && title_node.Count > 0)
{
title_node[0].InnerText = newTitle;
}

populate a tree view with an xml file

Im using .net windows form application. I have an xml file.I want to populate a tree view with data from a xml file. I am doing this using the following code.
private void button1_Click(object sender, EventArgs e)
{
try
{
this.Cursor = System.Windows.Forms.Cursors.WaitCursor;
//string strXPath = "languages";
string strRootNode = "Treeview Sample";
OpenFileDialog Dlg = new OpenFileDialog();
Dlg.Filter = "All files(*.*)|*.*|xml file (*.xml)|*.txt";
Dlg.CheckFileExists = true;
string xmlfilename = "";
if (Dlg.ShowDialog() == DialogResult.OK)
{
xmlfilename = Dlg.FileName;
}
// Load the XML file.
//XmlDocument dom = new XmlDocument();
//dom.Load(xmlfilename);
XmlDocument doc = new XmlDocument();
doc.Load(xmlfilename);
string rootName = doc.SelectSingleNode("/*").Name;
textBox4.Text = rootName.ToString();
//XmlNode root = dom.LastChild;
//textBox4.Text = root.Name.ToString();
// Load the XML into the TreeView.
this.treeView1.Nodes.Clear();
this.treeView1.Nodes.Add(new TreeNode(strRootNode));
TreeNode tNode = new TreeNode();
tNode = this.treeView1.Nodes[0];
XmlNodeList oNodes = doc.SelectNodes(textBox4.Text);
XmlNode xNode = oNodes.Item(0).ParentNode;
AddNode(ref xNode, ref tNode);
this.treeView1.CollapseAll();
this.treeView1.Nodes[0].Expand();
this.Cursor = System.Windows.Forms.Cursors.Default;
}
catch (Exception ex)
{
this.Cursor = System.Windows.Forms.Cursors.Default;
MessageBox.Show(ex.Message, "Error");
}
}
private void AddNode(ref XmlNode inXmlNode, ref TreeNode inTreeNode)
{
// Recursive routine to walk the XML DOM and add its nodes to a TreeView.
XmlNode xNode;
TreeNode tNode;
XmlNodeList nodeList;
int i;
// Loop through the XML nodes until the leaf is reached.
// Add the nodes to the TreeView during the looping process.
if (inXmlNode.HasChildNodes)
{
nodeList = inXmlNode.ChildNodes;
for (i = 0; i <= nodeList.Count - 1; i++)
{
xNode = inXmlNode.ChildNodes[i];
inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
tNode = inTreeNode.Nodes[i];
AddNode(ref xNode, ref tNode);
}
}
else
{
inTreeNode.Text = inXmlNode.OuterXml.Trim();
}
}
My xml file is this:"hello.xml"
<?xml version="1.0" encoding="utf-8" ?>
<languages>
<language>
<key>abc</key>
<value>hello how ru</value>
</language>
<language>
<key>def</key>
<value>i m fine</value>
</language>
<language>
<key>ghi</key>
<value>how abt u</value>
</language>
</languages>
Now after using the above code I am able to populate the tree view. But I dont like to populate the complete xml file. I should get only till
languages
language
key
value
I don't want
abc
how are you
etc.....
I mean to say the leaf nodes. Please help me
What you don't want to add is the text content of the nodes, if I understood correctly; then, you might check the NodeType property of the XmlNode class, something like:
xNode = inXmlNode.ChildNodes[i];
if (xNode.NodeType != XmlNodeType.Text) {
inTreeNode.Nodes.Add(new TreeNode(xNode.Name));
tNode = inTreeNode.Nodes[i];
AddNode(ref xNode, ref tNode);
}

Categories