Reach functionality from other class c# - c#

update
I'm writing a silverlight application and I have the following Class "Home", in this class a read a .xml file a write these to a ListBox. In a other class Overview I will show the same .xml file. I know it is stupid to write the same code as in the class "Home".
The problem is, how to reach these data.
My question is how can I reuse the method LoadXMLFile() from another class?
The code.
// Read the .xml file in the class "Home"
public void LoadXMLFile()
{
WebClient xmlClient = new WebClient();
xmlClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(XMLFileLoaded);
xmlClient.DownloadStringAsync(new Uri("codeFragments.xml", UriKind.RelativeOrAbsolute));
}
private void XMLFileLoaded(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
string xmlData = e.Result;
XDocument xDoc = XDocument.Parse(xmlData);
var tagsXml = from c in xDoc.Descendants("Tag") select c.Attribute("name");
List<Tag> lsTags = new List<Tag>();
foreach (string tagName in tagsXml)
{
Tag oTag = new Tag();
oTag.name = tagName;
var tags = from d in xDoc.Descendants("Tag")
where d.Attribute("name").Value == tagName
select d.Elements("oFragments");
var tagXml = tags.ToArray()[0];
foreach (var tag in tagXml)
{
CodeFragments oFragments = new CodeFragments();
oFragments.tagURL = tag.Attribute("tagURL").Value;
//Tags.tags.Add(oFragments);
oTag.lsTags.Add(oFragments);
}
lsTags.Add(oTag);
}
//List<string> test = new List<string> { "a","b","c" };
lsBox.ItemsSource = lsTags;
}
}

Create a class to read the XML file, make references to this from your other classes in order to use it. Say you call it XmlFileLoader, you would use it like this in the other classes:
var xfl = new XmlFileLoader();
var data = xfl.LoadXMLFile();
If I were you, I would make the LoadXMLFile function take a Uri parameter to make it more reusable:
var data = xfl.LoadXMLFile(uriToDownload);

You could create a class whose single responsibility is loading XML and returning it, leaving the class that calls your LoadXmlFile method to determine how to handle the resulting XML.

Related

Fill combobox with XML data

I want to get data from a XML file (https://xml.buienradar.nl/) and fill a combobox with that data. I want each regio from <weerstation regio=>
to be shown in the combobox.
I could not find anything working for me in UWP
Easiest way is to use XElement to load XML and then query over it.
First you need ComboBox in XAML page:
<ComboBox x:Name="Stations" />
Add new event handler for Loaded event and in code behind use this code to load XML and fill ComboBox:
private void MainPage_OnLoaded(object sender, RoutedEventArgs e)
{
var requestUri = new Uri("https://xml.buienradar.nl/");
var httpClient = new HttpClient();
var httpResponse = await httpClient.GetAsync(requestUri);
httpResponse.EnsureSuccessStatusCode();
var httpResponseStream = await httpResponse.Content.ReadAsStreamAsync();
var root = XElement.Load(httpResponseStream);
var stations =
from element in root.Descendants("weerstation")
select element;
foreach (var station in stations)
{
Stations.Items?.Add(station.Attribute("id")?.Value);
}
}
Here is link to source where I get idea.
And also link where you'll find documentation how to do simple HTTP GET request.
You could use LinqToXML to read the data and then set that as the ItemSource.
You can start of with the following snippet (see in action here):
var xml = XDocument.Load("https://xml.buienradar.nl/");
var weerstationList = xml.Descendants("weerstation");
var weerstations = weerstationList.Select(w => new Item()
{
Id = w.Attribute("id").Value,
Name = w.Descendants("stationnaam").First().Value
});
and the following helper class:
public class Item
{
public string Id { get; set; }
public string Name { get; set; }
}
You can then set the list of items weerstations as your ItemSource of the combo-box.

System.ArgumentNullException when trying to access span with Xpath (C#)

So i've been trying to get a program working where I get info from google finance regarding different stock stats. So far I have not been able to get information out of spans. As of now I have hardcoded direct access to the apple stock.
Link to Apple stock: https://www.google.com/finance?q=NASDAQ%3AAAPL&ei=NgItWIG1GIftsAHCn4zIAg
What i can't understand is that I receive correct output when I trying it in the chrome console with the following command:
$x("//*[#id=\"appbar\"]//div//div//div//span");
This is my current code in Visual studio 2015 with Html Agility Pack installed(I suspect a fault in currDocNodeCompanyName):
class StockDataAccess
{
HtmlWeb web= new HtmlWeb();
private List<string> testList;
public void FindStock()
{
var histDoc = web.Load("https://www.google.com/finance/historical?q=NASDAQ%3AAAPL&ei=q9IsWNm4KZXjsAG-4I7oCA.html");
var histDocNode = histDoc.DocumentNode.SelectNodes("//*[#id=\"prices\"]//table//tr//td");
var currDoc = web.Load("https://www.google.com/finance?q=NASDAQ%3AAAPL&ei=CdcsWMjNCIe0swGd3oaYBA.html");
var currDocNodeCurrency = currDoc.DocumentNode.SelectNodes("//*[#id=\"ref_22144_elt\"]//div//div");
var currDocNodeCompanyName = currDoc.DocumentNode.SelectNodes("//*[#id=\"appbar\"]//div//div//div//span");
var histDocText = histDocNode.Select(node => node.InnerText);
var currDocCurrencyText = currDocNodeCurrency.Select(node => node.InnerText);
var currDocCompanyName = currDocNodeCompanyName.Select(node => node.InnerText);
List<String> result = new List<string>(histDocText.Take(6));
result.Add(currDocCurrencyText.First());
result.Add(currDocCompanyName.Take(2).ToString());
testList = result;
}
public List<String> ReturnStock()
{
return testList;
}
}
I have been trying the Xpath expression [text] and received an output that i can work with when using the chrome console but not in VS. I have also been experimenting with a foreach-loop, a few suggested it to others.
class StockDataAccess
{
HtmlWeb web= new HtmlWeb();
private List<string> testList;
public void FindStock()
{
///same as before
var currDoc = web.Load("https://www.google.com/finance?q=NASDAQ%3AAAPL&ei=CdcsWMjNCIe0swGd3oaYBA.html");
HtmlNodeCollection currDocNodeCompanyName = currDoc.DocumentNode.SelectNodes("//*[#id=\"appbar\"]//div//div//div//span");
///Same as before
List <string> blaList = new List<string>();
foreach (HtmlNode x in currDocNodeCompanyName)
{
blaList.Add(x.InnerText);
}
List<String> result = new List<string>(histDocText.Take(6));
result.Add(currDocCurrencyText.First());
result.Add(blaList[1]);
result.Add(blaList[2]);
testList = result;
}
public List<String> ReturnStock()
{
return testList;
}
}
I would really appreciate if anyone could point me in the right direction.
If you check the contents of currDoc.DocumentNode.InnerHtml you will notice that there is no element with the id "appbar", therefore the result is correct, since the xpath doesn't return anything.
I suspect that the html element you're trying to find is generated by a script (js for example), and that explains why you can see it on the browser and not on the HtmlDocument object, since HtmlAgilityPack does not render scripts, it only download and parse the raw source code.

Editing XML node inner text only if has specified value

Hello i need your super help.
Im not soo skilled in C# and i stack for about 6 hours on this. So please if anyone know help me . Thx
I have Xml like this
<COREBASE>
<AGENT>
<AGENT_INDEX>1</AGENT_INDEX>
<AGENT_PORTER_INDEX>
</AGENT_PORTER_INDEX>
<AGENT_NAME>John</AGENT_NAME>
<AGENT_SURNAME>Smith</AGENT_SURNAME>
<AGENT_MOBILE_NUMBER>777777777</AGENT_MOBILE_NUMBER>
</AGENT>
<AGENT>
<AGENT_INDEX>2</AGENT_INDEX>
<AGENT_PORTER_INDEX>1
</AGENT_PORTER_INDEX>
<AGENT_NAME>Charles</AGENT_NAME>
<AGENT_SURNAME>Bukowski</AGENT_SURNAME>
<AGENT_MOBILE_NUMBER>99999999</AGENT_MOBILE_NUMBER>
</AGENT>
</COREBASE>
And I need to select agent by index in windows forms combo box and than edit and save his attributes to xml. I found how to edit and save it but i dont know why but its saved to the first agent and overwrite his attributes in XML but not in the selected one.. :-(
Plese i will be glad for any help
private void buttonEditAgent_Click(object sender, EventArgs e)
{
XmlDocument AgentBaseEdit = new XmlDocument();
AgentBaseEdit.Load("AgentBase.xml");
XDocument AgentBase = XDocument.Load("AgentBase.xml");
var all = from a in AgentBase.Descendants("AGENT")
select new
{
agentI = a.Element("AGENT_INDEX").Value,
porterI = a.Element("AGENT_PORTER_INDEX").Value,
agentN = a.Element("AGENT_NAME").Value,
agentS = a.Element("AGENT_SURNAME").Value,
agentM = a.Element("AGENT_MOBILE_NUMBER").Value,
};
foreach (var a in all)
{
if ("" == textBoxEditAgentIndex.Text.ToString())
{
MessageBox.Show("You must fill Agent Index field !!", "WARNING");
}
else
{
// AgentBaseEdit.SelectSingleNode("COREBASE/AGENT/AGENT_INDEX").InnerText == textBoxEditAgentIndex.Text
if (a.agentI == textBoxEditAgentIndex.Text.ToString())
{
AgentBaseEdit.SelectSingleNode("COREBASE/AGENT/AGENT_INDEX").InnerText = textBoxEditAgentIndex.Text;
AgentBaseEdit.SelectSingleNode("COREBASE/AGENT/AGENT_PORTER_INDEX").InnerText = textBoxEditAgentPorterIndex.Text;
AgentBaseEdit.SelectSingleNode("COREBASE/AGENT/AGENT_NAME").InnerText = textBoxEditAgentName.Text;
AgentBaseEdit.SelectSingleNode("COREBASE/AGENT/AGENT_SURNAME").InnerText = textBoxEditAgentSurname.Text;
AgentBaseEdit.SelectSingleNode("COREBASE/AGENT/AGENT_MOBILE_NUMBER").InnerText = textBoxEditAgentMobile.Text;
AgentBaseEdit.Save("AgentBase.xml");
ClearEditAgentTxtBoxes();
}
}
}
}
Am i on the right way but i dont see the doors or i am totaly wrong ? Thx all. Miko
OK i tried it this way but it didnt changed the inner text
string agentIndex = comboBoxEditAgentI.SelectedItem.ToString();
XmlDocument AgentBaseEdit = new XmlDocument();
AgentBaseEdit.Load("AgentBase.xml");
XDocument AgentBase = XDocument.Load("AgentBase.xml");
var xElemAgent = AgentBase.Descendants("AGENT")
.First(a => a.Element("AGENT_INDEX").Value == agentIndex);
xElemAgent.Element("AGENT_MOBILE_NUMBER").Value = textBoxEditAgentMobile.Text;
xElemAgent.Element("AGENT_SURNAME").Value = textBoxEditAgentSurname.Text;
AgentBaseEdit.Save("AgentBase.xml");
It would be easier if you use Linq2Xml.
int agentIndex = 2;
XDocument xDoc = XDocument.Load(filename);
var xElemAgent = xDoc.Descendants("AGENT")
.First(a => a.Element("AGENT_INDEX").Value == agentIndex.ToString());
//or
//var xElemAgent = xDoc.XPathSelectElement(String.Format("//AGENT[AGENT_INDEX='{0}']",agentIndex));
xElemAgent.Element("AGENT_MOBILE_NUMBER").Value = "5555555";
xDoc.Save(fileName)
PS: namespaces: System.Xml.XPath System.Xml.Linq
It does not work, because you are selecting the first agent explicitly with in each loop
AgentBaseEdit.SelectSingleNode("COREBASE/AGENT/...")
But you can do it easier by reading and changing withing the same xml document. I'm only changing the agent name and replacing it with "test 1", "test 2", ...
XDocument AgentBase = XDocument.Load("AgentBase.xml");
int i = 0;
foreach (XElement el in AgentBase.Descendants("AGENT")) {
el.Element("AGENT_NAME").Value = "test " + ++i;
// ...
}
AgentBase.Save("AgentBase.xml");
UPDATE
However, I'm suggesting you to separate the logic involving the XML handling from the form. Start by creating an Agent class
public class Agent
{
public string Index { get; set; }
public string PorterIndex { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Mobile { get; set; }
}
Then create an interface defining the needed functionality for an agent repository. The advantage of this interface is that it will make it easier later to switch to another kind of repository like a relational database.
public interface IAgentRepository
{
IList<Agent> LoadAgents();
void Save(IEnumerable<Agent> agents);
}
Then create a class that handles the agents. Here is a suggestion:
public class AgentXmlRepository : IAgentRepository
{
private string _xmlAgentsFile;
public AgentXmlRepository(string xmlAgentsFile)
{
_xmlAgentsFile = xmlAgentsFile;
}
public IList<Agent> LoadAgents()
{
XDocument AgentBase = XDocument.Load(_xmlAgentsFile);
var agents = new List<Agent>();
foreach (XElement el in AgentBase.Descendants("AGENT")) {
var agent = new Agent {
Index = el.Element("AGENT_INDEX").Value,
PorterIndex = el.Element("AGENT_PORTER_INDEX").Value,
Name = el.Element("AGENT_NAME").Value,
Surname = el.Element("AGENT_SURNAME").Value,
Mobile = el.Element("AGENT_MOBILE_NUMBER").Value
};
agents.Add(agent);
}
return agents;
}
public void Save(IEnumerable<Agent> agents)
{
var xDocument = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("COREBASE",
agents.Select(a =>
new XElement("AGENT",
new XElement("AGENT_INDEX", a.Index),
new XElement("AGENT_PORTER_INDEX", a.PorterIndex),
new XElement("AGENT_NAME", a.Name),
new XElement("AGENT_SURNAME", a.Surname),
new XElement("AGENT_MOBILE_NUMBER", a.Mobile)
)
)
)
);
xDocument.Save(_xmlAgentsFile);
}
}
The form can now concentrate on the editing logic. The form does not even need to know what kind of repository to use if you inject the repository in the form constructor (of cause the form constructor must declare a parameter of type IAgentRepository):
var myAgentForm = new AgentForm(new AgentXmlRepository("AgentBase.xml"));
myAgentForm.Show();
UPDATE #2
Note that you cannot change a single item within an XML file. You must load all the agents, make an edit and then rewrite the whole file, even if you edited only one agent.
To do this, you can use my LoadAgents method, then pick an agent from the returned list, edit the agent and finally write the agents list back to the file with my Save method. You can find an agent in the list with LINQ:
Agent a = agents
.Where(a => a.Index == x)
.FirstOrDefault();
This returns null if an agent with the required index does not exist. Since Agent is a reference type, you don’t have to write it back to the list. The list is keeping a reference to the same agent as the variable a.

Deserialize iCal using DDay.iCal, can't find the properties

I'm trying to deserialize an iCal file and then map the collection to a custom POCO. The problem is that I'm not sure where the properties are stored.
Here's the Deserialization method
public static IICalendarCollection Deserialize(String iCalUri)
{
var wc = new WebClient();
var result = wc.DownloadString(iCalUri);
using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(result)))
{
var serializer = new iCalendarSerializer();
var collection = (iCalendarCollection)serializer.Deserialize(memoryStream, Encoding.UTF8);
return collection;
}
}
Then in my service, I'm trying to map the properties to my POCO, but I can't find the properties.
var url = string.Format(GoogleICalUrl, calendarID);
var feed = iCalUtility.Deserialize(url);
foreach(var e in feed)
{
calendarModel.title = e.WhereTheHellAreThePropertiesKept;
}
Does anyone know the right way to loop through the iCalendarCollection and get all the properties?
I checked the DDay website but it's been down all day.
After some digging, it turns out that IICalendarCollection has a nested Event collection that needs to be parsed as follows.
var url = string.Format(GoogleICalUrl, calendarID);
var feed = iCalUtility.Deserialize(url);
foreach (var ev in feed.SelectMany(e => e.Events))
{
calendarModel.Add(new CalendarModel {description = ev.Description,
title = ev.Summary});
}

How to save directory list to xml file C#

I have looked all over for this. It could be me just typing the wrong thing in search I'm not sure. So, if you know a good tutorial or example of this please share. I'm trying to learn.
I have a C# Windows Form app I'm working on. I have information (movies in this case) saved in an XML file. I saved the xml file like this.
//Now we add new movie.
XmlElement nodRoot = doc.DocumentElement;
string allMyChildren = nodRoot.InnerText;
string capitalized = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(movieEditNameTextbox.Text);
int indexLookForNewMake = allMyChildren.IndexOf(capitalized);
if (indexLookForNewMake >= 0)
{
MessageBox.Show("Movie is already saved.", "Error");
}
else
{
XmlElement el = doc.CreateElement("Name");
el.InnerText = capitalized;
doc.DocumentElement.AppendChild(el);
//Check if Year is really a Number.
if (movieEditYearTextbox.Text.All(Char.IsDigit))
{
//Remove ' cause it gives errors.
string capitalizedFixed = capitalized.Replace("'", "");
string capitalizedFinalFixed = capitalizedFixed.Replace("\"", "");
//Assign Attribute to each New one.
el.SetAttribute("Name", capitalizedFinalFixed);
el.SetAttribute("Type", movieEditTypeDropdown.Text);
el.SetAttribute("Year", movieEditYearTextbox.Text);
//Reset all fields, they don't need data now.
movieEditNameTextbox.Text = "";
movieEditYearTextbox.Text = "";
movieEditTypeDropdown.SelectedIndex = -1;
removeMovieTextbox.Text = "";
doc.Save("movie.xml");
label4.Text = "Movie Has been Edited";
loadXml();
}
else
{
//Error out. Year not a Number
MessageBox.Show("Check movie year. Seems it isn't a number.", "Error");
}
}
That all works fine. Now what I'm trying to do is make it where you can choose a directory, and it search the directory and sub directories and get file names and save them into the XML file.
I used this to try to accomplish this. It does pull the list. But it doesn't save it. It don't save the new information.
I can't use LINQ as it cause a confliction for some reason with other code.
DirectoryInfo dirCustom = new DirectoryInfo(#"D:\Video");
FileInfo[] filCustom;
filCustom = dirCustom.GetFiles("*",SearchOption.AllDirectories);
//Open XML File.
XmlDocument doc = new XmlDocument();
doc.Load("movie.xml");
XmlElement el = doc.CreateElement("Name");
string fulCustoms = filCustom.ToString();
foreach (FileInfo filFile in filCustom)
{
string capitalized = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(filFile.Name);
string capitalizedFixed = capitalized.Replace("\"", "");
el.SetAttribute("Name", capitalizedFixed);
el.SetAttribute("Type", "EDIT TYPE");
el.SetAttribute("Year", "EDIT YEAR");
richTextBox1.AppendText(capitalizedFixed + "\r\n");
}
doc.Save("movie.xml");
label4.Text = "Movie Has been Edited";
loadXml();
Now, the richTextBox does display the information correctly but it don't save it.
The loadXml() is just my noobish way to refresh the datagridview.
I'm completely lost and don't know where to turn to. I know my coding is probarely horrible, lol. I'm new to this. This is my first more complex application I have worked on.
I can't think of anymore information that would help you understand what I mean. I hope you do.
Thank you so much for your help.
Not sure exactly what your LoadXML() method does but my only piece of advise with your issue is to change the way you are implementing this functionality.
Create an object called Movie
public class Movie
{
public Movie() {}
public String Title { get; set; }
blah... blah...
}
Then create a MovieList
public class MovieList : List<Movie> { }
Then implement the following 2 methods inside the MovieList.
public static void Serialize(String path, MovieList movieList)
{
XmlSerializer serializer = new XmlSerializer(typeof(MovieList));
using (StreamWriter streamWriter = new StreamWriter(path))
{
serializer.Serialize(streamWriter, movieList);
}
}
public static MovieList Deserialize(String path)
{
XmlSerializer serializer = new XmlSerializer(typeof(MovieList));
using (StreamReader streamReader = new StreamReader(path))
{
return (MovieList) serializer.Deserialize(streamReader);
}
}
Thats it... You now have your object serialized and you can retrieve the data to populate through binding or whatever other methods you choose.

Categories

Resources