0

Im trying to read a certain attributes from following xml file (as console program)

http://api.openweathermap.org/data/2.5/forecast?q=lahti,fin&mode=xml

As you see inside 'forecast' element there are multiple 'time' elements. What I want is to pick certain 'time' element and then pick given thing inside of it (lets say 'symbol') and print all/any attributes it has.

I want to be able to control which 'time' element I pick and which attributes I want to print.

This far all I have managed to do is to print every 'time' element and their attributes and also I managed to print every attribute inside of given 'time' element. But I just can't figure how to control it.

With the following code, I can print everything inside the first 'time' element. Item(0) is the index of element and the for loop makes sure that I don't get empty lines. As you can see from xml file, some 'time' elements has different amount of attributes inside of them so I guess I need to call them By name insted of index.

    static void xmlReader()
    {
        int i;

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(parseLink());

        foreach (XmlNode xmlNode in xmlDoc.DocumentElement.GetElementsByTagName("time").Item(0))
            for (i = 0; i < xmlNode.Attributes.Count; i++)
            {
                Console.WriteLine(xmlNode.Attributes[i].Value);
            }
        Console.ReadKey();

    }

5 Answers 5

1

Use Linq2Xml, it's much easier and convenient.

public static void Main()
{
    var forecast = XDocument.Load(@"http://api.openweathermap.org/data/2.5/forecast?q=lahti,fin&mode=xml")
                            .Root
                            .Element("forecast");

    foreach (var time in forecast.Elements("time")
                                 .Where(e => e.Element("clouds")
                                              .Attribute("value")
                                              .Value == "overcast clouds"))
    {
        Console.WriteLine(time.Element("symbol").Attribute("name").Value);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Using XDocument is a bit easier here...

private static void XmlOutput()
    {
        var filePathAndName = @"http://api.openweathermap.org/data/2.5/forecast?q=lahti,fin&mode=xml";
        var xmlDoc = XDocument.Load(filePathAndName);

        // Get list of Nodes matching the "time" name or any other filters you wish.
        var nodes = xmlDoc.Descendants().Where(nd => nd.Name.LocalName == "time");

        // Filter the node list to only those where the date is as specified (and any other filters you wish).
        // This could be done in the initial linq query - just making it clearer here.
        nodes = nodes.Where(nd => nd.Attributes().Any(cnd => cnd.Name.LocalName == "from" && cnd.Value.Contains("2015-03-07")));

        foreach (XElement element in nodes)
        {
            // For each descendant node where named "symbol"... 
            foreach(var node in element.Descendants().Where(nd => nd.Name.LocalName == "symbol"))
            {
                // Write out these particular attributes ("number" and "name")
                string output = "";
                output += node.Attributes().FirstOrDefault(nd => nd.Name.LocalName == "number").Value;
                output += ", " + node.Attributes().FirstOrDefault(nd => nd.Name.LocalName == "name").Value;
                Console.WriteLine(output);
            }
        }

        Console.ReadKey();
    }

Comments

0

Similar @aush's response, but with some formatting

        var doc = XDocument.Load(@"http://api.openweathermap.org/data/2.5/forecast?q=lahti,fin&mode=xml");
        var forecastEl = doc.Root.Element(XName.Get("forecast"));

        var timeNodes = from e in forecastEl.Elements("time")
                       where e.Element("symbol")
                            .Attribute(XName.Get("name"))
                            .Value == "light snow"
                       select e;

        var colFormat = "{0,-20} {1,-20} {2,-30}";
        Console.WriteLine(colFormat, "TimeFrom", "TimeTo", "SymbolName");
        foreach(var time in timeNodes)
            Console.WriteLine(colFormat
                , time.Attribute("from").Value
                , time.Attribute("to").Value
                , time.Element("symbol").Attribute("name").Value);

Results:

TimeFrom             TimeTo               SymbolName 
2015-03-07T12:00:00  2015-03-07T15:00:00  light snow 
2015-03-07T15:00:00  2015-03-07T18:00:00  light snow

Comments

0

You can use XmlReader (tutorial) as flowing,

Here I get from attribute from time element and name attribute sybol element.. And they are for same Time element. Also added extracting example for value of cloud

 using (XmlReader reader = XmlReader.Create(@"http://api.openweathermap.org/data/2.5/forecast?q=lahti,fin&mode=xml"))
 {
      // Walk through all Elements 
      while (reader.Read())
      {
         // If we meet time element ; go inside and walk 
         if (reader.Name == "time")
         {
               Console.WriteLine("A new TIME ");

               // Extract from attribute
               String from = reader["from"];
               if (from != null)
               {
                    Console.WriteLine("\t From : " + from);
               }

               // Now walk through all elements inside same Time element
               // Here I use do-while ; what we check is End element of time : </time> .. when we walk till we meet </time> we are inside children of same Time
               // That mean we start from <time> and walk till we meet </time>
               do
               {
                    reader.Read();

                    if (reader.Name == "symbol")
                    {
                         // You can use this approach for any Attribute in symbol Element
                         String name = reader["name"];
                         if (name != null)
                         {
                              Console.WriteLine("\t Symbol name :" + name);
                         }
                    }

                    if (reader.Name == "clouds")
                    {
                         String clouds = reader["value"];
                         if (clouds != null)
                         {
                           Console.WriteLine("\t\t Clouds value : " + clouds);
                         }
                     }

              } while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "time");

          }
      }
}

Simply try this on your Console program..

Comments

0

Using my xml library here, you can search for an actual DateTime value like this:

XElement root = XElement.Load(@"http://api.openweathermap.org/data/2.5/forecast?q=lahti,fin&mode=xml");

var search = DateTime.Parse("2015-03-07T21:00:00");

XElement time = root.XPathElement("//time[@from >= {0} and @to > {1}]", search, search);

var value = time.ToString();

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.