XML Reader threw Object Null exception, but node exists(?!) - c#

I am hoping someone could enlighten me as to why I am getting the annoying - "xml object reference not set to an instance .." error.
The elements (nodes?) I am looking for seem to exist and I have not misspelled it either :[
I might be doing something stupid here, but any help at all would be greatly appreciated.
My Code:
private void button1_Click(object sender, RoutedEventArgs e)
{
XmlDocument reader = new XmlDocument();
reader.Load("Kotaku - powered by FeedBurner.xml");
XmlNodeList titles = reader.GetElementsByTagName("title");
XmlNodeList dates = reader.GetElementsByTagName("pubDate");
XmlNodeList descriptions = reader.GetElementsByTagName("description");
XmlNodeList links = reader.GetElementsByTagName("link");
for (int i = 0; i < titles.Count; i++)
{
textBox1.AppendText(Environment.NewLine + titles[i].InnerText);
textBox1.AppendText(Environment.NewLine + descriptions[i].InnerText); //<<-- Throws Object Ref Null Exception
textBox1.AppendText(Environment.NewLine + links[i].InnerText);
textBox1.AppendText(Environment.NewLine + dates[i].InnerText); //<<-- Throws Object Ref Null Exception
}
}
The XML I am using is a saved XML page from: http://feeds.gawker.com/kotaku/full
The way I am working on it now is as follows: I have saved the page from the above link (which is an XML page) and put it next to my EXE for easier access.
Then I run the code.

The way that you read RSS is wrong. First get all the items and loop though each item and build the text. Better if you can use StringBuilder and finally convert it to string.
Before access properties of an object you can check for null.
XmlDocument RSSXml = new XmlDocument();
RSSXml.Load("Kotaku - powered by FeedBurner.xml");
XmlNodeList RSSNodeList = RSSXml.SelectNodes("rss/channel/item");
StringBuilder sb = new StringBuilder();
foreach (XmlNode RSSNode in RSSNodeList)
{
XmlNode RSSSubNode;
RSSSubNode = RSSNode.SelectSingleNode("title");
string title = RSSSubNode != null ? RSSSubNode.InnerText : "";
RSSSubNode = RSSNode.SelectSingleNode("link");
string link = RSSSubNode != null ? RSSSubNode.InnerText : "";
RSSSubNode = RSSNode.SelectSingleNode("description");
string desc = RSSSubNode != null ? RSSSubNode.InnerText : "";
RSSSubNode = RSSNode.SelectSingleNode("pubDate");
string pubDate = RSSSubNode != null ? RSSSubNode.InnerText : "";
sb.Append("<font face='arial'><p><b><a href='");
sb.Append(link);
sb.Append("'>");
sb.Append(title);
sb.Append("</a></b><br/>");
sb.Append(desc);
sb.Append(pubDate);
sb.Append("</p></font>");
}
textBox1.Text = sb.ToString();

It cannot run in for loop because number of items in titles, descriptions, links and dates was (at the time when I ran it) respectively: 39 38 39 37.

I checked the source of http://feeds.gawker.com/kotaku/full.
What I see - in the HMTL source at least - there is a <title> element in the channel header too. Which not belongs to any item yet. Isn't it possible, that your code count some additional elements like this when you use title.Count as the limit of your for cicle?
If that is the case, it is possible, that you wont have enough elements in the other arrays in your loop. Did you check this too?

Related

How Can I Parse an XML file using XmlNodeList

I have been tasked with taking one XML file and converting it to a new XML I have no experience working with XML documents but I have been able to get some of the data from the first XML document using the code shown below. Note not all code is being shown just a small example.
XmlDocument rssXmlDoc = new XmlDocument();
// Load the RSS file from the RSS URL
rssXmlDoc.Load("https://agency.governmentjobs.com/jobfeed.cfm?agency=ocso");
// Setup name space
XmlNamespaceManager nsmgr = new XmlNamespaceManager(rssXmlDoc.NameTable);
nsmgr.AddNamespace("joblisting", "http://www.neogov.com/namespaces/JobListing");
// Parse the Items in the RSS file
XmlNodeList rssNodes = rssXmlDoc.SelectNodes("rss/channel/item/");
// Iterate through the items in the RSS file
foreach (XmlNode rssNode in rssNodes)
{
XmlNode rssSubNode = rssNode.SelectSingleNode("title");
string title = rssSubNode != null ? rssSubNode.InnerText : "";
using this code I am able to get most of the elements. I have run into a wall when trying to get data from a child element. The portion of the XML I cannot get is shown below.
<joblisting:department>Supply</joblisting:department>
<guid isPermaLink="true">https://www.governmentjobs.com/careers/ocso/Jobs/2594527</guid>
<joblisting:categories>
<joblisting:category xmlns:joblisting="http://www.neogov.com/namespaces/JobListing" xmlns:atom="http://www.w3.org/2005/Atom">
<CategoryCode>ClericalDataEntry</CategoryCode>
<Category>Clerical & Data Entry</Category>
</joblisting:category>
<joblisting:category
</joblisting:categories>
But I cannot get all of the data. How can I get the value for the element that starts with guid isPermaLink="true"
For the joblisting:categories I have used a foreach loop to read those values
foreach (var item in rssSubNode.SelectNodes("joblisting:categories", nsmgr))
{
rssSubNode = rssSubNode = rssNode.SelectSingleNode("joblisting:category", nsmgr);
string category = rssSubNode != null ? rssSubNode.InnerText : "";
}
How can read the values of those child elements?
To read guid node you can use the follow code. note that use selectSingleNode in node contains the "item" node.
public static void test() {
XmlDocument rssXmlDoc = new XmlDocument();
// Load the RSS file from the RSS URL
rssXmlDoc.Load("https://agency.governmentjobs.com/jobfeed.cfm?agency=ocso");
// Setup name space
XmlNamespaceManager nsmgr = new XmlNamespaceManager(rssXmlDoc.NameTable);
nsmgr.AddNamespace("joblisting", "http://www.neogov.com/namespaces/JobListing");
// Parse the Items in the RSS file
XmlNodeList rssNodes = rssXmlDoc.SelectNodes("rss/channel/item");
// Iterate through the items in the RSS file
foreach (XmlNode rssNode in rssNodes) {
var xmlnode = rssNode.SelectSingleNode("guid ");
System.Console.WriteLine("the value of guid is =>" + xmlnode.InnerText);
XmlNode rssSubNode = rssNode.SelectSingleNode("title");
string title = rssSubNode != null ? rssSubNode.InnerText : "";
}
}

Can't parse XML data with C#

I have been trying to extract one value from a XML file, and then store it on the same file but in another node, I tried all the examples i've found on the net, read XPath Syntax documentation like hell and still can't get it to work.
I must take the <Documento ID="F60T33"> ID Value (which may vary) and copy it into <Reference URI="#F60T33">.
But I can't even do that if I can't manage to parse the lines, most of times node/variables/"", or I get an "object reference not established as object instance error".
Here's the code:
// Create a new XML document.
XmlDocument xmlDoc = new XmlDocument();
// Load an XML file into the XmlDocument object.
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(pfile);
//TEST !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PROBLEMA
XmlNodeList Documentos = xmlDoc.GetElementsByTagName("//Documento");
XmlNodeList DatosDocumento = ((XmlElement)Documentos[0]).GetElementsByTagName("ID");
foreach (XmlElement nodo in DatosDocumento)
{
int I = 0;
XmlNodeList ID = nodo.GetElementsByTagName("ID");
Console.WriteLine("Elemento nombre ... {0}}", ID[i].InnerText);
}
//
XmlNodeList nodes = xmlDoc.SelectNodes("EnvioDTE");
XmlNode nodesimple = xmlDoc.SelectSingleNode("EnvioDTE");
Console.WriteLine("Lista Nodos: " + nodes.Count);
Console.WriteLine("Nodo Simple: " + nodesimple.InnerText);
foreach (XmlNode node in nodes)
{
string id = node.Attributes["ID"].InnerText;
Console.WriteLine(id);
}
I am almost certain the problem is on the XPath Syntax, but I can't get it to work.
Sadly I can't use XDocument as im using .NET 3.5 for this task, I would really appreciate some help on this, by behand apologize my bad english
As the XML file is too big, I'll put it here on this URL
http://puu.sh/bVNDc/31e4da5a26.xml
If you can get your references right for using System.Linq.XDocument you can do:
string idValue = xDocument.XPathSelectElement("//EnvioDTE/SetDTE")
.Attributes().SingleOrDefault(a => a.Name == "ID").Value;

Sample code for converting TFS work item to XML?

I want to write a simple program to query TFS and convert all of the work items to a uniform type XML file and save them to separate files in a folder.
I'm sure this kind of work is commonly enough done, and is very simple - but I can find no samples on the Internet and no way of connecting to TFS programmatically and retrieving only work item info. Would anyone be able to help me out ?
Thanks very much
private TfsTeamProjectCollection GetTfsTeamProjectCollection()
{
TeamProjectPicker workitemPicker = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false, new UICredentialsProvider());
workitemPicker.AcceptButtonText = "workitemPicker.AcceptButtonText";
workitemPicker.Text = "workitemPicker.Text";
workitemPicker.ShowDialog();
if (workitemPicker.SelectedProjects != null || workitemPicker.SelectedProjects.Length > 0)
{
return workitemPicker.SelectedTeamProjectCollection;
}
return null;
}
private WorkItemCollection WorkItemByQuery(TfsTeamProjectCollection projects, string query) //query is likethis:SELECT [System.ID], [System.Title] FROM WorkItems WHERE [System.Title] CONTAINS 'Lei Yang'
{
WorkItemStore wis = new WorkItemStore(projects);
return wis.Query (query );
}
WorkItemCollection is what you want. You can get WorkItems and their properties.
You should use the TFS SDK.
You can find many tutorials on internet like this one.
MSDN will also help you too.
You can use the TFS SDK working with work items. Then all you need to do is convert it into the format you want.
You can fetch the query results as suggested by Lei Yang.
Then start building the XML.
XmlDocument xmlDoc = new XmlDocument();
//XML declaration
XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
// Create the root element
XmlElement rootNode = xmlDoc.CreateElement("WorkItemFieldList");
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
xmlDoc.AppendChild(rootNode);
//Create a new element and add it to the root node
XmlElement parentnode = xmlDoc.CreateElement("UserInput");
Iterate through all the workitem field values
xmlDoc.DocumentElement.PrependChild(parentnode);
//wiTrees of type WorkItemLinkInfo[] is the result of RunLinkQuery
foreach (var item in wiTrees)
{
int fieldcount = workItemStore.GetWorkItem(item.TargetId).Fields.Count;
while (fieldcount > 0)
{
//Create the required nodes
XmlElement mainNode = xmlDoc.CreateElement(workItemStore.GetWorkItem(item.TargetId).Fields[fieldcount -1].Name.ToString().Replace(" ", "-"));
// retrieve the text
//Use the custom method NullSafeToString to handle null values and convert them to String.Empty
XmlText categoryText = xmlDoc.CreateTextNode(workItemStore.GetWorkItem(item.TargetId).Fields[fieldcount - 1].Value.NullSafeToString().ToString());
// append the nodes to the parentNode without the value
parentnode.AppendChild(mainNode);
// save the value of the fields into the nodes
mainNode.AppendChild(categoryText);
fieldcount--;
}
}
// Save to the XML file
xmlDoc.Save("widetails.xml");

C# / XML - Question

I’ve got a problem witch I’ve been trying to solve almost for a week now, but it seems that, unfortunately, I can’t manage it by myself.
Maybe somebody could help me.
I’ve got this type of source XML:
<data>
<para1>24499</para1>
<para2>32080148</para2>
<para4>20e500cc6008d0f8ab1fd108b220ca261f85edd9</para4>
<para6></para6>
<timetype>4</timetype>
<fkcontent>964342</fkcontent>
<season>0</season>
<fmstoken><![CDATA[7bca3c544ad64e526806fb5a6b845148]]></fmstoken>
<fmstoken_user>32010484</fmstoken_user>
<fmstoken_time>1283165972</fmstoken_time>
<fmstoken_renew><![CDATA[http://www.sky.com/logic/fmstoken.php?method=refresh]]></fmstoken_renew>
<adserverXML><![CDATA[http://www.sky.de/dummy.xml]]></adserverXML>
<playlist>
<videoinfo quality="0" name="DSL 1000">
<id>24499</id>
<noad>1</noad>
<productplacement>0</productplacement>
<filename>http://www.sky.com/video/1/V_53511_BB00_E81016_46324_16x9-lq-512x288-vp6-c0_bbb491b3ce64ef667340a21e2bfb3594.f4v</filename>
<title><![CDATA[Who will be the winner?]]></title>
</videoinfo>
<videoinfo quality="1" name="DSL 2000">
<id>24499</id>
<noad>1</noad>
<productplacement>0</productplacement>
<filename>http://www.sky.de/video/1/V_53513_BB00_E81016_46324_16x9-hq-512x288-vp6-c0_fa948bc5429cf28455779666cc59cf5e.f4v</filename>
<title><![CDATA[Who will be the winner?]]></title>
</videoinfo>
</playlist>
</data>
And here are parts of the code that let me get required tag content from xml page above:
private static string getTagContent(string source, string tag)
{
string fullTagBegin = "<" + tag + ">";
string fullTagEnd = "</" + tag + ">";
int indexBegin = source.IndexOf(fullTagBegin) + fullTagBegin.Length;
int indexEnd = source.IndexOf(fullTagEnd);
int indexLength = indexEnd - indexBegin;
if (indexBegin == -1 || indexEnd == -1)
return "UNKNOWN";
return source.Substring(indexBegin, indexLength);
}
public static void Start(String url)
{
try
{
String urlXML = url;
WebClient wClient = new WebClient();
string sourceXML = wClient.DownloadString(urlXML);
sourceXML = sourceXML.Replace("]]>", "");
sourceXML = sourceXML.Replace("<![CDATA[", "");
String para1 = getTagContent(sourceXML, "para1");
String para2 = getTagContent(sourceXML, "para2");
String para4 = getTagContent(sourceXML, "para4");
String timetype = getTagContent(sourceXML, "timetype");
String fkcontent = getTagContent(sourceXML, "fkcontent");
String season = getTagContent(sourceXML, "season");
String fmstoken = getTagContent(sourceXML, "fmstoken");
String fmstoken_user = getTagContent(sourceXML, "fmstoken_user");
String fmstoken_time = getTagContent(sourceXML, "fmstoken_time");
String fmstoken_renew = getTagContent(sourceXML, "fmstoken_renew");
String filename = getTagContent(sourceXML, "filename").Replace("http://", "");
String title = System.Text.RegularExpressions.Regex.Replace(getTagContent(sourceXML, "title"), #"[^a-zA-Z0-9]","_");
The problem is:
everything works fine except the fact, that there are two "filename" and "title" tags in the source xml, but I need to choose only second ones, those that are under this line:
<videoinfo quality="1" name="DSL 2000">,
and somehow skip/ignore first ones, those that are above previous line and right under this line:
<videoinfo quality="0" name="DSL 1000">
I can't figure out how to do that.
(My only guess is that maybe it has something to do with XPathNavigator, but I’m not sure if that’s a right guess, and anyway, I don’t really understand how to use it properly).
Edit: problem solved.
I want to thank everyone who replied for your suggestions.
Really appreciated!
This is really not the right way to go about working with XML in .Net.
You didn't mention which version of .Net you are developing for. Depending on the version look into using XmlDocument, XDocument / LINQ to XML.
MSDN on LINQ to XML
MSDN on XmlDocument
You should really load the XML into XMlDocument object and then edit it.
But if you prefer to use your existing code, this dirty code should do the trick.
int indexBegin = source.IndexOf(fullTagBegin) == source.LastIndexOf(fullTagBegin) ? source.IndexOf(fullTagBegin) + fullTagBegin.Length : source.LastIndexOf(fullTagBegin) + fullTagBegin.Length;
int indexEnd = source.IndexOf(fullTagEnd) == source.LastIndexOf(fullTagEnd) ? source.IndexOf(fullTagEnd) : source.LastIndexOf(fullTagEnd);
This will move the indexes to the last occurrence of whatever tag you're looking for. Just replace your declarations with this ones.
Edit: Additionally, you use this easy few lines to find/manipulate your XML in a much cleaner way.
XmlDocument doc = new XmlDocument();
doc.Load(filename);
// or doc.LoadXML(fullXMLcode);
var elements = doc.GetElementsByTagName("title");
var element = elements.Item(elements.Count - 1); // returns the last element
// element.InnerText gets the value you need. You can use this property to change it, too
Hope this helps.
You need this XPath expression:
/data/playlist/videoinfo[2]/filename | /data/playlist/videoinfo[2]/title
Or
/data/playlist/videoinfo[2]/*[self::filename or self::title]
These expression return a node set with filename and title element in document order.
In C# (I'm not an expert):
XPathDocument doc = new XPathDocument("document.xml");
XPathNodeIterator nodeset = doc.CreateNavigator()
.Select("/data/playlist/videoinfo[2]/*[self::filename or self::title]");
foreach (XPathNavigator node in nodeset)
{
// Your code
}
As many people have already said, XPath and LINQ are both suitable. Here's LINQ to XML sample:
XDocument doc = XDocument.Load("yourXml.xml");
var result =
(from videoInfo in doc.Descendants("videoinfo")
let quality = videoInfo.Attribute("quality")
let name = videoInfo.Attribute("name")
where (quality != null && quality.Value == "1")
&& (name != null && name.Value == "DSL 2000")
select new
{
Title = videoInfo.Element("title"),
FileName = videoInfo.Element("filename")
}
).First();
string title = result.Title.Value;
string fileName = result.FileName.Value;

C# Foreach XML node

I'm trying to add all the nodes in an XML file into a listView, and I'm doing something wrong but I can't for the life of me figure it out even after looking at a load of examples. This is the XML snippet:
<queue>
<slots>
<slot>
<status>Downloading</status>
<filename>file1</filename>
<size>1 GB</size>
</slot>
<slot>
<status>Downloading</status>
<filename>file2</filename>
<size>2 GB</size>
</slot>
</slots>
</queue>
And here's the code:
XDocument xDoc = XDocument.Load(xmlFilePath);
List<Download> list = new List<Download>();
foreach (var download in xDoc.Descendants("slots"))
{
string filename = download.Element("filename").Value;
string size = download.Element("size").Value;
string status = download.Element("status").Value;
list.Add(new Download { Filename = filename, Size = size, Status = status });
}
Any help greatly appreciated as always.
EDIT: To clarify, I'm getting a NullReferenceException on
string filename = download.Element("filename").Value;
And i know the listview is missing, I've not done that bit yet :)
var list = (from download in xDoc.Descendats("slot")
select new Download
{
Filename = (string) download.Element("filename"),
Size = (string) download.Element("size"),
Status = (string) download.Element("status")
}).ToList();
This looks nicer, and since you didn't say what exactly is wrong with your code, it's about all I can do.
Update: just tested this, and it fixes your exception.
The XML in your example works fine. The NullReferenceException is happening because the real XML you're using doesn't have a filename element in one of the slots. You can use
string filename = download.Element("filename") == null ?
String.Empty : download.Element("filename").Value;
instead if there is a possible default for the filename. But more likely correctly handling this exception is better.
void LoadSlots()
{
XmlDocument doc = new XmlDocument();
doc.Load(Environment.CurrentDirectory + "\\queue.xml");
XmlNodeList nodes = doc.SelectNodes("//queue/slots/slot");
foreach (XmlNode node in nodes)
{
string filename = node.Attributes["filename"].InnerText;
string size = node.Attributes["size"].InnerText;
string status = node.Attributes["status"].InnerText;
_slots.Add(filename, size, status);
}
}

Categories