I want to add a new node to my xml file, but also, i would like to add id value in it, but incremented by 1 from the last value. Here is my XML:
<users>
<user>
<id>1</id>
<name>Name1</name>
<surname>Surname1</surname>
<weight>78</weight>
<height>180</height>
</user>
<user>
<id>2</id>
<name>Name2</name>
<surname>Surname2</surname>
<weight>84</weight>
<height>180</height>
</user>
</users>
And here is my code so far (for adding a new node):
XmlNode node = xmlDoc.SelectSingleNode("/users/user");
XmlNode newNode = xmlDoc.ImportNode(node, true);
xmlDoc.DocumentElement.AppendChild(newNode);
xmlDoc.SelectSingleNode("users/user/id").InnerText = ; // <-- ??
xmlDoc.SelectSingleNode("users/user/name").InnerText = nameBox.Text;
xmlDoc.SelectSingleNode("users/user/surname").InnerText = surnameBox.Text;
xmlDoc.SelectSingleNode("users/user/weight").InnerText = Convert.ToString(weightUpDown.Value);
xmlDoc.SelectSingleNode("users/user/height").InnerText = Convert.ToString(heightUpDown.Value);
I am using winforms in C#, in this case get the value from the text boxes and UpDown lists.
How can I do it in c#?
You can use LINQ to XML for that.First get the current element count, then insert a new element like this:
var xDoc = XDocument.Load("path");
var count = xDoc.Descendants("user").Count();
var newUser = new XElement("user",
new XElement("id", count+1),
new XElement("name", nameBox.Text),
new XElement("surname", surnameBox.Text),
new XElement("weight", weightUpDown.Value),
new XElement("height", heightUpDown.Value));
xDoc.Root.Add(newUser);
xDoc.Save(path);
I would suggest you to get element count first (maybe in Form_load) then store it into a variable.By doing that you don't need to perform this query each time you want to add new item.You just need to increment the count.
You can get the max id as follows:
var maxId = xmlDoc.SelectNodes("/users/user/id")
.Cast<XmlNode>()
.Max(node => int.Parse(node.InnerText));
using the count to determine the Id may not work correctly if nodes are removed from the XML, during execution of the program.
Use Guid.NewGuid() instead to create a unique ID
I think I need some more information...
At first glance it looks like you will need to do the following:
Iterate / loop through the values in text boxes and/or UpDown Lists.
Make sure your loop has a counter variable that is created outside of the loop "int counter = 1".
For each item you are iterating through use the counter to set the id in the xml you are generating.
Before the item goes back to looping you should then increment the counter + 1.
You will be auto-populating each node with the values anyways correct?
All you will need is to add this counter variable and you should have basically what you need.
Related
I searched a long time in order to get an answer but as i can see is not working.
I have an XML File and I would like to read a specific element from a node.
For example, this is the XML:
<Root>
<TV>
<ID>2</ID>
<Company>Samsung</Company>
<Series>13523dffvc</Series>
<Dimesions>108</Dimesions>
<Type>LED</Type>
<SmartTV>Yes</SmartTV>
<OS>WebOS</OS>
<Price>1993</Price>
</TV>
</Root>
I want to get the ID element in the code as a variable so i can increment it for the next item which i will add.
This is the code at this moment, but i can not find a way to select something from the item itself.
XDocument doc = XDocument.Load("C:TVList.XML");
XElement TV = doc.Root;
var lastElement = TV.Elements("TV").Last()
A query for the last TV's id (this will return 0 if there are no elements):
var lastId = (int) doc.Descendants("TV")
.Elements("ID")
.LastOrDefault();
You might also want the highest id (in case they're not in order):
var maxId = doc.Descendants("TV")
.Select(x => (int)x.Element("ID"))
.DefaultIfEmpty(0)
.Max();
See this fiddle for a working demo.
Use like this to get id value
XDocument doc = XDocument.Load(#"C:\TVList.XML");
XElement root = doc.Element("Root");
XElement tv = root.Element("TV");
XElement id = tv.Element("ID");
string idvalue = id.Value;
also make your <Type>LED</Tip> tag of xml to <Type>LED</Type> for match
I have XML Document like
<Records>
<Record>
<Event>Home Value Submits Page 2</Event>
<Date>17-Mar-14 4:49:32 PM</Date>
</Record>
<Record>
<Event>Hm Value Submits Hm Pg</Event>
<Date>17-Mar-14 4:54:36 PM</Date>
</Record>
</Records>
I need to delete last 30 Days nodes from XML Document.
I am using this code but it's not working,
var xelement = XElement.Load(Server.MapPath("~/XMLStorage/DataBase.xml"));
var value30days =
from nm in xelement.Elements("Record")
where (DateTime)nm.Element("Date") <= DateTime.Now && (DateTime)nm.Element("Date") >= DateTime.Now.AddDays(-30)
select nm;
foreach (XElement xEle in value30days)
{
xEle.Remove();
}
xelement.Save(Server.MapPath("~/XMLStorage/DataBase.xml"));
Please Give some solutions.
This is one of those fun problems caused by changing a collection while enumerating/querying it. As soon as you try to remove the first item you break the query.
Try this:
foreach (XElement xEle in value30days.ToArray())
{
xEle.Remove();
}
The ToArray call will ensure that the entire set of results is returned before you start modifying the XML content. You can then iterate through the array and delete as many of those items as you like without the loop breaking.
Considering the following XML:
<Stations>
<Station>
<Code>HT</Code>
<Type>123</Type>
<Names>
<Short>H'bosch</Short>
<Middle>Den Bosch</Middle>
<Long>'s-Hertogenbosch</Long>
</Names>
<Country>NL</Country>
</Station>
</Stations>
There are multiple nodes. I need the value of each node.
I've got the XML from a webpage (http://webservices.ns.nl/ns-api-stations-v2)
Login (--) Pass (--)
Currently i take the XML as a string and parse it to a XDocument.
var xml = XDocument.Parse(xmlString);
foreach (var e in xml.Elements("Long"))
{
var stationName = e.ToString();
}
You can retrieve "Station" nodes using XPath, then get each subsequent child node using more XPath. This example isn't using Linq, which it looks like you possibly are trying to do from your question, but here it is:
XmlDocument xml = new XmlDocument();
xml.Load(xmlStream);
XmlNodeList stations = xml.SelectNodes("//Station");
foreach (XmlNode station in stations)
{
var code = station.SelectSingleNode("Code").InnerXml;
var type = station.SelectSingleNode("Type").InnerXml;
var longName = station.SelectSingleNode("Names/Long").InnerXml;
var blah = "you should get the point by now";
}
NOTE: If your xmlStream variable is a String, rather than a Stream, use xml.LoadXml(xmlStream); for line 2, instead of xml.Load(xmlStream). If this is the case, I would also encourage you to name your variable to be more accurately descriptive of the object you're working with (aka. xmlString).
This will give you all the values of "Long" for every Station element.
var xml = XDocument.Parse(xmlStream);
var longStationNames = xml.Elements("Long").Select(e => e.Value);
Load function is already defined in xmlData class
public class XmlData
{
public void Load(XElement xDoc)
{
var id = xDoc.XPathSelectElements("//ID");
var listIds = xDoc.XPathSelectElements("/Lists//List/ListIDS/ListIDS");
}
}
I'm just calling the Load function from my end.
XmlData aXmlData = new XmlData();
string input, stringXML = "";
TextReader aTextReader = new StreamReader("D:\\test.xml");
while ((input = aTextReader.ReadLine()) != null)
{
stringXML += input;
}
XElement Content = XElement.Parse(stringXML);
aXmlData.Load(Content);
in load function,im getting both id and and listIds as null.
My test.xml contains
<SEARCH>
<ID>11242</ID>
<Lists>
<List CURRENT="true" AGGREGATEDCHANGED="false">
<ListIDS>
<ListID>100567</ListID>
<ListID>100564</ListID>
<ListID>100025</ListID>
<ListID>2</ListID>
<ListID>1</ListID>
</ListIDS>
</List>
</Lists>
</SEARCH>
EDIT: Your sample XML doesn't have an id element in the namespace with the nss alias. It would be <nss:id> in that case, or there'd be a default namespace set up. I've assumed for this answer that in reality the element you're looking for is in the namespace.
Your query is trying to find an element called id at the root level. To find all id elements, you need:
var tempId = xDoc.XPathSelectElements("//nss:id", ns);
... although personally I'd use:
XDocument doc = XDocument.Parse(...);
XNamespace nss = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";
// Or use FirstOrDefault(), or whatever...
XElement idElement = doc.Descendants(nss + "id").Single();
(I prefer using the query methods on LINQ to XML types instead of XPath... I find it easier to avoid silly syntax errors etc.)
Your sample code is also unclear as you're using xDoc which hasn't been declared... it helps to write complete examples, ideally including everything required to compile and run as a console app.
I am looking at the question 3 hours after it was submitted and 41 minutes after it was (last) edited.
There are no namespaces defined in the provided XML document.
var listIds = xDoc.XPathSelectElements("/Lists//List/ListIDS/ListIDS");
This XPath expression obviously doesn't select any node from the provided XML document, because the XML document doesn't have a top element named Lists (the name of the actual top element is SEARCH)
var id = xDoc.XPathSelectElements("//ID");
in load function,im getting both id and and listIds as null.
This statement is false, because //ID selects the only element named ID in the provided XML document, thus the value of the C# variable id is non-null. Probably you didn't test thoroughly after editing the XML document.
Most probably the original ID element belonged to some namespace. But now it is in "no namespace" and the XPath expression above does select it.
string xmldocument = "<response xmlns:nss=\"http://schemas.microsoft.com/SQLServer/reporting/reportdesigner\"><action>test</action><id>1</id></response>";
XElement Content = XElement.Parse(xmldocument);
XPathNavigator navigator = Content.CreateNavigator();
XmlNamespaceManager ns = new XmlNamespaceManager(navigator.NameTable);
ns.AddNamespace("nss", "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");
var tempId = navigator.SelectSingleNode("/id");
The reason for the null value or system returned value is due to the following
var id = xDoc.XPathSelectElements("//ID");
XpathSElectElements is System.xml.linq.XElment which is linq queried date. It cannot be directly outputed as such.
To Get individual first match element
use XPathSelectElement("//ID");
You can check the number of occurrences using XPathSelectElements as
var count=xDoc.XPathSelectElements("//ID").count();
you can also query the linq statement as order by using specific conditions
Inorder to get node value from a list u can use this
foreach (XmlNode xNode in xDoc.SelectNodes("//ListIDS/ListID"))
{
Console.WriteLine(xNode.InnerText);
}
For Second list you havnt got the value since, the XPath for list items is not correct
I'm trying to populate an array with the following xml:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<data>
<item>
<date>1307018090</date>
<price>10.4718867</price>
<low>10.38100000</low>
<high>10.49000000</high>
<nicedate>14:39</nicedate>
</item>
<item>
...
</item>
and so on
I'm using this Linq-query, which to me means that It'll create one object per :
var items = from item in doc.Element("data").Descendants()
select new Currency
{
Close = item.Element("price").Value.ToString(),
Date = item.Element("date").Value.ToString(),
Low = item.Element("low").Value.ToString(),
High = item.Element("high").Value.ToString(),
Time = item.Element("nicedate").Value.ToString()
};
And when I foreach through items, only one item gets selected. I'm not very used to Linq so I can't figure out how to properly construct this statement. Any suggestions?
You need to start the Linq-Xml like so
var items =
from item in
doc.Element("data")
.Elements("item")
Descedants() method returns not only children, but also grand-children, grand-grand-children etc. So, the second tag that gets processed by LINQ is your first <item>'s <date> and it isn't processed (I think there should be an exception here, can't check at the moment).
Replace your Descedants() call to Elements("item"), as suggested by #DaveShaw