I have to write a program using Linq. I'm just a student and I didn't learned that yet, so I have two questions:
What would be a good book/ebook... to teach myself what my next question will be about?
I have an XML-File, that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Projects>
<Project>
<Information>
<Name>Project1</Name>
<Date>26.01.2015</Date>
</Information>
<Files ID = "S" path = "C:\Users\marcel\Documents">
<file>Test1.txt</file>
<file>Test2.txt</file>
<file>Test3.txt</file>
<file>Test4.txt</file>
<file>Test5.txt</file>
</Files>
<Files ID = "C" path = "C:\Users\marcel\Documents">
<file>Test1(1).txt</file>
<file>Test1(2).txt</file>
<file>Test1(3).txt</file>
<file>Test1(4).txt</file>
<file>Test1(5).txt</file>
</Files>
</Project>
I want to get a string-array which is containing the values of the "file" elements, depenging on ID=S or C.
I have more than 1 project in there, so it first has to be searched by name, that's working right now:
var entries = from items in xelement.Elements("Project")
where (string)items.Element("Name").Value == projectName
select items;
that gets me the whole block of the needed project.
Can I use the result of the first command for getting the filenames?
Or can I just extend the code of the first part?
To get a specific Project element having the specified name you can use First:
var projectElement = xElement
.Elements("Project")
.First(x => (String) x.Element("Information").Element("Name").Value == projectName);
In a similar way you can find the desired Files element by specifying a value for the ID attribute:
var filesElement = projectElement
.Elements("Files")
.First(x => x.Attribute("ID").Value == id);
You can then use Select to project the File elements to their values and convert that to an array:
var files = filesElement
.Elements("file")
.Select(x => (String) x.Value)
.ToArray();
Note that this code will throw exceptions if the XML has an unexpected format. E.g., if First does not find a matching element an exception is thrown. Also, the Element method will return null if the specified element is not found and thus code like x.Element("Information").Element("Name") will throw an exception if there is no Information element because the next call to Element is performed on the null reference.
Thank you Martin, that worked :)
I just came up with an own solution looking like this:
var files = from file in entries.Elements("Files").Elements("file")
where (string)file.Parent.Attribute("ID").Value == cOrS
select file.Value;
Related
i want to find the value of an Attribute in our XML-FIle.
For Example, here our XML Document:
<PROJECT_DOCUMENTS>
<DOCUMENT isFile="YES" isLink="YES" type="Risk Action List (combined)" path="path" showFile="" showFolder="YES" FilePath="" FolderPath="" />
<DOCUMENT isFile="YES" isLink="NO" type="ASPICE-Action List" path="path" showFile="" showFolder="YES" FilePath="" FolderPath="path" />
</PROJECT_DOCUMENTS>
I want the value of path = " .... bla ..." were the type is ASPICE-Action List.
Here my code with i generated:
XElement elementToChange = (from c in getFileFromXML.Element("PROJECT_DOCUMENTS")
.Elements("DOCUMENT")
where("type"== "ASPICE-Action List")
select c).Single().Element("path");
But i dont get the infomation. I think the type == Aspice-Action list doesn´t work.
Can anyone help me to solve my Problem ;)
Thanks
If you want to get path attribute values you can use next code which manipulate with Attribute() method for attributes of element:
var elementsToChange = from c in getFileFromXML.Element("PROJECT_DOCUMENTS").Elements("DOCUMENT")
where c.Attribute("type")?.Value == "ASPICE-Action List" )
select c.Attribute("path").Value;
To retrieve whole elements use next code or add SingleOrDefault() or FirstOrDefault() to the end for your tasks:
var elementsToChange = from c in getFileFromXML.Element("PROJECT_DOCUMENTS").Elements("DOCUMENT")
where c.Attribute("type")?.Value == "ASPICE-Action List" )
select c;
You can try getting the same using the code below:
from c in getFileFromXML.Elements("DOCUMENT")
where "ASPICE-Action List" == c.Attribute("type").Value
select c;
I have some projects in an XML file. eg. Multiple projects like the one below in the same file . I want to search all project entries where FluidTypes matches a particular string .
<?xml version="1.0" encoding="utf-8"?>
<data>
<Project ID="P-2014-000037">
<Name>FDP001_Bakken</Name>
<Manager>shell</Manager>
<Area>NAM</Area>
<Field>Bakken</Field>
<Type>Time and Material External</Type>
<Country>USA</Country>
<Value>3.5</Value>
<Geomarket>NAM</Geomarket>
<FormationTypes>Carbonate</FormationTypes>
<FormationTypes>Coal</FormationTypes>
<FormationTypes>Fractures</FormationTypes>
<FormationTypes>Sandstone</FormationTypes>
<FluidTypes>Gas Cond</FluidTypes>
<FluidTypes>Heavy Oil</FluidTypes>
<DriveMechanisms>Compaction</DriveMechanisms>
<DriveMechanisms>Aquifer</DriveMechanisms>
<EORProcesses>CO2</EORProcesses>
<EORProcesses>CSS</EORProcesses>
</Project>
</data>
I am using the follwing code to search for Geomarket matches :
IEnumerable<XElement> values1 = from el1 in root.Elements("Project").
Where(r => regEx1.IsMatch(r.Element("Geomarket").Value))
select el1;
when I use same for Fluid type (which has multiple elements ):
IEnumerable<XElement> values1 = from el1 in root.Elements("Project").
Where(r => regEx1.IsMatch(r.Element("FluidTypes").Value))
select el1;
It only checks for a match with the first element with name Fluid Types and not ALL fluid types elements . As a result only Gas Cond matches this project but Heavy Oil does not.
How to make a query across all Fluid types search ?
Use a Where clause with a nested search:
var projects = root
.Elements("Project")
.Where(el => el.Elements("FluidTypes").Where(el2 => regEx1.IsMatch(el2.Value)).Any());
This returns all elements named "Project" with at least one nested element named "FluidTypes" whose Value matches your regular expression.
Or, use a nested Any():
var projects = root
.Elements("Project")
.Where(el => el.Elements("FluidTypes").Any(el2 => regEx1.IsMatch(el2.Value)));
Try
IEnumerable<XElement> values1 = from el1 in root.Elements("Project").Elements("FluidTypes")
.Where(r => regEx1.IsMatch(r.Value))
Select el1;
Still a Linq newbie here, and now having issues with the WHERE clause. I'm trying to return anything found in the printer tags, but only from below the element list type="lff".
If I try to output the descendant elements with no WHERE clause, I get everything (from both <list> elements). When I try to add various versions of a WHERE clause, I get nothing back. I'm obviously not putting the WHERE condition in correctly.
(I need to get the element object, so I can check the NAME and the VALUE. In my example below, I am only outputting the VALUE for now).
Can you advise?
Here is the XML:
<?xml version="1.0"?>
<printerlist>
<list type="aff">
<printserver>print-server1</printserver>
<printserver>print-server2</printserver>
<printserver>print-server3</printserver>
<additionalprinters>
<printer>
<fullname>\\servera\bbb</fullname>
</printer>
</additionalprinters>
</list>
<list type="lff">
<printserver>print-sever4</printserver>
<additionalprinters>
<printer>
<fullname>\\serverb\bbb</fullname>
</printer>
<printer>
<fullname>\\serverc\aaa</fullname>
</printer>
</additionalprinters>
</list>
</printerlist>
And here is the code to try and get the list:
var qq = from c in xml.Descendants("additionalprinters").Descendants("printer")
//where (string) c.Parent.Attribute("type") == "lff"
//Uncommenting the above line means that nothing is returned.
select c;
foreach (XElement q in qq)
{
Console.WriteLine("Test Output: {0}", q.Value );
}
Output is:
Test Output: \\servera\bbb
Test Output: \\serverb\bbb
Test Output: \\serverc\aaa
I am only looking for the final two outputs to be returned, in this particular case.
The parent of printer is additionalprinters and it doesn't have type property, you need to use .Parent twice to get list element.
from c in xml.Descendants("additionalprinters").Descendants("printer")
where (string) c.Parent.Parent.Attribute("type") == "lff"
select c
Or you can also do the following
xml.Descendants("list")
.Where(c => (string) c.Attribute("type") == "lff")
.SelectMany(x => x.Element("additionalprinters").Descendants("printer"))
You can also use XPath selector from System.Xml.XPath namespace for this purpose:
var doc = XDocument.Parse(xml);
var printers = doc.XPathSelectElements("//list[#type='lff']/additionalprinters/printer");
I want to search through my xml file. The structure looks like this:
<AForetag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Place ID="1006">
<Foretag>
<Epost>info#abc123.se</Epost>
<Namn>Abe</Namn>
<Ort>Abc123</Ort>
<Adress>Abc123</Adress>
<Postnummer>Abc123</Postnummer>
<Landskap>Abc123</Landskap>
<Telefon>Abc123</Telefon>
<Medlemskap>Abc123</Medlemskap>
</Foretag>
<Foretag>
<Epost>def456</Epost>
<Namn>def456</Namn>
<Ort>def456</Ort>
<Adress>def456</Adress>
<Postnummer>def456</Postnummer>
<Landskap>def456</Landskap>
<Telefon>def456</Telefon>
<Medlemskap>def456</Medlemskap>
</Foretag>
</Place>
</Aforetag>
And I want to search for the Element <Landskap>. And if I get and match I should pick all the other elements, Epost, Namn, Ort, Adress, Postnummer, Landskap, Telefon and Medlemskap. The info I want to put in an array.
I have tried this:
var aforetag = from foretag in doc.Descendants("Place")
where foretag.Attribute("ID").Value == "1006"
select foretag;
var landskap = aforetag.Elements("Foretag")
.Descendants()
.Where(x => x.Element("Landskap")
.Value
.Contains(s)
.Descendants()
.Select(c => (string)c)
.ToArray();
Your code is not well formed. Copy this into VS and there are a few errors, fix one and more errors!...
And most importantly, your XML is not XML as the start and end tag don't even match! Plus, there are other issues.
Fix all these and I'm sure it will help.
var landskap = aforetag.Elements("Foretag")
.Where(e=>e.Element("Landskap").Value.Contains(s))
.Select(e=>e.Elements().Select(x=>x.Value).ToArray());
//the result is an IEnumerable<string[]> for the matched keyword s
Trying to use
exportDoc.Root.Elements("string").Where(node => !(node.Element("product").HasElements) || node.Element("product").Element("type").Value != product).Remove();
to remove the nodes in my XML document where the product string I'm searching for doesn't occur. Here is a sample of my XML structure:
<root>
<string id = "Hithere">
<product>
<type>orange</type>
<type>yellow</type>
<type>green</type>
<product>
<element2/>
<element3/>
</string>
<string id ="...">
...
...
</root>
So I need to look under the product element of each string element AND at each of the type elements therein to see if the value of string product (input to the method where this is contained) occurs. At present, it looks like my code only removes the node if the product string I'm searching for matches the value of just the first type element.
The whole point is to remove all string nodes from this xdoc that don't have the product I'm looking for listed under their product element.
You need to change your search condition slightly:
var nodesToRemove = xDoc.Root
.Elements("string")
.Where(node =>
!(node.Element("product").HasElements) ||
node.Element("product").Elements("type").All(x => x.Value != product))
.ToList();
This should match elements which all string:product:types differ from product value (or in other words - if at least one <type> will match your product, it won't be marked for removal).
You can't Remove() while you're still enumerating (deferred execution).
You need something more like:
// untested
var toRemove = exportDoc.Root.Elements("string")
.Where(node => !(node.Element("product").HasElements) ||
node.Element("product").Element("type").Value != product).ToList();
toRemove.Remove();