Posts Tagged ‘LINQ to XML’

Getting a single XAttribute or XElement

I have come across two ways querying XElements or XAttributes:

  • Make an object IEnumerable and loop through the results
  • Use the Single() method to return a single object only

Typically you may have a situation where you write some Linq-to-XML like this:

IEnumerable attrib = from att in elemInner.Attributes()
                                             where (string)att.Name.ToString() == "sectionName"
                                             select att;

To loop through the results you have to use a foreach loop like this:


foreach (XAttribute innerAttrib in attrib)
{
     builder.AppendLine("

" + innerAttrib.Value +"

"); }

If however you just wanted a single attribute result, you could write the same code like this:


 XAttribute attribDisplayStyle = (from att in elemInner.Attributes()
                                            where (string)att.Name.ToString() == "sectionName"
                                            select att).Single();

Then you only have a single XAttribute instance and you dont need a foreach loop:


attribDisplayStyle.Value;

You would apply the same logic to XElement as well.

  • Share/Bookmark

Getting search results from Bing REST service and using LINQ to process results

So today I started reading about the Bing API and I got myself an API key and I read through the basic instruction manual, which tells you how to get search results from the web through the Bing REST service. Its pretty straight forward, just get your own key though! But here is some sample code that does the trick and uses Linq to XML to process the results:

            XDocument document = XDocument.Load("http://api.search.live.net/xml.aspx?Appid=&query=sushi&sources=web");
            XElement root = document.Root;
            XNamespace web = "http://schemas.microsoft.com/LiveSearch/2008/04/XML/web";
            var searchItems = document.Descendants(web + "Results").SingleOrDefault();

            IEnumerable testelem = from el in searchItems.Elements()
                                                 select el;
            foreach (XElement myElem in testelem)
            {
                context.Response.Write(myElem.Value + "");
            }

That is very easy!

  • Share/Bookmark

Enumerating through an XML document

I am in the process of developing some code for easily updating my CV, and one of the technologies I am using for this purpose is Linq to XML. As I have said previously on this blog, Linq to XML is an in-memory XML manipulation technology which allows you to manipulate XML as if you would use the XML DOM. So as part of my application I want to use XML because its easy to create or get the structure needed for creating the CV. I have discussed the idea of a CV Builder previously here. So part of this project involves reading XML and reading XML with LINQ to XML seems a rather straight forward process. The first thing you need to know about though is that the IEnumerable interface you need to use exists in the System.Collections.Generic namespace, not System.Collections. If you use only the latter you will get an error message saying:

The non-generic type ‘System.Collections.IEnumerable’ cannot be used with type arguments

Lets show some code that reads XML:

        XDocument document = XDocument.Load(context.Server.MapPath(@"CVTemplate.xml"));
        XElement root = document.Root;
        IEnumerable elements = from el in root.Descendants("parentsection")
                                             select el;
        foreach (XElement elem in elements)
        {
            builder.AppendLine("Element Name:\t" + elem.Name.ToString());
            builder.AppendLine("Attributes:");
            foreach (XAttribute attrib in elem.Attributes())
            {
                builder.AppendLine("\t\t" + attrib.Value);
            }
            foreach (XElement subElem in elem.Descendants())
            {
                builder.AppendLine("\t\t" + subElem.Name.ToString() + "\n\t\t\t" + subElem.Value);
            }
        }
        context.Response.Write(builder.ToString());

In the code above I use the XDocument class to read the XML from an XML file that I specified in a web.config app setting. I then create an XElement instance by assigning it to the document.Root of the XDocument instance, because its return type is XElement. I then create an enumerable variable elements of type XElement and get the enumerable result from a LINQ query that selects the elements from the XML of the nodes parentsection. I then enumerate through the XElements from the elements variable. Inside the foreach loop I enumerate twice again, once for the attributes of the XML node and the second time for the nested XElements. I just created a StringBuilder instance to write the values as the enumeration took place, its just so that I can see the values and also because I implemented this with a generic handler. Ok so what is next? Well next I need to be able to select items and move them around, but thats for another article.

  • Share/Bookmark

Linq to XML and DataSet to XML

On Monday I started working through some LINQ to XML and it got me so excited that I misunderstood some project requirements that ended up being quite wrong. It did not, however, diminish my enthusiasm. I ended up using a small part of the code in the end anyway, even though it was not in a production environment.

Lets say you have a collection of XML documents and you would like to know what elements appear in all of them, so at the end of it all you have a single of list of elements that appear between all of them. This is how I did it:

            DirectoryInfo di = new DirectoryInfo(ConfigurationManager.AppSettings["XMLDirectory"].ToString());
            Dictionary values = new Dictionary();
            FileInfo[] fi = di.GetFiles();
            Response.Write("
");
            Response.Write("
");
            foreach (FileInfo file in fi)
            {
                //Response.Write(@"


");
            }
            Response.Write("

");
            Response.Write("
");
            Response.Write(@"


");
            Response.Write("

");
            Response.Write("
"); //Response.Write("" + file.Name + "
"); XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreWhitespace = true; settings.IgnoreComments = true; settings.ConformanceLevel = ConformanceLevel.Fragment; //Console.WriteLine(file.Name); XmlReader reader = XmlReader.Create(file.Directory + @"\" + file.Name, settings); XDocument document = XDocument.Load(reader); IEnumerable elems = from items in document.Descendants("Bond") select items; foreach (XElement elem in elems) { IEnumerable childElems = from items in elem.Descendants() select items; foreach (XElement xelem in childElems) { //Response.Write(xelem.Name.ToString() + " " + xelem.Parent.Name.ToString() + "
"); if (!values.ContainsKey(xelem.Name.ToString())) { values.Add(xelem.Name.ToString(), xelem.Parent.Name.ToString()); } } } //Response.Write("
"); Response.Write("Combined"); var combined = values .OrderBy(kv => kv.Value); foreach (KeyValuePair kvp in combined) { Response.Write(kvp.Key + " " + kvp.Value + ""); } Response.Write("
");

I use the DirectoryInfo class on a directory, XMLPath in this instance. I then declare an array of type FileInfo, which I then use in a foreach (Enumerate) loop using the FileInfo class. I then use the XMLReader class to read the XML document that is represented through the FileInfo class to read the XML. Inside the foreach loop I create an enumerable instance of XElement called elems which uses LINQ to XML to select all the items. I then create a second enumerable instance of XElements called childElems. I then iterate (enumerate) through the childElems instance and add the Name of the element as the key and the parent as a value to a dictionary of type string,string which I declared earlier. This will loop through all files in the directory and generate a dictionary with combined values. Once its in a dictionary you can simply enumerate through it. I ordered it first by using the OrderBy extension method. Once it has been ordered I enumerate through it with a KeyValuePair and display the combined list. This approach has apparent weaknesses in that it uses the name of a node as a key and the parent as the value. What if two nodes are equal but have different parents? It served a purpose for me though.

The second piece of code I would like to show is an example of converting a dataset to xml and returning the raw XML. Let’s say you have an arbitrary function and you want to return the raw XML of a dataset, you could use:

            StringWriter writer = new StringWriter();
            transactionDS.WriteXml(writer);
            xmlizedString = writer.ToString();

            return xmlizedString;
  • Share/Bookmark

Growing into Learning LINQ to XML

So I forced myself last night to spend time learning LINQ to XML, both from a technical perspective and a theoretical perspective. My aim is to not only know what LINQ to XML is but also to understand why and how. My goal for the next six months is to not skim over source code, but to actually spend time going through it and trying to understand it, and the same applies to LINQ to XML.

I started off with the MSDN article, and my goal is to go through all of the material and to get a good overview of the technology as well as knowing the code that goes with it. So I will try and learn as much of code as possible.

From what I read last night I found a few facts about LINQ to XML interesting:

  • It is a built-in language feature. I already knew this actually. And because it is a built-in language feature it gets to use debugging features as well as be strongly typed
  • LINQ to XML is equivalent to a redesigned XML DOM. You write query expressions that are equivalent to XQuery and XPath in functionality (not syntax).
  • It uses something called functional construction
  • You can create and manipulate XML by saving it, serializing it or sending it over the net
  • The query expression are SQL-like:
    IEnumerable items = from items in purchaseOrder.Descendants(“Items”)
    where (int)items.Element(“Quantity”) * (decimal)items.Element(“USPrice”) > 100
    orderby (string)items.Element(“PartNumber”)
    select items;
    The above sample is taken directly from MSDN
  • Share/Bookmark
Get Adobe Flash playerPlugin by wpburn.com wordpress themes