I have set up a program that gets my weather for 1 day fine, but I have no idea how to get the other 4 days information because on the xml file the days all have the same name. How do I access the information from the different days?
http://weather.yahooapis.com/forecastrss?w=2473224 The Xml i am using
Code:
string query = String.Format("http://weather.yahooapis.com/forecastrss?w=2473224");
XmlDocument wData = new XmlDocument();
wData.Load(query);
XmlNamespaceManager manager = new XmlNamespaceManager(wData.NameTable);
manager.AddNamespace("yweather", "http://xml.weather.yahoo.com/ns/rss/1.0");
XmlNode channel = wData.SelectSingleNode("rss").SelectSingleNode("channel");
XmlNodeList nodes = wData.SelectNodes("/rss/channel/item/yweather:forecast", manager);
string temperature = channel.SelectSingleNode("item").SelectSingleNode("yweather:condition", manager).Attributes["temp"].Value;
string condition = channel.SelectSingleNode("item").SelectSingleNode("yweather:condition", manager).Attributes["text"].Value;
string humidity = channel.SelectSingleNode("yweather:atmosphere", manager).Attributes["humidity"].Value;
string WindSpeed = channel.SelectSingleNode("yweather:wind", manager).Attributes["speed"].Value;
string town = channel.SelectSingleNode("yweather:location", manager).Attributes["city"].Value;
string tfcond = channel.SelectSingleNode("item").SelectSingleNode("yweather:forecast", manager).Attributes["text"].Value;
string tfhigh = channel.SelectSingleNode("item").SelectSingleNode("yweather:forecast", manager).Attributes["high"].Value;
string tflow = channel.SelectSingleNode("item").SelectSingleNode("yweather:forecast", manager).Attributes["low"].Value;
Well I figured it out by assigning the values to an array like this and using some of the code like this.
var fiveDays = channel.SelectSingleNode("item").SelectNodes("yweather:forecast", manager);
foreach (XmlNode node in fiveDays)
{
var day = node.Attributes["day"].Value;
dayarray[i] = (day);
//
var text = node.Attributes["text"].Value;
textarray[i] = (text);
Thanks for all your help!
I believe you can use the XmlNode.SelectNodes method instead of SelectSingleNode.
This will return a list that you can then iterate through and copy the values to where you need them.
var fiveDays = channel.SelectSingleNode("item").SelectNodes("yweather:forecast", manager);
foreach (XmlNode node in fiveDays)
{
var text = node.Attributes["text"].Value;
var high = node.Attributes["high"].Value;
var low = node.Attributes["low"].Value;
}
This will give you a collection of the upcoming days, you can then loop over them to get the details on each day:
var upcomingDays = channel.SelectSingleNode("item").SelectNodes("yweather:forecast", manager);
foreach(XmlNode d in upcomingDays)
{
//d.Attributes["day"].Value;
}
I ran this in LINQPad and it worked fine.
This is much easier if you use a deserializer like XmlSerializer and classes. With the following classes:
[XmlRoot("rss")]
public class RssRoot
{
[XmlElement("channel")]
public Channel Channel { get; set; }
}
public class Channel
{
[XmlElement("item")]
public Item Item { get; set; }
// add other properties, if relevant
}
public class Item
{
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("forecast", Namespace="http://xml.weather.yahoo.com/ns/rss/1.0")]
public List<Forecast> Forecasts { get; set; }
// add other properties, if relevant
}
public class Forecast
{
[XmlAttribute("text")]
public string Text { get; set; }
// add other attributes, if relevant
}
This will get your data from the URL in query
string query = "http://weather.yahooapis.com/forecastrss?w=2473224";
using (var reader = XmlReader.Create(query))
{
var ser = new XmlSerializer(typeof(RssRoot));
var rss = (RssRoot)ser.Deserialize(reader);
// use rss
}
If you want to continue to work with the XML using XmlDocument, you should use SelectNodes to get multiple forecast nodes, instead of getting a single node.
Related
I have a file .xml inside multiple xml in one line.
How can I read this file and convert to object?
I tried with this code it works if there is only one.
Please help and thank you all
[XmlRoot(ElementName = "DepartmentMaster")]
public class DepartmentMaster
{
[XmlElement(ElementName = "DepartmentId")]
public int DepartmentId { get; set; }
[XmlElement(ElementName = "Name")]
public string Name { get; set; }
[XmlElement(ElementName = "Description")]
public string Description { get; set; }
[XmlElement(ElementName = "test")]
public int Test { get; set; }
}
//string xml = "<DepartmentMaster><DepartmentId>267854</DepartmentId><Name>Purchase</Name><Description>Purchase Department</Description><test>1</test></DepartmentMaster>";
string xml = "<DepartmentMaster><DepartmentId>267854</DepartmentId><Name>Purchase</Name><Description>Purchase Department</Description><test>1</test></DepartmentMaster><DepartmentMaster><DepartmentId>267855</DepartmentId><Name>Purchase5</Name><Description>Purchase Department5</Description><test>5</test></DepartmentMaster>";
using (TextReader reader = new StringReader(xml))
{
System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(DepartmentMaster));
var model = (DepartmentMaster)deserializer.Deserialize(reader);
}
image from the database
image from the database
Here it is two approaches below.
The first is using setting to accept XML data with multiple root elements (ConformanceLevel.Fragment).
private static IList<DepartmentMaster> DeserializeFragment(string xml)
{
var settings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
XmlReader reader = XmlReader.Create(new MemoryStream(Encoding.ASCII.GetBytes(xml)), settings);
var serializer = new XmlSerializer(typeof(DepartmentMaster));
var list = new List<DepartmentMaster>();
while (serializer.Deserialize(reader) is DepartmentMaster element)
{
list.Add(element);
}
return list;
}
And the second by adding a root element to deserialize a well-formed XML document.
public class DepartmentMasters
{
[XmlElement("DepartmentMaster")]
public List<DepartmentMaster> Items;
}
private static DepartmentMasters DeserializeWellFormedXML(string xml)
{
var text = #"<?xml version=""1.0""?><DepartmentMasters>" + xml + "</DepartmentMasters>";
var serializer = new XmlSerializer(typeof(DepartmentMasters));
return (DepartmentMasters)serializer.Deserialize(new StringReader(text));
}
I am developing an application with ASP.NET MVC using Visual Studio 2017 applying the Code First approach. I have three classes (tables) in the model and one repository named DataBase and an interface IDataBase.
I'm trying to store data in memory without using db. I don't now how to add new item in table?
This is my DataBase class (repository):
public class DataBase : IDataBase
{
private List<Proveedor> proveedors;
private List<Factura> facturas;
private List<FacturadeArticulo> facturadeArticulos;
public DataBase()
{
this.proveedors = new List<Proveedor>();
this.facturas = new List<Factura>();
this.facturadeArticulos = new List<FacturadeArticulo>();
}
public Proveedor AddProveedor(Proveedor item)
{
// acces db
if (item == null)
{
throw new ArgumentNullException("item");
}
proveedors.Add(item);
return item;
}
}
My interface IDataBase:
public interface IDatabase
{
Proveedor Add(Proveedor item);
}
My controller
public ActionResult Create(Proveedor provedor)
{
try
{
// TODO: Add insert logic here
var data = this.db.Add(provedor);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I don't now how to implement Add method and save data in memory without using database.
Just for the case, the Entity Framework is not designed for using In-Memory storage.
To do this, you need to implement the appropriate ADO.NET provider: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/data-providers
/**You can Save Data in XML file**/
//You can Save and load time by this method but it's slow process,
it may crash if data is large and system is slow, it stores data runtime
so takes RAM, its ok to use for few rows without any problem
//use the collection for storing data runtime
List<Person> pers = new List<Person>();
public class Person
{
public string id { get; set; }//1
public string name { get; set; }//2
public string bilno { get; set; }//3
public string mob { get; set; }//4
public DateTime dt { get; set; }//5
}
string path=#"c:\.....";
void save()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\data.xml");
XmlNode xnode = xdoc.SelectSingleNode("Items");
xnode.RemoveAll();
foreach (Person i in pers)
{
XmlNode xtop = xdoc.CreateElement("Item");
XmlNode x1 = xdoc.CreateElement("a");
XmlNode x2 = xdoc.CreateElement("b");
XmlNode x3 = xdoc.CreateElement("c");
XmlNode x4 = xdoc.CreateElement("d");
XmlNode x5 = xdoc.CreateElement("e");
x1.InnerText = i.id;
x2.InnerText = i.name;
x3.InnerText = i.bilno;
x4.InnerText = i.mob;
x5.InnerText = i.dt.ToFileTime().ToString();
xtop.AppendChild(x1);
xtop.AppendChild(x2);
xtop.AppendChild(x3);
xtop.AppendChild(x4);
xtop.AppendChild(x5);
xdoc.DocumentElement.AppendChild(xtop);
}
xdoc.Save(path + #"\data.xml");
}
void load()
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(path + #"\data.xml");
foreach (XmlNode xnode in xdoc.SelectNodes("Items/Item"))
{
Person p = new Person();
p.id = xnode.SelectSingleNode("a").InnerText;
p.name = xnode.SelectSingleNode("b").InnerText;
p.bilno = xnode.SelectSingleNode("c").InnerText;
p.mob = xnode.SelectSingleNode("d").InnerText;
p.dt = DateTime.FromFileTime(Convert.ToInt64(xnode.SelectSingleNode("e").InnerText));
}
}
This is a sample xml. If a new font is to be added in the sense, all the existing fonts to be compare with the new font before adding to the preference.
How do I check the node(font) whether already exists or not in case of XmlDocument?
<preferences>
<font role="console">
<size>9</size>
<fname>Courier</fname>
</font>
<font role="default">
<fname>Times New Roman</fname>
<size>14</size>
</font>
<font role="titles">
<size>10</size>
<fname>Helvetica</fname>
</font>
</preferences>
Xnode has a feature called DeepEqual to compare nodes. XmlNode can be converted into Xnode by simple parsing.
XElement XmlElementToXElement(XmlNode e)
{
return XElement.Parse(e.OuterXml);
}
So, it will be easier from here. The method below will return true if two nodes are equal.
bool XmlNode_DeepEquals(XmlNode node1, XmlNode node2)
{
XElement tempX = XmlElementToXElement(node2);
XElement searchX = XmlElementToXElement(node1);
return XNode.DeepEquals(tempX, searchX))
}
This method is for comparing a list of Node.
bool isNodeAlreadyExists(XmlNode searchNode, XmlNodeList list)
{
bool exists = false;
foreach (XmlNode node in list)
{
if (XmlNode_DeepEquals(searchNode, node))
{
exists = true;
}
}
return exists;
}
One approach would be to create a couple of classes to represent the XML document and implement the IEquatable<T> Interface.
https://dotnetfiddle.net/QZFwDy
Classes for XML
[XmlRoot(ElementName = "font")]
public class Font : IEquatable<Font>
{
[XmlElement(ElementName = "size")]
public string Size { get; set; }
[XmlElement(ElementName = "fname")]
public string Fname { get; set; }
[XmlAttribute(AttributeName = "role")]
public string Role { get; set; }
public bool Equals(Font font)
{
if (font == null) return false;
return (Size == font.Size) && (Fname == font.Fname) && (Role == font.Role);
}
}
[XmlRoot(ElementName = "preferences")]
public class Preferences
{
[XmlElement(ElementName = "font")]
public List<Font> Font { get; set; }
}
Then use the Preferences class to deserialize the XML. Once the document is deserialized, leverage the List<T>.Contains(T item) method to see if the font node exists. The .Contains method will call the implementation of Equals in the Font class.
Code to Demonstrate
static void Main(string[] args)
{
Preferences preferences = null;
var xmlString = Data.XML;
using (var stream = new StringReader(xmlString))
{
var serializer = new XmlSerializer(typeof(Preferences));
preferences = (Preferences)serializer.Deserialize(stream);
}
var node0 = new Font()
{
Fname = "New One",
Role = "console",
Size = "12"
};
var node1 = new Font()
{
Fname = "Helvetica",
Role = "titles",
Size = "10"
};
if (preferences.Font.Contains(node0))
{
// Not expecting to enter here
Console.WriteLine($"'{nameof(node0)}' is already present");
}
if (preferences.Font.Contains(node1))
{
Console.WriteLine($"'{nameof(node1)}' is already present");
}
}
I am trying to convert a html list to xml format with a console application, but i did what i planned and now i dont know how to continue. I will share my code and explain a bit. What i dont know for now , and is confusing me is where the 'magic' happens. Ok i know i have to take that list from the page , read the list with all the tags inside, but what next, how can i transform that list into xml format? I am new to xml i know some basics so please help me.
Here is the application :
static void Main(string[] args)
{
string _url = "http://example.com/media";
int newsCounter = 0;
List<News> _newsList = new List<News>();
HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load(_url);
HtmlNode ulNode = doc.DocumentNode.SelectSingleNode("//ul[#class='content articles']");
HtmlNodeCollection liNode = ulNode.SelectNodes(".//li");
foreach (HtmlNode node in ulNode.SelectNodes(".//div[#class='article_box']"))
{
var news = new News();
news.Imgsrc = node.FirstChild.SelectSingleNode("//img").Attributes["src"].Value;
var nodes = doc.DocumentNode.FirstChild.SelectNodes("//img[#src]");
foreach (HtmlNode childNode in node.SelectNodes(".//div[#class='box_info']"))
{
// string src = node.SelectSingleNode("//img").Attributes["src"].Value;
foreach(HtmlNode _node in childNode.SelectNodes(".//h3"))
{
news.Link = "";
news.Title = _node.FirstChild.InnerText;
news.Date = _node.NextSibling.NextSibling.InnerText;
news.Text = _node.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
}
}
_newsList.Add(news);
newsCounter++;
}
and also the News class :
public class News
{
public string Imgsrc { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public string Date { get; set; }
public string Text { get; set; }
}
these are all the parameters i have to read from the list.I am able to read them and return all of the news in my list , but what next , how to transform my list into xml format? Any suggestions are welcomed.
There are many way of creating xml. There are not a lot of items in your case so just using Xml linq is very simple. Putting it into a class may produce cleaner code or you can just use the code directly like Sledge suggested.
public class News
{
public string Imgsrc { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public string Date { get; set; }
public string Text { get; set; }
public XElement ToXml()
{
return new XElement("news", new object[] {
new XElement("Imgscr", Imgsrc),
new XElement("Title", Title),
new XElement("Link", Link),
new XElement("Date", Date),
new XElement("Text", Text),
});
}
}
Thanks to everyone guys. I marked 'News' class as Serializable and with a few lines of code managed to generate the xml file. Here is the code, really simple :
XmlSerializer serializer = new XmlSerializer(typeof(List<News>));
using (TextWriter writer = new StreamWriter(#"D:\News.xml"))
{
serializer.Serialize(writer, _newsList);
}
I want to create XML document with multiple elements inside. The format should be something like this:
<Item>
<Id>2276138</Id>
<Title>92907-03100-00 WASHER, CHAIN</Title>
<Link>http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00</Link>
<Price>0.0000</Price>
<Description>WASHER, CHAIN (92907-03100-00)</Description>
<Condition>New</Condition>
<Brand />
<Product_Type />
<Availability>In Stock</Availability>
<Manufacturer>Suzuki</Manufacturer>
</Item>
Everything is ok after the first loop of fetching data, but once the 2nd loop is done, I have this:
<Item></Item>
<Item>
<Id>2276138</Id>
<Title>92907-03100-00 WASHER, CHAIN</Title>
<Link>http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00</Link>
<Price>0.0000</Price>
<Description>WASHER, CHAIN (92907-03100-00)</Description>
<Condition>New</Condition>
<Brand />
<Product_Type />
<Availability>In Stock</Availability>
<Manufacturer>Suzuki</Manufacturer>
</Item>
So after every round of fetching I get the empty item element and just the last element is populated.
Here is the code for the loop:
while (rdr.Read())
{
if (rdr.HasRows)
{
XmlElement part = docOrders.CreateElement("Item");
id.InnerText = rdr[0].ToString();
part.AppendChild(id);
title.InnerText = rdr[1].ToString();
part.AppendChild(title);
link.InnerText = rdr[2].ToString();
part.AppendChild(link);
price.InnerText = rdr[3].ToString();
part.AppendChild(price);
desc.InnerText = rdr[4].ToString();
part.AppendChild(desc);
cond.InnerText = rdr[5].ToString();
part.AppendChild(cond);
brand.InnerText = rdr[6].ToString();
part.AppendChild(brand);
productType.InnerText = rdr[7].ToString();
part.AppendChild(productType);
availability.InnerText = rdr[8].ToString();
part.AppendChild(availability);
manufacturer.InnerText = rdr[9].ToString();
part.AppendChild(manufacturer);
root.AppendChild(part);
}
}
rdr.Close();
}
How Can I solve this, so the data will be fetched correctly?
Thanks in advance
where do you create the id, title, etc. nodes? It looks like you're reusing these instead of creating new nodes, that's why it's not working correctly.
If you're reusing a child node, it will remove it from the current node and insert it into the new node, that's why you're seeing the empty element.
Also check this question here on SO, basically the same exact problem.
You haven't said which version of .NET you are using. If using .NET 3.5 or above, then I would recommend using LINQ to XML, especially if you can get strongly-typed data from your query. For example:
using System;
using System.Linq;
using System.Xml.Linq;
public class Testing
{
private void Main()
{
var items = new[]
{
new DataItem
{
Id = 2276138,
Title = "92907-03100-00 WASHER, CHAIN",
Link =
new Uri(
"http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00"),
Price = 0.0M,
Description = "WASHER, CHAIN (92907-03100-00)",
Condition = "New",
Availability = "In Stock",
Manufacturer = "Suzuki"
},
new DataItem
{
Id = 2276139,
Title = "92907-03100-01 WASHER, CHAIN",
Link =
new Uri(
"http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00"),
Price = 0.0M,
Description = "WASHER, CHAIN (92907-03100-00)",
Condition = "New",
Availability = "In Stock",
Manufacturer = "Suzuki"
},
new DataItem
{
Id = 2276140,
Title = "92907-03100-02 WASHER, CHAIN",
Link =
new Uri(
"http://www.mywebsite.com/Product.aspx?ProductId=2453575&SKU=92907-03100-00"),
Price = 0.0M,
Description = "WASHER, CHAIN (92907-03100-00)",
Condition = "New",
Availability = "In Stock",
Manufacturer = "Suzuki"
},
};
var doc = new XDocument(
new XElement(
"Items",
from item in items
select
new XElement(
"Item",
new XElement("Id", item.Id),
new XElement("Title", item.Title),
new XElement("Link", item.Link),
new XElement("Price", item.Price),
new XElement("Description", item.Description),
new XElement("Condition", item.Condition),
new XElement("Brand", item.Brand),
new XElement("Product_Type", item.ProductType),
new XElement("Availability", item.Availability),
new XElement("Manufacturer", item.Manufacturer))));
}
public class DataItem
{
public int Id { get; set; }
public string Title { get; set; }
public Uri Link { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public string Condition { get; set; }
public string Brand { get; set; }
public string ProductType { get; set; }
public string Availability { get; set; }
public string Manufacturer { get; set; }
}
}
Have you considered using the System.XML.Serialisation namespaces, which has an XMLSerializer class which does this kind of thing very well for you? There's some MSDN documentation here - http://msdn.microsoft.com/en-us/library/swxzdhc0.aspx - which goes into depth with some good examples, and a shorter description here which has enough for the basics - http://support.microsoft.com/kb/815813