I have an xml file like this:
<servers>
<general name="1">
<service name="ser1"/>
<service name="ser2"/>
</general>
<general name="2">
<service name="ser1"/>
<service name="ser2"/>
</general>
</servers>
In my winform application, I have a treeview list with checkbox property set to true.What I am trying to achieve is that I am attempting to read this xml file and update both the parent and child node to this tree view.
What I have tried is:
XDocument doc = XDocument.Load(#"D:\\path.xml");
TreeNode node;
var gnrl = from general in doc.Descendants("general")
select new
{
parent = general.Attribute("name").Value,
child = general.Descendants("service")
};
//Loop through results
foreach (var general in gnrl)
{
// Add a root node.
node = dcselectview.Nodes.Add(String.Format(general.parent));
foreach (var ser in general.child)
{
// Add a node as a child of the previously added node.
node = node.Nodes.Add(String.Format(ser.Attribute("name").Value));
}
}
it reads the file and all details are updated but not in a proper way. rather it is shown as below:
Needed:
I want the parent element to be on top and down-right to it,the child elements. If possible, it would be nice if I dont have checkboxes for parent elements.
Any help would be really appreciated..
EDIT:
My code edited. Now I am getting as shown in new picture below:
I want the 2 black lines to be in same line,not as child node of another..
Do you want a hierarchical structure, like this?
If so, I recommend you to look at the Treeview:
http://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.checkboxes.aspx
Try this you will get
XDocument doc = XDocument.Load(#"D:\\test.xml");
IEnumerable<XElement> Xele = doc.XPathSelectElements("//general");
foreach (XElement xe in Xele.Descendants())
{
//MessageBox.Show(xe.Attribute("name").Value);
dcselectview.Parent.Text =xe.Parent.Attribute("name").Value; // here parent value ----> name="1" and name="2"
dcselectview.Nodes.Add(xe.Attribute("name").Value); // ser1 ser2 ser1 ser2
}
Try this:
public static class TreeViewExtension
{
public static bool LoadNodesFromXML(this TreeView tv, string xml)
{
try
{
XDocument doc = XDocument.Parse(xml);
TreeNode rootNode = new TreeNode();
rootNode.Text = doc.Root.ToString().Split('>')[0] + ">";
rootNode.LoadTreeNodes(doc.Root.Elements());
tv.Nodes.Add(rootNode);
return true;
}
catch { return false; }
}
public static void LoadTreeNodes(this TreeNode parentNode, IEnumerable<XElement> elements)
{
foreach (var e in elements) {
TreeNode childNode = new TreeNode();
childNode.Text = e.ToString().Split('>')[0] + ">";
parentNode.Nodes.Add(childNode);
childNode.LoadTreeNodes(e.Elements());
}
}
}
//Usage:
var yourInputXMLString = "<servers><general name=\"1\"><service name=\"ser1\"/>" +
"<service name=\"ser2\"/></general><general name=\"2\">" +
"<service name=\"ser1\"/><service name=\"ser2\"/>" +
"</general></servers>";
treeView1.LoadNodesFromXML(yourInputXMLString);
You have to add parent as a node first
public static bool LoadNodesFromXML()
{
XDocument doc = XDocument.Load(#"D:\\path.xml");
var root = doc.Root;
var childenode = dcselectview.Nodes.Add(root.Attribute("Name").Value);
foreach (var xElement in root .Elements())
{
InsertNode(childenode, xElement);
}
}
private void InsertNode(TreeNode parent, XElement element)
{
var childenode = parent.Nodes.Add(element.Attribute("Name").Value);
if(element.Elements().Count() > 0)
foreach (var xElement in element.Elements())
{
InsertNode(childenode, xElement);
}
}
Thanks all for your help::But I have found another solution of my own::
XDocument doc = XDocument.Load(#"path\\test.xml");
// Add nodes to treeView1.
TreeNode pnode;
TreeNode cnode;
var gnrl = from general in doc.Descendants("general")
select new
{
parent = general.Attribute("name").Value,
child = general.Descendants("service")
};
//Loop through results
foreach (var general in gnrl)
{
// Add a root node.
pnode = treeview.Nodes.Add(String.Format(general.parent));
foreach (var ser in general.child)
{
// Add a node as a child of the previously added node.
cnode = pnode.Nodes.Add(String.Format(ser.Attribute("name").Value));
}
}
Related
I am getting output xml format in that can able to access appointment-nbr, but I am not able to eqid. How can I get slot-start,slot-end,eqid.
> <appointment-nbr>494</appointment-nbr> <slot
> slot-start="2018-07-16T12:31:00" slot-end="2018-07-16T13:00:00" />
> <appointment requires-xray="false" /> <container eqid="ASWU2705080" />
This is my code:
foreach (XmlNode node in appointmentsresponce){
XmlElement flightEle = (XmlElement)node;
XmlNodeList appointmentnbr = flightEle.GetElementsByTagName("appointment-nbr");
XmlNodeList containerNodeList = flightEle.GetElementsByTagName("container");
}
Try (I'm guessing a bit since you didn't post the full data):
foreach (XElement level1Element in XElement.Load(#"your_file.xml").Elements("appointment-nbr"))
{
foreach (XElement level2Element in level1Element.Elements("slot"))
{
Console.WriteLine(level1Element.Attribute("slot-start").Value);
}
}
Simple call GetAttribute("AttributeName") on your XmlElement
So:
var slotXml = appointmentsresponce.SelectSingleNode("//slot")
var startAttr = slotXml.GetAttribute("slot-start")
var endAttr = slotXml.GetAttribute("slot-end")
var containerXml = appointmentsresponce.SelectSingleNode("//container ")
var eqidAttr = containerXml .GetAttribute("eqid")
I have program which add and remove unwanted chapter from tree view. Everything I am writing to file, which later is generated to PDF. First of all, here is my code of files writing:
private void button3_Click(object sender, EventArgs e)
{
{
var header = File.ReadAllText(#"C:\dir\header.tex");
var footer = File.ReadAllText(#"C:\dir\footer.tex");
var sb = new StringBuilder();
sb.AppendLine(header);
foreach (TreeNode node in treeView1.Nodes)
{
var tag = node.Tag as string;
sb.AppendLine(string.IsNullOrEmpty(Text) ? node.Text : tag);
}
sb.AppendLine(footer);
File.WriteAllText(#"C: \dir\final.tex", sb.ToString());
}
{
var chapaheader = File.ReadAllText(#"C:\dir\chapaheader.tex");
var sba = new StringBuilder();
sba.AppendLine(chapaheader);
foreach (TreeNode node in treeView1.Nodes)
{
foreach (TreeNode child in node.Nodes)
{
var tag = child.Tag as string;
sba.AppendLine(string.IsNullOrEmpty(Text) ? child.Text : tag);
}
File.WriteAllText(#"C: \dir\chapterA.tex", sba.ToString());
}
I have about 5chapter and I dont know how to write each chapters sections in right chapters file. For now my program is doing great by adding right chapters to main file, but chapters A file is full of others chapter sections and chapters B,C,D,E is empty. So I think I need to make it hierarchic foreach loop. Maybe some could help me?
Thanks.
You can try with this code , recursive method
IEnumerable<TreeNode> Iterate(TreeNodeCollection nodes)
{
foreach(TreeNode node in nodes)
{
yield return node;
foreach (var child in Iterate(node.Nodes)
{
yield return child;
}
}
}
i'm trying to read xml file and update all it's value my xml was
<adf>
<prospect>
<requestdate>2015-10-29 07-38-22</requestdate>
<id sequence="1" source="admin.ss.com">admin.ss.com</id>
<vehicle interest="buy" status="">
<id sequence="1" source=""></id>
<year></year>
<make></make>
<model>camry</model>
<vin></vin>
<stock></stock>
<trim></trim>
</vehicle>
<customer>
<contact primarycontact="1">
<name part="first">Jessica</name>
<name part="last">Sonntag</name>
<email>js#test.com</email>
<phone type="phone" time="day">555-585-5555</phone>
<address>
<street line="1"></street>
<city></city>
<regioncode></regioncode>
<postalcode></postalcode>
<country></country>
</address>
</contact>
<comments>Vehicle Year: 2011 Comments: </comments>
</customer>
<provider>
<name part="full">ST</name>
<service> Engine Marketing</service>
<phone>1-866-572-3952</phone>
</provider>
</prospect>
</adf>
so i select node like below
var items = (from item in xmlDoc.Descendants("requestdate")
select item).ToList();
then i can update only requestdata tag value so do i have to repeat same for all tags or is there any good way to accomplish this.
Regards
There is an easy way to do this. This one is a hidden gem. Most people may not know this. This feature came in VS2013 and it's called "Paste XML as Classes."
Save your xml (Ex: MyXml.XML)
Create a new Console project
Open the Xml in Visual studio
Copy All contents of the xml (Ctl+A, Ctl + C)
Add a new class to your project. You can give any name you like.
Go to Edit>Paste Special>Paste XML as classes.
Add another class to your project. Then add below two methods to that class.
public static string Serialise<T>(T serialisableObject)
{
var doc = new XmlDocument();
using (var stream = new StringWriter())
{
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlWriter xmlWriter = XmlWriter.Create(stream, settings);
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(xmlWriter, serialisableObject, ns);
doc.LoadXml(stream.ToString());
}
return doc.InnerXml;
}
public static T Deserialise<T>(string xml)
{
T list;
using (var reader = new StringReader(xml))
{
var serialiser = new XmlSerializer(typeof(T));
list = (T)serialiser.Deserialize(reader);
}
return list;
}
Then in your console applications Main method; add this.
var myObj = new adf();
myObj.prospect = new adfProspect();
myObj.prospect.customer = new adfProspectCustomer(){comments = "dgsrtetetete"};
//populate all fields.....
var xml = MySerializer.Serialise(myObj);
File.WriteAllText(#"C:\myNewXml.xml", xml);
That's it. Same way now you can deserialise an xml object in to your class.
Try the XmlSerializer class: https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer(v=vs.110).aspx If you serialize/deserialize the xml then up dating is trivial.
If you wanted to change every phone number to "0123456789" you could do something like:
var xDoc = XDocument.Load("document.xml");
var results = from phone in xDoc.Descendants("phone") select phone;
foreach (XElement result in results)
{
element.SetValue("0123456789");
}
i have came up with solution with support two extension method i'm iterating all nodes and update.(since my xml is not too big or complicated this one would be a good solution)
with help of these two extension methods
public static void IterateThroughAllNodes(this XmlDocument doc, Action<XmlNode> elementVisitor)
{
if (doc != null && elementVisitor != null)
{
foreach (XmlNode node in doc.ChildNodes)
{
DoIterateNode(node, elementVisitor);
}
}
}
public static void IterateThrough(this XmlNodeList nodes, Action<XmlNode> elementVisitor)
{
if (nodes != null && elementVisitor != null)
{
foreach (XmlNode node in nodes)
{
DoIterateNode(node, elementVisitor);
}
}
}
private static void DoIterateNode(XmlNode node, Action<XmlNode> elementVisitor)
{
elementVisitor(node);
foreach (XmlNode childNode in node.ChildNodes)
{
DoIterateNode(childNode, elementVisitor);
}
}
then i can update my xml nodes as below
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("~/xmlmail.xml"));
var email = new XmlEmail();
doc.IterateThroughAllNodes(
delegate(XmlNode node)
{
if (node.Name.Equals("requestdate"))
node.InnerText= email.RequestDate.ToLongDateString();
if (node.Name.Equals("vehicle"))
{
XmlNodeList childs = node.ChildNodes;
childs.IterateThrough(delegate(XmlNode vnode)
{
if (vnode.Name.Equals("id"))
vnode.InnerText= email.VehicleId.ToString();
if (vnode.Name.Equals("year"))
vnode.InnerText= email.Year.ToString();
if (vnode.Name.Equals("make"))
vnode.InnerText= email.Make;
if (vnode.Name.Equals("model"))
vnode.InnerText= email.Model;
if (vnode.Name.Equals("vin"))
vnode.InnerText= email.Vin;
if (vnode.Name.Equals("trim"))
vnode.InnerText = email.Trim;
});
}
if (node.Name.Equals("customer"))
{
XmlNodeList childs = node.ChildNodes;
childs.IterateThrough(delegate(XmlNode vnode)
{
if (vnode.Attributes != null && (vnode.Name.Equals("name") && vnode.Attributes["part"].Value.Equals("first")))
vnode.InnerText= email.FirstName;
if (vnode.Attributes != null && (vnode.Name.Equals("name") && vnode.Attributes["part"].Value.Equals("last")))
vnode.InnerText= email.LastName;
if (vnode.Name.Equals("email"))
vnode.InnerText= email.Email;
if (vnode.Name.Equals("phone"))
vnode.InnerText= email.Phone;
if (vnode.Name.Equals("comments"))
vnode.InnerText= email.Comments;
if (vnode.Name.Equals("address"))
{
XmlNodeList addresschilds = vnode.ChildNodes;
addresschilds.IterateThrough(delegate(XmlNode anode)
{
if (anode.Name.Equals("street"))
anode.InnerText= email.Street;
if (anode.Name.Equals("city"))
anode.InnerText= email.City;
if (anode.Name.Equals("phone"))
anode.InnerText= email.Phone;
if (anode.Name.Equals("regioncode"))
anode.InnerText= email.RegionCode;
if (anode.Name.Equals("postalcode"))
anode.InnerText= email.Postalode;
if (anode.Name.Equals("country"))
anode.InnerText= email.Country;
});
}
});
}
});
I am having trouble while load xml file into Observable Collection.
My XML look like
<?xml version="1.0" encoding="utf-8"?>
<Stock>
<Assortment>
<Item>Адельфан - эзидрекс таб №10</Item>
<Quantity>89</Quantity>
<Price>3.0000</Price>
<Summ>267</Summ>
<Price1>3.0000</Price1>
<Summ1>267</Summ1>
<ValidDate>01.01.2031</ValidDate>
<Manufacturer>КРКА</Manufacturer>
</Assortment>
<Assortment>
<Item>Адельфан - эзидрекс таб №10</Item>
<Quantity>8</Quantity>
<Price>3.0000</Price>
<Summ>24</Summ>
<Price1>3.0000</Price1>
<Summ1>24</Summ1>
<ValidDate>01.01.2019</ValidDate>
<Manufacturer>КРКА</Manufacturer>
</Assortment>
</Stock>
And my code which I tried is this.
XDocument xml = XDocument.Load(filename);
foreach (XElement xe in xml.Elements("Assortment"))
{
_dummyCollection1.Add(new DummyClass1()
{
Наименование = xe.Element("Item").Value,
Количество = xe.Element("Quantity").Value,
Цена = xe.Element("Price").Value,
Сумма = xe.Element("Summ").Value,
Цена1 = xe.Element("Price1").Value,
Сумма1 = xe.Element("Summ1").Value,
Срокгодности = xe.Element("ValidDate").Value,
Производитель = xe.Element("Manufacturer").Value
});
}
BuyDataGrid.ItemsSource = _dummyCollection1;
I am getting empty DataGrid. How to pass xml in to Observable Collection?
I found how to do it, in case if someone need;
XmlDocument doc = new XmlDocument();
doc.Load(filename);
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("Assortment");
foreach (XmlNode node in nodes)
{
_dummyCollection1.Add(new DummyClass1()
{
Наименование = node["Item"].InnerText,
Количество = node["Quantity"].InnerText,
Цена = node["Price"].InnerText,
Сумма = node["Summ"].InnerText,
Цена1 = node["Price1"].InnerText,
Сумма1 = node["Summ1"].InnerText,
Срокгодности = node["ValidDate"].InnerText,
Производитель = node["Manufacturer"].InnerText
});
}
BuyDataGrid.ItemsSource = _dummyCollection1;
Your class which you plan to use as an object for the ObservableCollection collection must implement INotifyPropertyChanged
this is my answer with an example how to populate model for dataGrid
example
Currently I have the following code:
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
foreach (int i in tweets)
{
if (tweets[i].InnerText.Length > 0)
{
MessageBox.Show(tweets[i].InnerText);
}
}
Which doesn't work, it gives me System.InvalidCastException on the foreach line.
The following code works perfectly (no foreach, the i is replaced with a zero):
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
if (tweets[0].InnerText.Length > 0)
{
MessageBox.Show(tweets[0].InnerText);
}
I know that there is already a marked answer, but you can do it like you did in your first try, you just need to replace the int with XmlNode
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
foreach (XmlNode i in tweets)
{
if (i.InnerText.Length > 0)
{
MessageBox.Show(i.InnerText);
}
}
tweets is a node list. I think that what you're trying to do is this:
XmlDocument xDoc = new XmlDocument();
xDoc.Load("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter");
XmlNodeList tweets = xDoc.GetElementsByTagName("text");
for (int i = 0; i < tweets.Count; i++)
{
if (tweets[i].InnerText.Length > 0)
{
MessageBox.Show(tweets[i].InnerText);
}
}
It is not of Int type, That is the reason you are getting a casting exception. You can either replace int with the appropriate type or simply make use of type inference (implicitly typed variables) to handle this. Here i am using typeinference.by saying type as var, The compiler will understand it is of type of the iterator variable in tweets collection
foreach (var i in tweets)
{
if (i!=null)
{
string tweet= (((System.Xml.XmlElement)(i))).InnerText;
MessageBox.Show(tweet);
}
}
EDIT : With the Wonderful LINQtoXML, Your code can be rewritten like this.
string url = "http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=twitter";
XElement elm = XElement.Load(url);
if (elm != null)
{
foreach (var status in elm.Elements("status"))
{
string tweet = status.Element("text").Value;
MessageBox.Show(ss);
}
}
All the answers seem to be a bit outdated Imperative examples so I will add a declarative one. This is not doing what the OP wanted but I'm sure you'll get the point.
public static List<System.Xml.XmlNode> toList(System.Xml.XmlNodeList nodelist){
List<System.Xml.XmlNode> nodes = new List<System.Xml.XmlNode>();
foreach (System.Xml.XmlNode node in nodelist)
{
nodes.Add(node);
}
return nodes;
}
public static ReadMeObject setXml(ReadMeObject readmeObject){
readmeObject.xmlDocument = new System.Xml.XmlDocument();
readmeObject.xmlDocument.LoadXml("<body>"+readmeObject.htmlStringContent+"</body>");
System.Xml.XmlNodeList images = readmeObject.xmlDocument.SelectNodes("//img");
Array.ForEach(
Functions.toList( images )
.Where((image) => image.Attributes != null)
.Where((image) => image.Attributes["src"] != null)
.Where((image) => image.Attributes["src"].Value != "")
.ToArray()
, (image) => {
Console.WriteLine(image.Attributes["src"].Value);
}
);
return readmeObject;
}
foreach (XmlNode node in tweets)
{
if (tweets[i].InnerText.Length > 0)
{
MessageBox.Show(tweets[node].InnerText);
}
}
I've changed the 'I', which you cannot use, to XmlNode, which selects a single line of your list.
You can loop through the Collection with .GetEnumerator()
this code is taken Microsoft Documentation :
XmlNodeList elemList = root.GetElementsByTagName("title");
IEnumerator ienum = elemList.GetEnumerator();
while (ienum.MoveNext()) {
XmlNode title = (XmlNode) ienum.Current;
Console.WriteLine(title.InnerText);
}
Use this simple extension method to iterate through XmlNodeList:
public static void ForEachXml<TXmlNode>(this XmlNodeList nodeList, Action<TXmlNode> action)
{
foreach (TXmlNode node in nodeList) action(node);
}
Method Call:
xDoc.GetElementsByTagName("text").ForEachXML<XmlNode>(tweet =>
{
if (tweet.InnerText.Length > 0)
MessageBox.Show(tweet.InnerText);
});