Search code examples
c#xml-parsingwindows-runtimewindows-store-appsazure-blob-storage

how get tags from a XElement


I've developed code like this:

String resultString = await response.Content.ReadAsStringAsync();
Stream resultStream = await response.Content.ReadAsStreamAsync();

XElement rootElement = XDocument.Load(resultStream).Elements().First();
XElement blobs = rootElement.Element("Blobs");
foreach (var blob in blobs.Elements("Blob"))
{
    var t = blob;
}

Now the resultString and resultStream come from HttpClient reposnse. I get the response from an Azure blob REST service (listing), like this:

<EnumerationResults>
    <Blobs>
        <Blob>
            <Name></Name>
            <Url></Url>
            <Properties></Properties>
         </Blob>
         <Blob>
            <Name></Name>
            <Url></Url>
            <Properties></Properties>
         </Blob>
    </Blobs>
</EnumerationResults>

With my code, I've managed to get an IEnumerable<XNode> from <Blobs> BUT I can't get to Name and Url inside the <Blob> element. I get all of it as a string in one line. How do I need to change my code to get each <Blob> and get from it <Name> and <Url>?


Solution

  • Well to start with, once you've loaded the document, you can just use the Root property to get at the root element. You can then get each Blob element using Descendants or via multiple calls to Elements. You can do that outside the foreach loop though:

    var doc = XDocument.Load(resultStream);
    var allBlobs = doc.Root.Elements("Blobs").Elements("Blob");
    

    or var doc = XDocument.Load(resultStream); var allBlobs = doc.Root.Descendants("Blob");

    Now when you iterate over each blob, you can just get the name element using Element again, and get the text content of the element by using the explicit string conversion

    foreach (var blob in allBlobs)
    {
        var nameElement = blob.Element("Name");
        var nameText = (string) nameElement;
        ...
    }
    

    Obviously that can be done as a single statement - I just wanted to keep them separate for clarity. You can then do the same for the URL. Using the string conversion gives you a null reference if the element is missing, whereas using the Value property will give you a NullReferenceException unless you guard against it. Which is more appropriate depends on your use case.

    An alternative approach is to do all the extraction outside your foreach loop, in a query:

    var data = doc.Root.Elements("Blobs").Elements("Blob")
                  .Select(blob => new {
                      Name = (string) blob.Element("Name"),
                      Url = (string) blob.Element("Url");
                  });
    

    Then:

    foreach (var item in data)
    {
        // Use item.Name and item.Data in here
    }