Linq query to Parse XML - c#

I have the XML shown below. I am trying to parse using C# with LINQ.
<software>
<version>31.0.1</version>
<status>uptime 2d 22h 39m 26s</status>
<wPack>
<rv>
<total>0</total>
<qv>0</qv>
</rv>
<sv>
<total>0</total>
<qv>0</qv>
</sv>
</wPack>
<sPack>
<rv>
<total>242</total>
<qv>1</qv>
</rv>
<sv>
<total>69845</total>
<qv>145</qv>
</sv>
<size>146</size>
</sPack>
<dPack>
<rv>
<total>88560</total>
</rv>
<sv>
<total>0</total>
</sv>
<in>0.28,0.23,0.35</in>
<out>0.00,0.00,0.00</out>
<qv>216806</qv>
<db>mysql</db>
</dPack>
<bClients>
<bClient>
<type>sPackbClient</type>
<id>test1</id>
<IP>127.0.0.1</IP>
<queue>0</queue>
<status>on-line 2d 22h 39m 21s</status>
<ssl>no</ssl>
</bClient>
<bClient>
<type>sPackbClient</type>
<id>test2</id>
<IP>127.0.0.1</IP>
<queue>0</queue>
<status>on-line 2d 22h 39m 18s</status>
<ssl>no</ssl>
</bClient>
<bClient>
<type>sPackbClient</type>
<id>test3</id>
<IP>127.0.0.1</IP>
<queue>0</queue>
<status>on-line 0d 2h 33m 30s</status>
<ssl>no</ssl>
</bClient>
</bClients>
<servers>
<server>
<name>EC1</name>
<admin-id>EC1</admin-id>
<id>EC1</id>
<status>online 8901s</status>
<failed>0</failed>
<qv>0</qv>
<sPack>
<rv>0</rv>
<sv>0</sv>
<in>0.00,0.00,0.00</in>
<out>0.00,0.00,0.00</out>
</sPack>
<dPack>
<rv>0</rv>
<sv>0</sv>
<in>0.00,0.00,0.00</in>
<out>0.00,0.00,0.00</out>
</dPack>
</server>
<server>
<name>EC2</name>
<admin-id>EC2</admin-id>
<id>EC2</id>
<status>online 8918s</status>
<failed>2</failed>
<qv>0</qv>
<sPack>
<rv>79</rv>
<sv>20843</sv>
<in>0.00,0.00,0.00</in>
<out>0.06,0.05,0.08</out>
</sPack>
<dPack>
<rv>35050</rv>
<sv>0</sv>
<in>0.10,0.07,0.14</in>
<out>0.00,0.00,0.00</out>
</dPack>
</server>
<server>
<name>EC3</name>
<admin-id>EC3</admin-id>
<id>EC3</id>
<status>re-connecting</status>
<failed>0</failed>
<qv>0</qv>
<sPack>
<rv>4</rv>
<sv>1671</sv>
<in>0.00,0.00,0.00</in>
<out>0.00,0.00,0.00</out>
</sPack>
<dPack>
<rv>1664</rv>
<sv>0</sv>
<in>0.00,0.00,0.00</in>
<out>0.00,0.00,0.00</out>
</dPack>
</server>
</servers>
</software>
When I try to get <sPack> elements using following query.
var software = (from sw in xDoc.Descendants("software")
from sp in sw.Descendants("sPack")
select sp).ToList();
I get all instance of <sPack> which are under:
<servers>
<server>
<sPack>
What i want is to get <sPack> which comes under <software> and a separate query for parsing <servers>.

You could simply use xDoc.Root.Elements("sPack") to select the sPack child element(s) of the root element and then xDoc.Root.Elements("servers").Elements("server").Elements("sPack") to select the sPack descendants of the server element(s).

The sPack element you're getting as part of your query is a descendant ofsoftware. As software is the root element, all elements within are descendants. The example in the docs shows how this query works.
What you want is Elements, which only returns the child elements, it doesn't involve any recursion.
var software = xDoc.Elements("software").Elements("sPack");
For your second query, you do want to search recursively through all elements. So Descendants is appropriate here:
var servers = xDoc.Descendants("servers").Descendants("sPack");

Related

C# XML LINQ searching

I have a XML file like this:
<SoftwareComponent schemaVersion="1.0" packageID="Y75WC" releaseID="Y75WC" hashMD5="a190fdfa292276288df38507ea551a3b" path="FOLDER04650736M/1/OptiPlex_3050_1.7.9.exe" dateTime="2017-12-05T05:34:30+00:00" releaseDate="décembre 05, 2017" vendorVersion="1.7.9" dellVersion="1.7.9" packageType="LWXP" identifier="532f5a9e-c087-4499-b40c-cf7921ee06d3" rebootRequired="true">
<Name>
<Display lang="en"><![CDATA[Dell OptiPlex 3050 System BIOS,1.7.9]]></Display>
</Name>
<ComponentType value="BIOS">
<Display lang="en"><![CDATA[BIOS]]></Display>
</ComponentType>
<Description>
<Display lang="en"><![CDATA[This package provides the Dell System BIOS update and is supported on Dell OptiPlex 3050 Tower, OptiPlex 3050 Small Form Factor and OptiPlex 3050 Micro for Windows Operation System.]]></Display>
</Description>
<LUCategory value="NONE">
<Display lang="en"><![CDATA[None]]></Display>
</LUCategory>
<Category value="BI">
<Display lang="en"><![CDATA[FlashBIOS Updates]]></Display>
</Category>
<SupportedDevices>
<Device componentID="159" embedded="0">
<Display lang="en"><![CDATA[OptiPlex 3050 System BIOS]]></Display>
</Device>
</SupportedDevices>
<SupportedSystems>
<Brand key="1" prefix="OP">
<Display lang="en"><![CDATA[Optiplex]]></Display>
<Model systemID="07A3">
<Display lang="en"><![CDATA[3050]]></Display>
</Model>
</Brand>
</SupportedSystems>
<ImportantInfo URL="http://www.dell.com/support/home/us/en/19/Drivers/DriversDetails?driverId=Y75WC" />
<Criticality value="2">
<Display lang="en"><![CDATA[Urgent-Dell highly recommends applying this update as soon as possible. The update contains changes to improve the reliability and availability of your Dell system.]]></Display>
</Criticality>
There are multiple SoftwareComponent Elements inside.
I tried to get some attributes of SoftwareComponent ( dellVersion, hashMD5) based on descendants Elements ( ComponentType value, SupportedSystems->Device->Display value, Criticality value) but all my tests were not good.
See my actual code, I can get all the value in the XML file only:
XDocument doc = XDocument.Load("catalog.xml");
var els = from el in doc.Root.Elements("SoftwareComponent")
select new
{
dellVersion = (string)el.Attribute("dellVersion"),
hashMD5 = (string)el.Attribute("hashMD5"),
path = (string)el.Attribute("path"),
};
foreach (var el in els)
{
Console.WriteLine("dell BIOS: {0}, MD5: {1}, path: {2}", el.dellVersion, el.hashMD5, el.path);
}
Somebody can show me how to proceed please ?
Thanks
First of all, your XML document is missing a </SoftwareComponent> end tag. Maybe you didn't copy the contents OK here.
Then, SoftwareComponent is actually the root in your document, so you would need code like:
XDocument doc = XDocument.Load("catalog.xml");
var el = new
{
dellVersion = (string)doc.Root.Attribute("dellVersion"),
hashMD5 = (string)doc.Root.Attribute("hashMD5"),
path = (string)doc.Root.Attribute("path"),
};
Console.WriteLine("dell BIOS: {0}, MD5: {1}, path: {2}", el.dellVersion, el.hashMD5, el.path);
Your code would work OK as-is if the XML would have the format:
<Root>
<SoftwareComponent schemaVersion="1.0" packageID="Y75WC" releaseID="Y75WC" hashMD5="a190fdfa292276288df38507ea551a3b" path="FOLDER04650736M/1/OptiPlex_3050_1.7.9.exe" dateTime="2017-12-05T05:34:30+00:00" releaseDate="décembre 05, 2017" vendorVersion="1.7.9" dellVersion="1.7.9" packageType="LWXP" identifier="532f5a9e-c087-4499-b40c-cf7921ee06d3" rebootRequired="true">
</SoftwareComponent>
</Root>
XML documents can only have one root node, so you can't have multiple SoftwareComponent as root as you seem to imply.
If you want to get, for example, ComponentType value, you can do:
componentTypeValue = (string)el.Descendants("ComponentType").FirstOrDefault().Attribute("value")
I would actually change the query into a foreach and check that FirstOrDefault result for null.

Parsing Advanced XML File & Turning Information Into Class In C#

What needs to be done
Currently I have 1 Advanced XML file that needs to be parsed. I need to iterate through the file and read each "Entity" tag individually. Altough the issue I come across is reading & iterating through the Stats and Slots. Also, the amount of Stat & Slot tags will vary depending on the Entity. (Yes I have researched this topic but I still can't find a way without creating errors as I need some more guidance. The other posts haven't had the exact fix I've hoped for...)
XML File
<ROOT>
<Entity Type="Clothing" Name="Light Robe" ID="0">
<Armor>2</Armor>
<Weight>1</Weight>
<Usability>120</Usability>
<Rarity>0.1</Rarity>
<Stats>
<Stat Type="Health">10</Stat>
</Stats>
<Slots>
<Slot>Torso</Slot>
</Slots>
</Entity>
<Entity Type="Clothing" Name="Medium Robe" ID="1">
<Armor>4</Armor>
<Weight>2</Weight>
<Stats>
<Stat Type="Health">15</Stat>
</Stats>
<Usability>120</Usability>
<Rarity>0.1</Rarity>
<Slots>
<Slot>Torso</Slot>
</Slots>
</Entity>
<Entity Type="Clothing" Name="Heavy Robe" ID="2">
<Armor>6</Armor>
<Weight>4</Weight>
<Stats>
<Stat Type="Health">25</Stat>
</Stats>
<Usability>120</Usability>
<Rarity>0.1</Rarity>
<Slots>
<Slot>Torso</Slot>
</Slots>
</Entity>
</ROOT>
If anybody has any criticism of this post please say so as I'll edit accordingly.
Use XDocument for XML reading.
// Load Document
XDocument _doc = XDocument.Load("C:\\t\\My File2.txt");
// Get all Entity elements and put them into a list.
List<XElement> employees = _doc.XPathSelectElements("ROOT/Entity").ToList();
// Next you can loop thru the list to check the Entity's elements
foreach (var employee in employees)
{
// to get the armor element:
string armor = employee.Element("Armor").Value;
// to get the rarity element:
string rarity = employee.Element("Rarity").Value;
// to get the Stat element:
string stat = employee.Element("Stats").Element("Stat").Value;
// to get the Slot element:
string slot = employee.Element("Slots").Element("Slot").Value;
}
// To get one element specific by attribute use this (I check on attribute ID):
XElement emp = _doc.XPathSelectElements("ROOT/Entity").FirstOrDefault(c => c.Attribute("ID").Value == "0");
// Next you can extract information from this element just like in the foreach loop.

LINQ TO XML retrieving Child Element Value

I have the following XML
<ABC xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://ns.hr-xml.org/2007-04-15">
<ReceiptId>
<IdValue>123</IdValue>
</ReceiptId>
<ClientOrderId>
<IdValue>345</IdValue>
</ClientOrderId>
<AccessPoint>
<Description>My Description</Description>
</AccessPoint>
<ABCStatus>
<Status>Error</Status>
<Details>ERRORS:
Talent is already in an active process for this opening.
</Details>
<StatusDate>2015-08-05</StatusDate>
</ABCStatus>
</ABC>
I am trying to retrieve the element value 345 nested in IdValue and ClientOrderId
I have used the Linq to xml code in C# to retrieve the value with no luck
XDocument XMLResults = XDocument.Parse(sResult);
var sClientOrderID =
from nodeAElem in XMLResults.Root.Elements("ABC")
from nodeA1Elem in nodeAElem.Elements("ClientOrderId")
from nodeA11Elem in nodeA1Elem.Elements("IdValue")
select nodeA11Elem.Value;
also need to retrieve the Status Elements value which is Error for the above xml.
Any help is greatly appreciated
Your XML document is using a namespace, you have to use it in your query to make it work.
Root already brings you to ABC element, so you don't have to call Elements("ABC")
You're looking for single value, so you probably want to use Element instead of Elements.
var ns = (XNamespace)"http://ns.hr-xml.org/2007-04-15";
var sClientOrderID = (int)XMLResults.Root
.Element(ns + "ClientOrderId")
.Element(ns + "IdValue");

XmlDocument in an array like object

I googled for hours and didn't find anything.
I'm trying to make a Metro App which is reading from an online XML Service. Getting the XML is not the problem, i'm simply doing it like this ->
var xmlDoc = await XmlDocument.LoadFromUriAsync(new Uri(url));
but now the problem is, how to convert it into a list or something readable like this.
The XML I want to read is really huge and i don't want to go through all nodes with foreach.
A simple Array/List with all nodes and innerText as Value would be awesome.
Is this possible? If yes.. how ?
The structure of my XML is like this ->
<?xml version="1.0" encoding="UTF-8"?>
<city>
...
<credit>
...
</credit>
<forecast>
<date value="2013-11-08">
...
<time value="06:00">
...
</time>
<time value="11:00">
...
</time>
<time value="17:00">
...
</time>
<time value="23:00">
...
</time>
...
</date>
<date value="2013-11-09">
<same content here>
</date>
<date value="2013-11-09">
<same content here>
</date>
</forecast>
</city>
as you can see... there's a lot of information in the XML and I need nearly everything. In Actionscript I would realize it with a XMLList and make 3 Lists of the date Tags with content, so i can use
xmllist1.time[0] - xmllist1.time[3]
xmllist2.time[0] - xmllist2.time[3]
xmllist3.time[0] - xmllist3.time[3]
to get my data.
And now i want this XMLList in C#... I hope it's possible...Thx 4 help
If I understand you correctly, you want to parse the list of "city" items from the xml.
I do something similar using XDocument and Linq like this and it should work for you:
XDocument xdoc = <add your code to get xml from url>;
var ns = xdoc.Root.GetDefaultNamespace();
var cityList = from query in xdoc.Descendants(ns + "city")
select new CityItem
{
Date = (string)query.Element(ns + "date").Attribute("value").Value,
Time = (string)query.Element(ns + "time").Attribute("value").Value
};
public class CityItem
{
public string Date {get;set;}
public string Time {get;set;}
}

Using Linq and XDocument, can I get all the child elements under parent tag?

I have an XML
<data>
<summary>
<account curr_desc='USD' acct_nbr='123' net='1000.00' />
<account curr_desc='USD' acct_nbr='456' net='2000.00' />
</summary>
<details>
<accounts>
<account acct_nbr="123" curr="USD">
<activity color='False' settle_date='02 Jul 2010' amt='580.00' />
<activity color='True' settle_date='09 Jul 2010' amt='420.00' />
</account>
<account acct_nbr="456" curr="USD">
<activity color='True' settle_date='12 Dec 2010' amt='1500.00' />
<activity color='True' settle_date='19 Dec 2010' amt='500.00' />
</account>
</accounts>
</details>
</data>
Using Linq and XDocument, I can extract "summary" information but how can I extract "account" information under "summary" tag?
XDocument XMLDoc = XDocument.Load("testdata.xml");
XElement accounts = (from xml2 in XMLDoc.Descendants("summary")
select xml2).FirstOrDefault();
How can I specify something like "summary/account" so that it returns me all the elements under <summary>? Note, that I have <account> under <detail><accounts>, I only want the elements under summary tag.
You should use the Elements method:
var accounts = doc.Root.Elements("summary").Elements("account");
Or, alternatively, XPathSelectElements, which in this case is simpler:
var accounts = doc.XPathSelectElements("/data/summary/account");
In this instance you can also use Descendants, as Andrew Barber suggested, but in general you should only do this when you really want to find all descendants with a given name, and not just immediate children. Otherwise your code does a lot of searching that it doesn't need to, and may return elements you don't want it to.
var accountSummaryElems =
XMLDoc.Element("summary").Elements("account");
This gives you a collection of the account elements under the summary element. You can then iterate them to get the values.
EDITED to use the same pattern you were; I call First() instead of FirstOrDefault() because that code won't run anyway if the "account" element is not found.
Then you have the right idea with iterating over the collection returned.
This returns child elements as a string list not matter where it is.
using System.Xml.Linq;
XDocument xmlDocument = XDocument.Load(fileName);
public List<string> FindChilds(string parentTag)
{
return xmlDocument.Descendants().Where(x => x.Parent != null).Where(x => x.Parent.Name.ToString().Equals(parentTag)).Select(x => x.Name.ToString()).ToList();
}

Categories

Resources