1

Goal: I am trying to retrieve a city name from an xml file

I am using an api that can give me all the information I need by indicating the latitude and longtitude.

This is an URL to the full XML that I am using: http://dev.virtualearth.net/REST/v1/Locations/50,50?o=xml&key=Avu1gnmc6hy50Jsb-l3U_iTbKyOXI2wnsVS1tj7UMtwJxesB9WDZs_qyG0zKgpkZ

And here is an excerpt from the XML that is returned, showing the relevant parts:

<?xml version="1.0" encoding="UTF-8"?>
<Response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/search/local/ws/rest/v1">
    ...
    <ResourceSets>
        <ResourceSet>
            <EstimatedTotal>1</EstimatedTotal>
            <Resources>
                <Location>
                    <Name>Kaztalovskiy rayon, Kazakhstan</Name>
                    ...
                    <Address>
                        <AdminDistrict>Batys Qazaqstan</AdminDistrict>
                        <CountryRegion>Kazakhstan</CountryRegion>
                        <FormattedAddress>Kaztalovskiy rayon, Kazakhstan</FormattedAddress>
                        <Locality>Kaztalovskiy rayon</Locality>
                    </Address>
                    ...
                </Location>
            </Resources>
        </ResourceSet>
    </ResourceSets>
</Response>

This is what I have tried:

HttpClient Client = new HttpClient();

string Result = await Client.GetStringAsync("http://dev.virtualearth.net/REST/v1/Locations/ " + position.Coordinate.Latitude  +", " + position.Coordinate.Longitude +"?o=xml&key=Avu1gnmc6hy50Jsb-l3U_iTbKyOXI2wnsVS1tj7UMtwJxesB9WDZs_qyG0zKgpkZ");

XDocument ResultDocument = XDocument.Parse(Result);
XElement AddressElement = ResultDocument.Root.Element("ResourceSets");

string City = AddressElement.Element("Locality").Value;

I need to get information that's inside the big <ResourceSets> block. Inside it has another block called <Address>.

I am not sure how to get the contents of the <Locality> field from it, I know that it is in the big block of <ResourceSets> but how can I go deeper in it and tell the reader to get me that specific field?

helderdarocha
  • 23,209
  • 4
  • 50
  • 65

2 Answers2

1

There's a simple way to do this with the WinRT XML API:

using Windows.Data.Xml.Dom;

var uri = new Uri("http://dev.virtualearth.net/REST/v1/Locations/50,50?o=xml&key=Avu1gnmc6hy50Jsb-l3U_iTbKyOXI2wnsVS1tj7UMtwJxesB9WDZs_qyG0zKgpkZ");

try
{ 
    var doc = await XmlDocument.LoadFromUriAsync(uri);
    var lc = doc.GetElementsByTagName("Locality");

    if (lc != null && lc[0] != null)
    {
        //lc[0].InnerText is the piece you want
    }
    else
    {
        //Element not in the XML
    }
}
catch
{
    //Handle errors, e.g. no connectivity
}
0

One possibility is to use XPath. It will allow you to select the node you want. Once you set it up it's very simple and you can use it to retrieve other nodes very easily. For examples on how to use it with Linq see System.Xml.XPath and Extensions.XPathSelectElement.

XPath allows you to select the node you want using a path location syntax. Each path step corresponds to a XML node which may be an element, attribute, text, etc. For example, you can select the Locality element using XPath with:

/Response/ResourceSets/ResourceSet/Resources/Location/Address/Locality

You can also use // to skip the details in this case, for example:

/Response//Locality

Since there is only one Locality element in the whole document, you could simply use

//Locality

Your document is a bit more complicated because it has namespaces, and XPath requires you to prefix each element which belongs in a namespace. To do that you will have to register the namespace associating a prefix, and then add that prefix to each element in your path. For example, if you map the ns1 prefix to your "http://schemas.microsoft.com/search/local/ws/rest/v1" namespace then you can use:

//ns1:Locality

o retrieve your data.

You can register the namespaces using System.Xml.XmlNamespaceManager and pass that as an argument when processing your expression.

If you are only going to extract that one value, it might be simpler to just ignore the namespaces and select the local name. //* selects a set of all elements in the file, and [local-name()='Locality'] restricts the set to the elements that have a local name of Locality (ignoring the namespace). So you can simply use this XPath expression to retrieve your data:

//*[local-name()='Locality']

For examples on how to use XPath with Linq see: how to use XPath with XDocument? and Parsing XML using XDocument .

Community
  • 1
  • 1
helderdarocha
  • 23,209
  • 4
  • 50
  • 65