Check if Xml Element exists before/during a foreach loop - c#

I started learning C# this month and I'm creating a program to parse XML file and get some data. The .xml file is:
<Info>
<Symbols>
<Symbol>
<Name>Name</Name>
<Type>INT</Type>
</Symbol>
<Symbol>
<Name>Name</Name>
<Type>INT</Type>
<Properties>
<Property>
<Name>TAG</Name>
</Property>
</Properties>
</Symbol>
</Symbols>
</Info>
My code below, gets values from elements "Name" and "Type", from "Symbol". But I need to check if the element "Properties" exists in each "Symbol", because, as you can see, there will be some (like the first "Symbol") without the "Properties" element.
If it exists, I will get the value from , in this case: "TAG".
Is there a simple way to make the foreach try to get it only if it exists?!
var symbols = from symbol in RepDoc.Element("Info").Element("Symbols").Descendants("Symbol")
select new
{
VarName = symbol.Element("Name").Value,
VarType = symbol.Element("Type").Value,
};
foreach (var symbol in symbols)
{
Console.WriteLine("" symbol.VarName + "\t" + symbol.VarType);
}
Thank you in advance ^^

var res = XDocument.Load(fname)
.Descendants("Symbol")
.Select(x => new
{
Name = (string)x.Element("Name"),
Type = (string)x.Element("Type"),
Props = x.Descendants("Property")
.Select(p => (string)p.Element("Name"))
.ToList()
})
.ToList();
Props will have zero or more elements depending on the Properties tag.

Related

i want to fetch array of record in xml using c# Linq

this is my code to fetch xml values from files and it does successfully but single element like an in file type but when i try to fetch array of records from xml it failed
public void readXmlFiles()
{
var xml = XDocument.Load(#"C:\Applications\Files\Xmldemo.xml");
var format = from r in xml.Descendants("insureance")
select new
{
type = r.Element("type").Value,
// values=r.Element("value").Value
};
foreach (var r in format)
{
Console.WriteLine(r.values);
}
}
this is my xml file
<?xml version="1.0" encoding="UTF-8"?>
<insureance>
<type>Risk</type>
<classofbusiness type="array">
<value>0</value>
<value>1</value>
<value>2</value>
</classofbusiness>
</insureance>
now i want to fetch classofbusiness all values thanx in advance
Your current attempt selects a single value element, which doesn't exist as a child of insureance. I would guess you get a null reference exception as a result.
You need to follow the structure of the document
var format =
from ins in doc.Descendants("insureance")
select new
{
Type = (string) ins.Element("type"),
ClassOfBusiness = ins.Elements("classofbusiness")
.Elements("value")
.Select(x => (int) x)
.ToArray()
};
var format = xml.Elements("insureance").Elements("classofbusiness").Descendants();

Multiple child elements of XML into one line of combobox

I have some XML that looks similar to this:
<SolutionString>
<Solutions>
<Solution>
<ID>1</ID>
<Property>
<Name>DriverSheave</Name>
<Value>1VP34</Value>
</Property>
<Property>
<Name>DriverBushing</Name>
<Value>
</Value>
</Property>
<Property>
<Name>DrivenSheave</Name>
<Value>AK49</Value>
</Property>
<Property>
<Name>DrivenBushing</Name>
<Value>
</Value>
</Property>
</Solution>
<Solution>
<ID>2</ID>
For every ID number, the example above includes ID 1. I'd like to include all of its child elements into one line of a combobox.
To look similar to this
DriverSheave = 1vp34, Driver Bushing = (nothing)/0, DrivenSheave = AK49,
etc...
I have looked at Getting XML data into combobox, but it only shows how to get single items from XML into combo boxes.
So, for each entry, we have:
A Solution element containing:
An ID element
Some Property elements containing:
A Name element
A Value element (optional)
I would first transform the XML to that structure in memory, and then you can convert it to strings. A LINQ query should make that easy - you could either create classes, or just use anonymous types if this is all you need it for:
var doc = XDocument.Load(file);
var solutions = docs
.Descendants("Solution")
.Select(x => new {
ID = (string) x.Element("ID"),
Properties = x.Elements("Property").Select(p => new {
Name = (string) p.Element("Name"),
Value = (string) p.Element("Value")
}).ToList()
}).ToList();
Then you could use:
var items = solutions
.Select(s => new {
ID = s.ID,
Text = string.Format("{0}. {1}", s.ID,
string.Join(", ", s.Properties
.Select(p => string.Format("{0} = {1}",
p.Name,
p.Value ?? "(nothing/0)"))))
}).ToArray();
comboBox.DisplayMember = "Text";
comboBox.ValueMember = "ID";
comboBox.Items.AddRange(items);
(This is untested, and it may have some bracket mismatches, but should give you the basic idea.)

List is empty after parsing XML with LinQ

I have an xml file similar to the following:
<doc>
<file>
<header>
<source>
RNG
</source>
</header>
<body>
<item name="items.names.id1">
<property>propertyvalue1</property>
</item>
<!-- etc -->
<item name="items.names.id100">
<property>propertyvalue100</property>
</item>
<!-- etc -->
<item name="otheritems.names.id100">
<property>propertyvalue100</property>
</item>
</body>
</file>
</doc>
And the following class:
private class Item
{
public string Id;
public string Property;
}
The file has, for example, 100 item entries (labeled 1 to 100 in the name attribute). How can I use Linq Xml to get hold of these nodes and place them a in list of item?
Using Selman22's example, I'm doing the following:
var myList = xDoc.Descendants("item")
.Where(x => x.Attributes("name").ToString().StartsWith("items.names.id"))
.Select(item => new Item
{
Id = (string)item.Attribute("name"),
Name = (string)item.Element("property")
}).ToList();
However, the list is empty. What am I missing here?
Using LINQ to XML:
XDocument xDoc = XDocument.Load(filepath);
var myList = xDoc.Descendants("item").Select(item => new Item {
Id = (string)item.Attribute("name"),
Property = (string)item.Element("property")
}).ToList();
You can use LinqToXml to directly query the XML, or deserialize it and use LINQ to object. If you choose to deserialize I suggest to start from the schema and generate the classes representing your datamodel with xsd.exe. If you don't have the schema of your xml, even xsd.exe can infer one from an example xml file, but you probably need to fine tune the result.
Try this one XElement root = XElement.Parse("your file name");
var items textSegs =(from item in root.Descendants("item")
select item).ToList();
Now iterate over list and store it
The below is a way of getting information from xml using Xdocument.
string input = "<Your xml>";
Xdocument doc = XDocument.Parse(input);
var data = doc.Descendants("item");
List<Items> itemsList = new List<Items>();
foreach(var item in data)
{
string itemname= item.Element("item").Value;
string property = item.Element("property").Value;
itemsList.Add(new item(itemname, property));
}
I'm guessing you want the code given how your question is phrased.. also I'm assuming the real XML is very simplistic as well.
var items = from item in doc.Descendants("item")
select new Item()
{
Id = item.Attributes("name").First().Value,
Property = item.Elements().First().Value,
};
Just ensure that your xml is loaded into doc. You can load the xml in two ways:
// By a string with xml
var doc = XDocument.Parse(aStringWithXml);
// or by loading from uri (file)
var doc = XDocuemnt.Load(aStringWhichIsAFile);

Retrieving a Deeply Nested Value in an XML File

I'm trying to read a property in an XML file using C# and LINQ XML and I can't retrieve a value that is deeply nested in the tree. The value I'm trying to get is the contents of <Value> near <DisplayName>Add Your Comments</DisplayName>. Every <OrderProduct id=???> may have its own comments.
I can read other properties in the XML file using LINQ, but I'm confused how to go about reading something so deeply nested.
Thanks.
<?xml version="1.0" encoding="utf-16"?>
<OrderXml>
<Order>
<OrderProducts>
<OrderProduct id="1">
.
.
.
</OrderProduct>
<OrderProduct id="2">
<PropertyValues>
<PropertyValue>
<Property id="10786">
<DisplayName>Base</DisplayName>
</Property>
<Value />
</PropertyValue>
<PropertyValue>
<Property id="10846">
<DisplayName>Add Your Comments</DisplayName>
</Property>
<Value>this is a comment</Value>
</PropertyValue>
</PropertyValues>
</OrderProduct>
</OrderProducts>
</Order>
</OrderXml>
This is the code I have so far. I can retrieve the "Add Your Comments" part, but I'm stuck in how to get the part that follows it.
string productOrderID = "";
string productName = "";
XElement xelement;
xelement = XElement.Load (#"D:\Order.xml");
IEnumerable<XElement> Products = xelement.Descendants ("OrderProduct");
foreach (var order in Products)
{
productOrderID = order.Attribute ("id").Value;
productName = order.Element ("Product").Element ("Name").Value;
Console.WriteLine ("productOrderID: {0}", productOrderID);
Console.WriteLine ("productName: {0}", productName);
Console.WriteLine ("");
IEnumerable<XElement> PropertyValues = xelement.Descendants ("PropertyValues").Elements ("PropertyValue");
foreach (var propValue in PropertyValues.Elements ("Property").Elements ("DisplayName"))
{
Console.WriteLine ("Property ID: {0}", propValue.Value);
if (propValue.Value == "Add Your Comments")
{
Console.WriteLine ("---");
}
}
}
You can use Descendants to search for nodes in document no matter where they are:
string name = "Add Your Comments";
var value = xdoc
.Descendants("PropertyValue")
.Where(pv => (string)pv.Element("Property").Element("DisplayName") == name)
.Select(pv => (string)pv.Element("Value"))
.FirstOrDefault();
Output:
this is a comment

C# Querying an XML Document

Good Day,
I am trying to query an XML document and have the following query:
XElement root = XElement.Load(#"..\..\Data.xml");
var entries = root.Descendants()
.Where(x => x.Name.LocalName == "Entry")
.ToList();
Console.WriteLine("There are {0} nodes...", entries.Count());
foreach (XElement v in entries)
{
Console.WriteLine(v.Value);
}
and this code works because it pulls the correct number of Entry nodes. The Entry
nodes look like:
<?xml version="1.0" encoding="UTF-8"?>
<Database xmlns="http://www.someurl.org/schemas">
<InfoFromRecord>
<BaseData>
<Entry>
<Date>2006-03-08</Date>XD
<Time>09:20:00</Time>
<EnteredBy>DNS</EnteredBy>
<TextEntry>Record 1</TextEntry>
</Entry>
<Entry>
<Date>2006-03-08</Date>
<Time>09:33:00</Time>
<EnteredBy>MW</EnteredBy>
<TextEntry>Record 2</TextEntry>
</Entry>
<Entry>
<Date>2006-03-08</Date>
<Time>08:58:00</Time>
<EnteredBy>BH</EnteredBy>
<TextEntry>Record 3</TextEntry>
</Entry>
</BaseData>
</InfoFromRecord>
</Database>
The problem is, I want to extract only the Date and Time, not all four fields.
Let's assume your entire XML file looks like this for a clear example:
<Entries>
<Entry>
<Date>2006-03-08</Date>
<Time>09:33:00</Time>
<EnteredBy>XX</EnteredBy>
<TextEntry>Test Data</TextEntry>
</Entry>
</Entries>
You could then do something like this:
var document = XDocument.Load(#"..\..\Data.xml");
var dateAndTimes =
from d in document.Root.Descendants("Entry")
select new
{
Date = d.Element("Date").Value,
Time = d.Element("Time").Value
};
From there, the dateAndTimes type will select an anonymous type of the Date and Time. You can change the anonymous type to be your own type, or something else.
EDIT: The problem is your xmlns. Change your code like so:
XNamespace namespc = "http://www.someurl.org/schemas";
var document = XDocument.Parse(xml);
var dateAndTimes =
from d in document.Root.Descendants(namespc + "Entry")
select new
{
Date = d.Element(namespc + "Date").Value,
Time = d.Element(namespc + "Time").Value
};
I haven't had a chance to try it but something like the following may give you what you are looking for
var entries = from i in root.Descendants()
where Name=='entry'
let date = i.Element('Date').Value
let time = i.ELement('Time').Value
select new Tuple<string,string>(date,time);
foreach (XElement v in entries)
{
Console.WriteLine(v.Element("Date").Value);
Console.WriteLine(v.Element("Time").Value);
}
Do not forget that Descendants finds children at any level, i.e. children, grand-children, etc where Elements find only direct child. So i guess Elements is the safe option in most of the cases.
EDIT : After seeing the XML
You need to include the Namspace also when getting the data
XNamespace ns = "http://www.someurl.org/schemas";
var entries = elm.Descendants().Where(x => x.Name.LocalName == "Entry").ToList();
foreach (XElement v in entries)
{
Console.WriteLine(v.Element(ns+"Date").Value);
Console.WriteLine(v.Element(ns+"Time").Value);
}
IEnumerable<XElement> de = from el in xdoc.Descendants() select el;
foreach (XElement el in de)
{
if (string.Equals(el.Name.ToString(), "movie",
`StringComparison.InvariantCultureIgnoreCase))`enter code here`
StringComparison.InvariantCultureIgnoreCase))
{
date(el);
}

Categories