how do i create a hierarchical structure in WPF using treeview?
Here is my suggestion:
//create treeNode myParent = null;
while (Reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
var newNode = new TreeViewItem
{
Header = reader.Name
};
if(theParent !=null)
{
theParent.Items.Add(newnode);
}
else
{
treeView.Items.Add(newnode);
}
theParent = newnode;
break;
case XmlNodeType.Text: //Display the text in each element.
Console.WriteLine(reader.Value);
break;
case XmlNodeType.EndElement: //Display the end of the element.
Console.Write("</" + reader.Name);
Console.WriteLine(">");
if (theParent != null)
{
theParent = theParent.Parent;
}
break;
}
}
Don't try to manipulate the WPF TreeView directly. Instead, make your own "view model" representing a node, then bind it recursively to the TreeView using HierarchicalDataTemplate.
More info here.
Related
I have the following XML file (parse.xml):
<Invoice>
<InvoiceHeader>
<Name>cust1</Name>
<Number>5689</Number>
</InvoiceHeader>
<InvoiceHeader>
<Name>cust1</Name>
<Number>5689</Number>
<Number>5459</Number>
</InvoiceHeader>
<InvoiceHeader>
<Name>cust1</Name>
<Number>5689</Number>
<Number>5645</Number>
<Number>5879</Number>
</InvoiceHeader>
</Invoice>
I would like to read it into a list of the following class:
public class Details
{
public string Name {get; set;}
public List<string> Number{get; set;}
}
As you can see, in the XML the node Number can appear more than one time in InvoiceHeader. I'm not sure how to parse this XML into the List<Details> class.
I tried my code:
List<Details> details = new List<Details>;
XmlDocument doc = new XmlDocument();
doc.Load("parse.xml");
XmlNodeList nodeList = doc.SelectNodes("/Invoice/InvoiceHeader");
foreach (XmlNode node in nodeList)
{
details.Add(node["Name"].InnerText);
XmlNodeList dd = node.ChildNodes;
foreach (XmlNode inch in dd)
{
details.Add(node["Number"].InnerText);
}
}
I know this code isn't right but wanted to show what I have done so far.
nodeList is a list of <InvoiceHeader> nodes. One method to solve this problem would be to iterate through the ChildNodes of nodeList and use the property Name to create the Details class in each iteration.
Your code was almost there... I've just updated it slightly so it correctly adds the <Number> elements to the list:
List<Details> detailsList = new List<Details>();
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList nodeList = doc.SelectNodes("/Invoice/InvoiceHeader");
foreach (XmlNode node in nodeList)
{
// create details class for each InvoiceHeader
Details detail = new Details();
detail.Number = new List<string>();
// loop over child nodes to get Name and all Number elements
foreach (XmlNode child in node.ChildNodes)
{
// check node name to decide how to handle the values
if (child.Name == "Name")
{
detail.Name = child.InnerText;
}
else if (child.Name == "Number")
{
detail.Number.Add(child.InnerText);
}
}
detailsList.Add(detail);
}
Then you can display the results like this:
foreach (var details in detailsList)
{
Console.WriteLine($"{details.Name}: {string.Join(",", details.Number)}");
}
// output
cust1: 5689
cust1: 5689,5459
cust1: 5689,5645,5879
Another method you could consider is Linq-to-Xml. The below code produces the same output as that above:
XDocument doc = XDocument.Load(path);
var details = doc.Descendants("Invoice")
.Elements()
.Select(node => new Details()
{
Name = node.Element("Name").Value,
Number = node.Elements("Number").Select(child => child.Value).ToList()
})
.ToList();
Please find below code attachment
You need to follow this few steps
using System.Xml;
XmlTextReader reader = new XmlTextReader ("file name.xml");
while (reader.Read())
{
// Do some work here on the data.
Console.WriteLine(reader.Name);
}
Console.ReadLine();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
Console.Write("<" + reader.Name);
Console.WriteLine(">");
break;
case XmlNodeType.Text: //Display the text in each element.
Console.WriteLine (reader.Value);
break;
case XmlNodeType. EndElement: //Display the end of the element.
Console.Write("</" + reader.Name);
Console.WriteLine(">");
break;
}
}
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
Console.Write("<" + reader.Name);
while (reader.MoveToNextAttribute()) // Read the attributes.
Console.Write(" " + reader.Name + "='" + reader.Value + "'");
Console.WriteLine(">");
break;
case XmlNodeType.Text: //Display the text in each element.
Console.WriteLine (reader.Value);
break;
case XmlNodeType. EndElement: //Display the end of the element.
Console.Write("</" + reader.Name);
Console.WriteLine(">");
break;
}
}
finally save code and run them...
Complete code listing
using System;
using System.Xml;
namespace ReadXMLfromFile
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
static void Main(string[] args)
{
XmlTextReader reader = new XmlTextReader ("file name.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
Console.Write("<" + reader.Name);
Console.WriteLine(">");
break;
case XmlNodeType.Text: //Display the text in each element.
Console.WriteLine (reader.Value);
break;
case XmlNodeType.EndElement: //Display the end of the element.
Console.Write("</" + reader.Name);
Console.WriteLine(">");
break;
}
}
Console.ReadLine();
}
}
}
<tours xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://api.contiki.com/schemas/v2/detailed_tours.xsd">
<tour>
<id>290</id>
<name>Peru Uncovered</name>
<lowest_price>
<code>11D15a</code>
</lowest_price>
</tour>
</tours>
I want to read Id, name and code.
I am trying this code
XmlTextReader reader = new XmlTextReader(downloadfolder);
XmlDocument doc = new XmlDocument();
XmlNode node = doc.ReadNode(reader);
foreach (XmlNode chldNode in node.ChildNodes)
{
string employeeName = chldNode.Attributes["name"].Value;
}
But i am getting null. Can anyone tell me how can i read the values? i can not use Linq as i am working in SSIS 2008 project which does not support linq.
Updated Answer
XmlTextReader reader = new XmlTextReader(downloadfolder);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: // The node is an element.
string node = reader.Name;
if (node == "id")
{
string id = reader.ReadString();
}
if (node == "name")
{
string name = reader.ReadString();
}
if (node == "code")
{
string code = reader.ReadString();
}
break;
}
I can read the values but how can i add these as a row in my data table?
here node type of "name" is element.
below code can be used for node type checking
XmlTextReader reader = new XmlTextReader ("<file name>");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
Reference : http://support.microsoft.com/en-us/kb/307548
For my information program I need to read a web xml file and place it in a label for every value.
An example of the XML file:
<ActueleVertrekTijden>
<VertrekkendeTrein>
<RitNummer>5070</RitNummer>
<VertrekTijd>2015-03-20T19:42:00+0100</VertrekTijd>
<EindBestemming>Den Haag Centraal</EindBestemming>
<TreinSoort>Sprinter</TreinSoort>
<RouteTekst>Lage Zwaluwe, Dordrecht, Rotterdam C.</RouteTekst>
<Vervoerder>NS</Vervoerder>
<VertrekSpoor wijziging="false">6</VertrekSpoor>
</VertrekkendeTrein>
<VertrekkendeTrein>
<RitNummer>1971</RitNummer>
<VertrekTijd>2015-03-20T19:50:00+0100</VertrekTijd>
<EindBestemming>Venlo</EindBestemming>
<TreinSoort>Intercity</TreinSoort>
<RouteTekst>Tilburg, Eindhoven, Helmond</RouteTekst>
<Vervoerder>NS</Vervoerder>
<VertrekSpoor wijziging="false">4</VertrekSpoor>
<Opmerkingen> // This is not always available, but it is important and specific for a 'VertrekkendeTrein'
<Opmerking>Rijdt vandaag niet</Opmerking>
</Opmerkingen>
</VertrekkendeTrein>
</ActueleVertrekTijden>
I tried it with XMLDocument (using foreach) like this:
foreach (XmlNode nodelist2 in nodeList)
{
if (i < 1) //1
{
switch (nodelist.Name)
{
case "VertrekTijd": string vertrek1 = (nodelist2.InnerText); break;
case "VertrekVertragingsTekst": string vertraging1 = (nodelist2.InnerText); break;
case "EindBestemming": string eindbest1 = (nodelist2.InnerText); break;
case "TreinSoort": string treinsoort1 = (nodelist2.InnerText); break;
case "RouteTekst": string route1 = (nodelist2.InnerText); break;
case "VertrekSpoor": string spoor1 = (nodelist2.InnerText); i++ break;
case "Opmerkingen": case "Opmerking": string opmerking1 = (nodelist2.InnerText); break;
}
}
}
But it wasn't a success.
Is there a smarter way to read it, and place it in a lot of labels?
EDIT:
With the answer I got, I tried the following code:
try
{
string urlo = "**secured webaddress that not end with .xml**";
string resultje = HttpGeto(urlo);
XmlDocument doc = new XmlDocument();
XmlNode root = doc.FirstChild;
//* the document has one root element "ActueleVertrekTijden"
//* the root element has multiple child nodes "VertrekkendeTrein"
XmlNodeList nodelist1 = root.ChildNodes;
for (int i = 0; i < nodelist1.Count; i++)
{
XmlNodeList nodelist2 = nodelist1[i].ChildNodes;
//* for each child node get all of all of child nodes,
//* that is where you need to get the text within each one of them
foreach (XmlNode node in nodelist2)
{
switch (node.Name)
{
case "VertrekTijd":
string vertrek1 = node.InnerText; MessageBox.Show(vertrek1); lblts1.Text = vertrek1;
break;
case "VertrekVertragingsTekst":
string vertraging1 = node.InnerText;
break;
case "EindBestemming":
string eindbest1 = node.InnerText;
break;
case "TreinSoort":
string treinsoort1 = node.InnerText;
break;
case "RouteTekst":
string route1 = node.InnerText;
break;
case "VertrekSpoor":
string spoor1 = node.InnerText;
break;
case "Opmerkingen":
XmlNode OpNode = node.FirstChild;
if (OpNode != null)
{
string opmerking1 = OpNode.InnerText;
}
break;
}
}
}
}
catch
{
lblcatch.Text = "werktniet";
}
But it doesn't work. And also, how can i read the next "VertrekkendeTrein"?, just by copying the code and use the I++;? I need to read the first 6 "VertrekkendeTrein".
XmlNode root = doc.FirstChild;
//* the document has one root element "ActueleVertrekTijden"
//* the root element has multiple child nodes "VertrekkendeTrein"
XmlNodeList nodelist1 = root.ChildNodes;
for (int i=0; i<nodelist1.Count; i++)
{
XmlNodeList nodelist2 = nodelist1[i].ChildNodes;
//* for each child node get all of all of child nodes,
//* that is where you need to get the text within each one of them
foreach (XmlNode node in nodeList2)
{
switch (node.Name)
{
case "VertrekTijd":
string vertrek1 = node.InnerText;
break;
case "VertrekVertragingsTekst":
string vertraging1 = node.InnerText;
break;
case "EindBestemming":
string eindbest1 = node.InnerText;
break;
case "TreinSoort":
string treinsoort1 = node.InnerText;
break;
case "RouteTekst":
string route1 = node.InnerText;
break;
case "VertrekSpoor":
string spoor1 = node.InnerText;
break;
case "Opmerkingen":
XmlNode OpNode = node.FirstChild;
if(OpNode!=null)
{
string opmerking1 = OpNode.InnerText;
}
break;
}
}
}
Consider the following XML which I have to parse.
<root>
<item>
<itemId>001</itemId>
<itemName>test 1</itemName>
<description/>
</item>
</root>
I have to parse each of its tag and store it into a table as follows:
TAG_NAME TAG_VALUE IsContainer
------------ -------------- -----------
root null true
item null true
itemId 001 false
itemName test 1 false
description null false
/item null true
/root null true
Now to get this done, I am using XmlReader as this allows us to parse each & every node.
I am doing it as follows:
I created the following class to contain each tag's data
public class XmlTag
{
public string XML_TAG { get; set; }
public string XML_VALUE { get; set; }
public bool IsContainer { get; set; }
}
I am trying to get the list of tags(including closing ones) as follows:
private static List<XmlTag> ParseXml(string path)
{
var tags = new List<XmlTag>();
using (var reader = XmlReader.Create(path))
{
while (reader.Read())
{
var tag = new XmlTag();
bool shouldAdd = false;
switch (reader.NodeType)
{
case XmlNodeType.Element:
shouldAdd = true;
tag.XML_TAG = reader.Name;
//How do I get the VALUE of current reader?
//How do I determine if the current node contains children nodes to set IsContainer property of XmlTag object?
break;
case XmlNodeType.EndElement:
shouldAdd = true;
tag.XML_TAG = string.Format("/{0}", reader.Name);
tag.XML_VALUE = null;
//How do I determine if the current closing node belongs to a node which had children.. like ROOT or ITEM in above example?
break;
}
if(shouldAdd)
tags.Add(tag);
}
}
return tags;
}
but I am having difficulty determining the following:
How to determine if current ELEMENT contains children XML nodes? To set IsContainer property.
How to get the value of current node value if it is of type XmlNodeType.Element
Edit:
I have tried to use LINQ to XML as follows:
var xdoc = XDocument.Load(#"SampleItem.xml");
var tags = (from t in xdoc.Descendants()
select new XmlTag
{
XML_TAG = t.Name.ToString(),
ML_VALUE = t.HasElements ? null : t.Value,
IsContainer = t.HasElements
}).ToList();
This gives me the XML tags and their values but this does not give me ALL the tags including the closing ones. That's why I decided to try XmlReader. But If I have missed anything in LINQ to XML example, please correct me.
First of all, as noted by Jon Skeet in the comments you should probably consider using other tools, like XmlDocument possibly with LINQ to XML (EDIT: an example with XmlDocument follows).
Having said that, here is the simplest solution for what you have currently (note that it's not the cleanest possible code, and it doesn't have much validation):
private static List<XmlTag> ParseElement(XmlReader reader, XmlTag element)
{
var result = new List<XmlTag>() { element };
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
element.IsContainer = true;
var newTag = new XmlTag() { XML_TAG = reader.Name };
if (reader.IsEmptyElement)
{
result.Add(newTag);
}
else
{
result.AddRange(ParseElement(reader, newTag));
}
break;
case XmlNodeType.Text:
element.XML_VALUE = reader.Value;
break;
case XmlNodeType.EndElement:
if (reader.Name == element.XML_TAG)
{
result.Add(new XmlTag()
{
XML_TAG = string.Format("/{0}", reader.Name),
IsContainer = element.IsContainer
});
}
return result;
}
}
return result;
}
private static List<XmlTag> ParseXml(string path)
{
var result = new List<XmlTag>();
using (var reader = XmlReader.Create(path))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
result.AddRange(ParseElement(
reader,
new XmlTag() { XML_TAG = reader.Name }));
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
result.Add(new XmlTag()
{
XML_TAG = string.Format("/{0}",current.Name)
});
}
}
}
return result;
}
An example using XmlDocument. This will give slightly different result for self-enclosing tags (<description/> in your case). You can change this behaviour easily, depending on what you want.
private static IEnumerable<XmlTag> ProcessElement(XElement current)
{
if (current.HasElements)
{
yield return new XmlTag()
{
XML_TAG = current.Name.ToString(),
IsContainer = true
};
foreach (var tag in current
.Elements()
.SelectMany(e => ProcessElement(e)))
{
yield return tag;
}
yield return new XmlTag()
{
XML_TAG = string.Format("/{0}", current.Name.ToString()),
IsContainer = true
};
}
else
{
yield return new XmlTag()
{
XML_TAG = current.Name.ToString(),
XML_VALUE = current.Value
};
yield return new XmlTag()
{
XML_TAG = string.Format("/{0}",current.Name.ToString())
};
}
}
And using it:
var xdoc = XDocument.Load(#"test.xml");
var tags = ProcessElement(xdoc.Root).ToList();
I am a new to programming, and have a serious problem and cant get out of it.
I have 5 XML URLs. such as http://www.shopandmiles.com/xml/3_119_3.xml
This is an XML URL which I have to get values and write to database in related columns.
My column names and XML tag names do match.
When I write the below code, reader element miss null xml values. Some tags do not have value inside. I have to add them null to linkedlist because after that code, i am going through the linked list but the order doesnt match if ı cant add a value for null xml values. So column names and data inside doesnt match. i lose the order. My all code is here, you can also check comment in the code if that helps. Thank you all.
public void WebServiceShopMilesCampaignsXMLRead(string URL)
{
XmlReader reader = XmlReader.Create(URL);
LinkedList<string> linkedList = new LinkedList<string>();
List<ShopAndMilesCampaigns> shopMileCampaigns = new List<ShopAndMilesCampaigns>();
try
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Text:
linkedList.AddLast(reader.Value);
break;
}
}
}
catch (XmlException exception)
{
Console.WriteLine("XML okurken bir sorun oluştu, hata detayı --> " + exception.Message);
}
LinkedListNode<string> node = linkedList.First;
while (node != null)
{
ShopAndMilesCampaigns shopMilesCampaign = new ShopAndMilesCampaigns();
shopMilesCampaign.Name = node.Value; // Null values mixes up the order because i cant add as null with reader.read above
node = node.Next;
shopMilesCampaign.Summary = node.Value;
node = node.Next;
shopMilesCampaign.AccountName = node.Value;
node = node.Next;
shopMilesCampaign.Category = node.Value;
node = node.Next;
shopMilesCampaign.Sector = node.Value;
node = node.Next;
shopMilesCampaign.Details = node.Value;
node = node.Next;
shopMilesCampaign.Image = node.Value;
node = node.Next;
shopMilesCampaign.Status = 1;
node = node.Next;
shopMileCampaigns.Add(shopMilesCampaign);
}
foreach (ShopAndMilesCampaigns shopMileCampaign in shopMileCampaigns)
{
shopMileCampaign.Insert();
}
}
I found the answer. Here it is to let you know.
If the XmlNodeType is equal to Element, then the loop continues to read from the XML data and looks for Whitesapces and end Element of XML tag. The below code gives me the exact value of XML tag even it is empty.
public LinkedList<string> AddToLinkedList(XmlReader reader)
{
LinkedList<string> linkedList = new LinkedList<string>();
try
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
reader.Read();
Start:
if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Element)
{
reader.Read();
goto Start;
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
linkedList.AddLast("");
}
else
{
linkedList.AddLast(reader.Value);
}
break;
}
}
}