I have next XML file:
<root>
<location id='IBM'>
<property name='locale' value='en-EN' />
<property name='path' value='c:\program files\IBM' />
<property name='option' value='licence' />
<package kind='offering' name='IBM tools'>
<property name='cic.name' value='IBM Studio'/>
<property name='cic.version' value='13.4'/>
</package>
</location>
<location id='Microsoft'>
<property name='locale' value='en-EN' />
<property name='path' value='c:\program files\MS' />
<property name='option' value='licence' />
<package kind='offering' name='Microsoft'>
<property name='cic.name' value='Windows XP'/>
<property name='cic.version' value='10.3.2'/>
</package>
</location>
</root>
How I can get this values from cic.name and cic.version inside that XML structure:
IBM Studio
13.4
Windows Xp
10.3.2
I have tried this
XElement roots = XElement.Load(#"C:\test.xml");
foreach (var i in roots.Descendants("location"))
{
Console.WriteLine(i.Attribute("id").Value);
}
But I get only:
IBM
Microsoft
Thank you!
Here is the solution
var doc = XDocument.Load(yourXmlFilePath);
var packages = doc.Descendants("package")
.Select(p => new
{
Name = p.Elements("property")
.SingleOrDefault(i => i.Attribute("name")?.Value == "cic.name")
?.Attribute("value")
?.Value,
Version = p.Elements("property")
.SingleOrDefault(i => i.Attribute("name")?.Value == "cic.version")
?.Attribute("value")
?.Value
}).ToList();
var result = names.Select(i => string.Format("{0} {1}", i.Name, i.Version)).ToList();
//result: "IBM Studio 13.4"
// "Windows XP 10.3.2"
Your code only looks for id attributes on location elements.
If you want the cic.name and cic.version values, you'll have to include those in your query instead.
var results =
from package in doc.Descendants("package")
select new
{
Name = (string) package.Elements("property")
.Where(x => (string) x.Attribute("name") == "cic.name")
.Attributes("value")
.Single(),
Version = (string) package.Elements("property")
.Where(x => (string) x.Attribute("name") == "cic.version")
.Attributes("value")
.Single(),
};
See this fiddle for a demo.
Try something like this
foreach (var Locations in roots.Descendants("location"))
{
foreach (var item in Locations.Descendants("package"))
{
Console.WriteLine(item.Attribute("id").Value);
}
}
Related
I'm trying to use LINQ to parse data from an XML file, but the code I have does not seem to work and I cannot figure out what I'm doing wrong.
Shortened version of the xml:
<Components>
....
<Component Id="b3d06054-6113-4775-9353-f48aa21295e8" ProductId="ERDDMR">
<Sections>
<ComponentSection Id="bb05507e-200d-494a-9aef-3181c039efc7" ProductSectionId="ERDDMR.Process" />
<ComponentSection Id="391aead4-cfeb-4739-b8ec-c6b12664189f" ProductSectionId="ERDDMR.Exhaust" />
</Sections>
<VariantData Type="eContact">
<Row Name="dampersize" Value="5610" Description="Return Damper Size" />
<Row Name="damperactuators" Value="1" Description="Return (0=None, 1=2-Pos, 2=MOD)" />
<Row Name="damperconstruction" Value="1" Description="Return (0=N/A, 1=VCD-23, 2=VCD-34" />
</VariantData>
</Component>
<Component Id="f4130a92-aac1-4039-a4df-83d6994ae095" ProductId="ERDSIC">
<Sections>
<ComponentSection Id="1e65f0c4-db4f-4eb7-8605-e37f9d7e6f68" ProductSectionId="ERDSIC.1" />
</Sections>
<VariantData Type="eContact">
<!-- *** Find this one, below! *** -->
<Row Name="dampersize" Value="5926" Description="MUA Damper Size" />
<Row Name="damperactuators" Value="1" Description="MUA (0=None, 1=2-Pos, 2=MOD)" />
<Row Name="damperconstruction" Value="1" Description="MUA (0=N/A, 1=VCD-23, 2=VCD-34, 3=VCD-40" />
</VariantData>
</Component>
...
</Components>
I'm trying to find the attribute Value of the Row Element that has attribute Name = "dampersize" and is a descendant of the Element "Component" whose attribute ProductId = "ERDSIC" (I identified it in the xml above)
My failed attempt is here:
var prop = xDoc.Elements("Component")
.Where(c => c.Attribute("ProductId").Value == "ERDSIC")
.Descendants("Row").Where(t => t.Attribute("Name").Value == "dampersize")
.Select(v => v.Attribute("Value").Value).FirstOrDefault();
Console.WriteLine("Result: " + prop.ToString());
The error I get is (located on the Console.WriteLine line):
System.NullReferenceException: Object reference not set to an instance of an object
EDIT - Changed "Type" to "Name" the code is still wrong
If xDoc is XDocument type:
var xDoc = XDocument.Load("test.xml");
then use the Root property:
var prop = xDoc.Root.Elements("Component")
Or change the xDoc type to XElement:
var xDoc = XElement.Load("test.xml");
Then your code will be fully working.
I suggest you cast to get value instead of use the Value property to avoid this kind of error, I think there is a node that doesn't have the attribute or you misspelled some name,
var prop = xDoc.Root.Elements("Component")
.Where(c => (string)c.Attribute("ProductId") == "ERDSIC")
.Descendants("Row").Where(t => (string)t.Attribute("Name") == "dampersize")
.Select(v => (string)v.Attribute("Value")).FirstOrDefault();
If I put the OP's XML in a file called Data.xml in the \bin\Debug folder and run the following, it works, so I can only assume that his method for loading the XML is not working and prop is null.
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Work
{
public class Program
{
public static void Main(string[] _)
{
var folder = AppDomain.CurrentDomain.BaseDirectory;
var path = Path.Combine(folder, "Data.xml");
var xml = XElement.Load(path);
var prop = xml.Elements("Component")
.Where(c => c.Attribute("ProductId").Value == "ERDSIC")
.Descendants("Row").Where(t => t.Attribute("Name").Value == "dampersize")
.Select(v => v.Attribute("Value").Value).FirstOrDefault();
Console.WriteLine("Result: " + prop);
Console.ReadKey();
}
}
}
I wish to access some specific attribute (Tag name) i an XML file, and place them in a list but i cant get i right. What am I doing wrong??
The list should look like this:
Tag_1
Tag_2
Tag_3
Code:
XElement xelement = XElement.Load("C:/...../Desktop/Testxml.xml");
var tagNames = from tag in xelement.Elements("tagGroup")
select tag.Attribute("name").Value;
foreach (XElement xEle in tagNames)
{
//....
}
Here is the XML file:
<configuration>
<logGroup>
<group name="cpm Log 1h 1y Avg" logInterval="* 1 * * * ?" />
<group name="cpm Log 1d 2y Avg" logInterval="* 10 * * * ?" />
</logGroup>
<tagGroup>
<tag name="Tag_1">
<property name="VALUE">
<logGroup name="cpm Log 1h 1y Avg" />
<logGroup name="cpm Log 1d 2y Avg" />
</property>
</tag>
<tag name="Tag_2">
<property name="VALUE">
<logGroup name="cpm Log 1h 1y Avg" />
<logGroup name="cpm Log 1d 2y Avg" />
</property>
</tag>
<tag name="Tag_3">
<property name="VALUE">
<logGroup name="cpm Log 1h 1y Avg" />
<logGroup name="cpm Log 1d 2y Avg" />
</property>
</tag>
</tagGroup>
</configuration>
just change your linq query for:
var tagNames = from tag in xelement.Elements("tagGroup").Elements("tag")
select tag.Attribute("name").Value;
then tagName is an IEnumerable<string> and you can iterating like this:
foreach (var element in tagNames)
{
//element is a string
}
Your code enumerates through the elements called tagGroup, and then attempts to get the attribute in called name. There is no attribute in tagGroup. In fact tagGroup has descendants two levels deep called logGroup. It's logGroup that has the name attribute.
This code will not work:
XElement xelement = XElement.Load("C:/...../Desktop/Testxml.xml");
var tagNames = from tag in xelement.Elements("tagGroup")
select tag.Attribute("name").Value;
What you need is something like
var tagGroups = xelement.Descendants("tag").Select(x => x.Attribute("name")).ToList();
Or if you want to the others:
var tagGroups = xelement.Descendants("logGroup").Select(x => x.Attribute("name")).ToList();
var tagGroups = xelement.Elements("tagGroup").ToList();
var logGroups = tagGroups.SelectMany (g => g.Descendants("logGroup")).ToList();
var logAttributes = tagGroups.SelectMany (g => g.Descendants("logGroup").Select(x => x.Attribute("name"))).ToList();
Something Like :
var tagNames = xe.Element("tagGroup").Elements("tag").Select(a => a.Attribute("name").Value);
foreach (var xEle in tagNames)
{
Console.WriteLine(xEle);
}
Try this...
var tagNames = from tag in xelement.Elements("tagGroup").Elements("tag")
select tag.Attribute("name").Value;
or
var tagNames = xelement.Elements("tagGroup")
.Elements("tag")
.Attribute("name").Value;
In my web application, I am using NHibernate configured by an xml file (nhibernate.cfg.xml). I need to read the connection string from that file in my C# code. My code is working, but I don't like it (in particular the foreach!) and I would like to query the xml file in a straight manner. I have tried to query it with link, but I always get null nodes.
Here is the cfg file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Server=LEG\SQL12;initial catalog=DVR;user id=daniele;pwd=s;
</property>
<property name="dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
</session-factory>
</hibernate-configuration>
and here it is my C# code:
public static String GetConnectionString()
{
if (String.IsNullOrEmpty(_connectionString))
{
XElement root = XElement.Load("hibernate.cfg.xml");
var sessionFactoryNode = root.Elements().FirstOrDefault(); // session-factory
if (sessionFactoryNode != null)
{
var properties = sessionFactoryNode.Elements();
foreach (var property in properties)
{
if (property.Attribute("name").Value == "connection.connection_string")
_connectionString = property.Value.Trim();
}
}
}
return _connectionString;
}
How can I obtain the same result querying the xml?
XElement root = XElement.Load("hibernate.cfg.xml");
var connString = root.Descendants("property")
.Where(p => (string) p.Attribute("name") == "connection.connection_string")
.Select(p => (string) p)
.First();
I was asked today to look at a new project - reading in some XML and doing some analysis. I know a little C#. I have gotten this far with this code that so far works. I get the 4 node lists successfully. I have a couple problems. First I am not sure how to access what is in the tag on any of the nodes in any of the lists. Second, I'd prefer to be able to use LINQ queries but XmlNodeList doesn't seem to support that syntax. In the sample XML below, I'd like to be able to get all the vdisks that belong to a particular IO Group or mdisk as determined by io_group_name or mdisk_grp_name property. Most of what I looked at gave examples for accessing the [Attribute] list and searches all used properties/atttributes interchanged.
What I tried is also below, it gave a null value exception. The Attributes list only has one attribute. I can't find any examples to do what I want and it isn't clear from inspecting the node in the debugger what I need to access to do what I want.
//this works
XmlTextReader reader = new XmlTextReader(_InputFile);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList clusterlist = doc.SelectNodes("//object[#type='cluster']");
XmlNodeList controllerlist = doc.SelectNodes("//object[#type='controller']");
XmlNodeList mdisklist = doc.SelectNodes("//object[#type='mdisk']");
XmlNodeList vdisklist = doc.SelectNodes("//object[#type='vdisk']");
// this did not work - got null value exception
foreach (XmlNode vdisknode in vdisklist)
{
string str = vdisknode.Attributes["mdisk_grp_name"].Value;
}
A sample of the XML:
<object type="vdisk">
<property name="id" value="0" />
<property name="name" value="nim01_vd06_gmt" />
<property name="IO_group_id" value="0" />
<property name="IO_group_name" value="ossvc06_iogrp0" />
<property name="status" value="online" />
<property name="mdisk_grp_id" value="0" />
<property name="mdisk_grp_name" value="T1_OSIBM06_MDG1" />
<property name="capacity" value="644245094400" />
<property name="type" value="striped" />
</object>
object node has only one attribute: type
string type = vdiskNode.Attributes["type"].Value;
property node has two attributes: name and value:
string name = propertyNode.Attributes["name"].Value;
string value = propertyNode.Attributes["value"].Value;
What you need I deem is to extend the XPath query:
"//object[#type='vdisk']/property[#name='mdisk_grp_name']/#value"
Or use LINQ to XML:
from obj in doc.Load(xml).Root.Elements("object")
where (string)obj.Attribute("type") == "vdisk"
from prop in obj.Elements("property")
//where (string)prop.Attribute("name") == name
select prop.Value
I am trying to load an XML file onto my GUI using a TreeView control.
However, I am using a proprietary layout for my XML file.
The XML is structured like this:
<ConfiguratorConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Section>
<Class ID="Example" Name="CompanyName.Example" Assembly="Example.dll">
<Interface>
<Property Name="exampleProperty1" Value="exampleValue" />
<Property Name="exampleProperty2" Value="exampleValue" />
<Property Name="exampleProperty3" Value="exampleValue" />
</Interface>
</Class>
</Section>
</ConfiguratorConfig>
I'd like the output to be structured like:
Class "Example"
Property "exampleProperty1"
Property "exampleProperty2"
Property "exampleProperty3"
I'm totally new to using XML. I've been searching the web for the past few hours, and none of the results have helped. Some have come close, but perhaps properties won't show up, or node's names won't display, etc.
I'm writing in c# in Visual Studio 2005.
Thanks for the help!
You can iterate through nodes using XmlDocument, you can put this demo in a Main method of a console application:
string xml = #"<ConfiguratorConfig xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
<Section>
<Class ID=""Example"" Name=""CompanyName.Example"" Assembly=""Example.dll"">
<Interface>
<Property Name=""exampleProperty1"" Value=""exampleValue"" />
<Property Name=""exampleProperty2"" Value=""exampleValue"" />
<Property Name=""exampleProperty3"" Value=""exampleValue"" />
</Interface>
</Class>
</Section></ConfiguratorConfig>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode _class in doc.SelectNodes(#"/ConfiguratorConfig/Section/Class"))
{
string name = _class.Attributes["ID"].Value;
Console.WriteLine(name);
foreach (XmlElement element in _class.SelectNodes(#"Interface/Property"))
{
if (element.HasAttribute("Name"))
{
string nameAttributeValue = element.Attributes["Name"].Value;
Console.WriteLine(nameAttributeValue);
}
}
}
If you're using version of .NET higher than 3.0 you can use XDocument class (recommended if you can choose).
XDocument xdoc = XDocument.Parse(xml);
foreach (XElement _class in xdoc.Descendants("Class"))
{
string name = _class.Attribute("ID").Value;
Console.WriteLine(name);
foreach (XElement element in _class.Descendants("Property"))
{
XAttribute attributeValue = element.Attribute("Name");
if (attributeValue != null)
{
string nameAttributeValue = attributeValue.Value;
Console.WriteLine(nameAttributeValue);
}
}
}