Linq to Xml query - c#

I have a xml structure like this:
<Items>
<Configuration>
<ConfigurationSetting>Setting1</ConfigurationSetting>
<ConfigurationSetting>Setting2</ConfigurationSetting>
</Configuration>
<MetaData>
...
</MetaData>
<Group>
<GroupType>MyType1</GroupType>
<GroupType>MyType2</GroupType>
</Group>
<Group> <--- Looking for this Element
<Reference>MyReference1</Reference>
<Reference>MyReference2</Reference>
</Group>
<Group>
<GroupType>MyType3</GroupType>
<GroupType>MyType4</GroupType>
</Group>
</Items>
I want to write a Linq query that returns the first "Group" Element that contains a Sub-Element "Reference".
Thanks for your help.

Something like:
var grp = doc.Root.Elements("Group")
.Where(g => g.Elements("Reference").Any())
.FirstOrDefault();
Or as xPath (perhaps in XmlDocument): #"/Items/Group[Reference]"

Related

Iterating through linq results results in more items than query count

I'm fairly new to LINQ but this seemed pretty straightforward.
I have an XML doc which contains a structure like this:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<folders>
<folder id="-1" parent="-100">
<name><![CDATA[Root]]></name>
<children>
<folder id="2" parent="-1">
<name><![CDATA[Contribution]]></name>
<documents />
<children>
<folder id="775" parent="2">
<name><![CDATA[category1]]></name>
<documents />
<children>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts1]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts2]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
etc...
</children>
</folder>
</children>
</folder>
</children>
</folder>
</folders>
What I'm trying to do is to select all the elements with an attribute 'parent="775"'.
XElement xelement = XElement.Load("folders_only_registrar_folder.xml");
IEnumerable <XElement> folders = xelement.Elements();
var query = from node in folders.Descendants("folder")
where node.Attribute("parent").Value == registrarNodeID
select node;
Console.WriteLine(query.Count());
Console.ReadKey();
foreach(XElement departmentNode in query.Descendants("name"))
{
Console.WriteLine(departmentNode.Value.ToString());
}
When I run the query and test the count, I get 48 results (which is good)... but when I try to write out those same nodes, I get hundreds of results. For some reason it's giving me almost ALL of the elements named "folder" including children folders.
Thoughts as to what I'm doing wrong?
UPDATE... ok so now I know why i'm getting all the folders but any thoughts on how to create a collection of each grouping of nodes and sub-nodes?
Can the selection in LINQ send each 775 folder node (plus it's collective sub-nodes) into some sort of collection of nodes and then I could parse through them in a foreach by grouping of node?
Replace query.Descendants() with just query. query.Descendants() gets every child of every node that was originally contained within query.

How to use LINQ to get data from an XML file?

I have xml files which look like this:
<?xml version="1.0" encoding="utf-8"?>
<record id="177" restricted="false">
<type>record type</type>
<startdate>2000-10-10</startdate>
<enddate>2014-02-01</enddate>
<titles>
<title xml:lang="en" type="main">Main title</title>
<!-- only one title element with type main -->
<title xml:lang="de" type="official">German title</title>
<!-- can have more titles of type official -->
</titles>
<description>description of the record</description>
<categories>
<category id="122">
<name>category name</name>
<description>category description</description>
</category>
<!-- can have more categories -->
</categories>
<tags>
<tag id="5434">
<name>tag name</name>
<description>tag description</description>
</tag>
<!-- can have more tags -->
</tags>
</record>
How do I select the data from these xml files using LINQ, or should I use something else?
You can load xml into XDocument objects using either the Load() method
for files, or the Parse() method for strings:
var doc = XDocument.Load("your-file.xml");
// OR
var doc = XDocument.Parse(yourXmlString);
Then you can access the data using LINQ:
var titles =
from title in doc.XPathSelectElements("//title")
where title.Attribute("type").Value == "official"
select title.Value;
Was searching for examples of Xmlserializer and found this: How to Deserialize XML document
So why not to try. I did Ctrl+C and Edit -> Paste Special -> Paste XML As Classes in Visual Studio 2013 and... Whoa I got all the classes generated. One condition target framework must be 4.5 and this function is available from Visual Studio 2012+ (as stated in that post)

Reading and Editing XML file

I have an XML file which contains employee details. How can i edit the existing employee names in that MXL file using C# .NET.
Here is the xml file.
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee id="1">
<Name>Employee 1</Name>
<Designation>SE </Designation>
<Qualification>MCA </Qualification>
</Employee>
<Employee id="2">
<Name>Employee 2</Name>
<Designation>SE </Designation>
<Qualification>MCA </Qualification>
</Employee>
<Employee id="3">
<Name>Employee 3</Name>
<Designation>SE </Designation>
<Qualification>MCA </Qualification>
</Employee>
</Employees>
How can i edit the employee names. I am new to xml. For example using Console Application
You can simple do that using Linq to Xml.
using System.Xml.Linq;
...
XDocument xDoc = XDocument.Load(#"Your xml file path goes here"); // or XDocument.Parse("Your xml string goes here");
xDoc.Root.Elements("Employee").First(xe => xe.Attribute("id").Value == "1").Element("Name").Value = "your value";
Here is a good reference for head start: Programming Guide (LINQ to XML)
you can use XML Serialization, in my opinion this is the most comfortable way
of working with c# and xml,
some examples are here:
http://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx

XPath accessing a non-uniform XML file

I have an XML file that's modeled something like the following:
<data>
<customer>
<id></id>
<name></name>
<model>
<id></id>
<name></name>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
</model>
<model>
<id></id>
<name></name>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
</model>
</customer>
<customer>
<id></id>
<name></name>
<model>
<id></id>
<name></name>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
<item>
<id></id>
<history>
<date></date>
<location></location>
</history>
</item>
</model>
</customer>
<customer>
<id></id>
<name></name>
</customer>
</data>
Using XPath in C#, I need to access the following for each customer:
customer/id
customer/name
customer/model/id
customer/model/name
customer/model/item/id
customer/model/item/history/date
customer/model/item/history/location
When data does not exist for any given customer, then the result stored will be null, since all fields of my customer object must be populated. If the XML file was uniform, this would be easy. My problem is accessing each customer's data when each customer may potentially have a different number of model and item nodes. Any ideas?
Assuming that the result will consist of these types of object:
Customer, Model, Item and History
The pseudo - code for populating them is:
Select all /data/customer elements
For each of the nodes selected in 1. do:
Select ./id and ./name and populate the corresponding properties of the object.
Populate a List<Model> property from all model children of the current customer element:
Select all ./model children of the current element.
For each selected model element in 5. create a Model object and populate its properties:
For the current Model object populate its Id and Name properties by selecting the ./id and ./name children of the current model element.
Populate a List<Item> property from all item children of the current model element:
Select all ./item children of the current element.
For the current Item object populate its Id property by selecting the ./id child of the current item element.
In a similar way populate the History property of the Item object with a History object, that you create and populate from the ./history child of the current item element.
Of course, you can skip all this if you use XML Serialization -- read about this here: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

Create a new XMLDocument by filtering an existing document in c# using xpath

I have a situation where I receive an XML (document) file from an external company. I need to filter the document to remove all data I am not interested in.
The file is about 500KB but will be requested very often.
let say the following file:
<dvdlist>
<dvd>
<title>title 1</title>
<director>directory 2</director>
<price>1</price>
<location>
<city>denver</city>
</location>
</dvd>
<dvd>
<title>title 2</title>
<director>directory 2</director>
<price>2</price>
<location>
<city>london</city>
</location>
</dvd>
<dvd>
<title>title 3</title>
<director>directory 3</director>
<price>3</price>
<location>
<city>london</city>
</location>
</dvd>
</dvdlist>
What I need is simply filter the document based on the city = london in order to end up with this new XML document
<dvdlist>
<dvd>
<title>title 2</title>
<director>directory 2</director>
<price>2</price>
<location>
<city>london</city>
</location>
</dvd>
<dvd>
<title>title 3</title>
<director>directory 3</director>
<price>3</price>
<location>
<city>london</city>
</location>
</dvd>
</dvdlist>
I have tried the following
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\Development\Website\dvds.xml");
XmlNode node = doc.SelectSingleNode("dvdlist/dvd/location/city[text()='london']");
Any help or links will appreciate
Thanks
XPath is a selection expression language -- it never modifies the XML document(s) it operates on.
Therefore, in order to obtain the desired new XML document, you need to either use XML DOM (not recommended) or apply an XSLT transformation to the XML document. The latter is the recommended way to go, since XSLT is a language especially designed for tree transformations.
In .NET one can use the XslCompiledTransform class and its Transform() method. Read more about these in the relevant MSDN documentation.
The XSLT transformation itself is extremely simple:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="dvd[not(location/city='london')]"/>
</xsl:stylesheet>
Here, you can find a complete code example how to obtain the result of the transformation as an XmlDocument (or if desired, as an XDocument).
Here's an example using LINQ to XML.
//load the document
var document = XDocument.Load(#"C:\Development\Website\dvds.xml");
//get all dvd nodes
var dvds = document.Descendants().Where(node => node.Name == "dvd");
//get all dvd nodes that have a city node with a value of "london"
var londonDVDs = dvds.Where(dvd => dvd.Descendants().Any(child => child.Name == "city" && child.Value == "london"));

Categories

Resources