Display all values except the null reference object - c#

I have a foreach loop that is pulling data from an XML file, however some fields are blank. When the loop tries to pull a specific value it will sometimes get a null reference exception. Is there a way to single out the variable that has the null value and set it to an empty string while displaying all the other values in an efficient way? For the sake of the example lets say the address field is returning the null value.
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(id);
XmlNodeList person = xmldoc.SelectNodes("//parent/child");
foreach (XmlNode node in person)
{
try
{
var name = node["name"].InnerText;
var phone = node["phone"].InnerText;
var email = node["email"].InnerText;
var address = node["address"].InnerText;
lblPopulate2.Text = name;
lblPopulate7.Text = address;
lblPopulate5.Text = phone;
lblPopulate6.Text = email;
}
catch(NullReferenceException ex)
{
???
}
finally
{
}

You could use the null conditional operator which would return null if the address node is not present, otherwise the InnerText.
var address = node["address"]?.InnerText;
And then the null coalescing operator for setting your Text property:
lblPopulate7.Text = address ?? string.Empty;

Related

Cannot looping DataGridView null values

I'm trying to loop through the DataGridView rows and then send the values for an update in my SQL-DB. I can make the update, but the program crashes when I come to the end of the rows, because then it read a null-value.
Exception: System.NullReferenceException, Additional information: Object reference not set to an instance of an object.
I have two questions:
Why can't I stop the method with return (see below) with my if
statement?
How can I let the loop insert null values in the strings? Some of
my columns it's OK to send null-values to. And some not, is there
any way to choose which?
private void editEmployeeDGV()
{
foreach (DataGridViewRow row in employeeDataGridView.Rows)
{
if (row.Cells["SocialSNColumn"].Value.ToString() == null)
{
return;
}
string SocialSN = row.Cells["SocialSNColumn"].Value.ToString();
string Name = row.Cells["nameColumn"].Value.ToString();
string Surname = row.Cells["SurnameColumn"].Value.ToString();
string Email = row.Cells["EmailColumn"].Value.ToString();
string TelNr = row.Cells["TelNrColumn"].Value.ToString();
string Gender = row.Cells["GenderColumn"].Value.ToString();
string ECName = row.Cells["ECNameColumn"].Value.ToString();
string ECNumber = row.Cells["ECNumberColumn"].Value.ToString();
cont.editEmployeeDGV(SocialSN, Name, Surname, Email, TelNr, Gender, ECName, ECNumber);
}
}
The reason for the exception is that you're trying to call the ToString() method on the Value property, but it's null.
if (row.Cells["SocialSNColumn"].Value.ToString() == null)
{
return;
}
There's no reason to cast to a string first; just test for null:
if (row.Cells["SocialSNColumn"].Value == null)
{
return;
}
Your other lines of code run the same risk of throwing an NRE if any of their Value properties are null. To avoid those, you may want to replace ToString() with the Convert.ToString() method, which replaces null with an empty string:
string SocialSN = Convert.ToString(row.Cells["SocialSNColumn"].Value);
string Name = Convert.ToString(row.Cells["nameColumn"].Value);

Parsing XML: NullReferenceException for Variable Elements

I'm getting a text string from a website and parsing it into an XDocument. I'm looking to feed the value of certain elements into a very simple object (named NWSevent). My problem is that the original string changes and the XML tree varies; sometimes there are numerous events, up to 40, sometimes there is only one, and sometimes there is only one that does not have all the characteristics. If there are no alerts, then the "event" element has a title, but no areaDesc, summary, or severity.
I have two constructors for NWSevent, one takes in a single string, the other takes in four string arguments. I'm having trouble getting around a NullReferenceException. The if statement below can't do it because there is no value to compare. I'd appreciate any help.
public static void ParseWeatherData(String xmlString)
{
String ticker = string.Empty;
XDocument root = XDocument.Parse(xmlString);
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
XNamespace nsCap = XNamespace.Get("urn:oasis:names:tc:emergency:cap:1.1");
//get list of entry elements, set conditions for title, areaDesc, etc
var xlist = root.Descendants(ns + "entry").Select(elem => new
{ //use first or default to deal with possiblity of null return
Title = elem.Descendants(ns + "title").FirstOrDefault(),
AreaDesc = elem.Descendants(nsCap + "areaDesc").FirstOrDefault(),
Severity = elem.Descendants(nsCap + "severity").FirstOrDefault(),
Summary = elem.Descendants(ns + "summary").FirstOrDefault()
});
foreach (var el in xlist) //need to address null values when no alerts
{
if (el.AreaDesc.Value != null) //causes yellow null ERROR; no value exists for el.areaDesc.value
{
String titleIn = el.Title.Value;
String areaIn = el.AreaDesc.Value;
String severityIn = el.Severity.Value;
String summaryIn = el.Summary.Value;
new Models.NWSevent(titleIn, areaIn, severityIn, summaryIn);
}
else
{
String titleIn = el.Title.Value;
new Models.NWSevent(titleIn);
}
}
Embarassing! Props to Dweeberly for pointing it out. I just need to change the if statement from
if (el.AreaDesc.Value != null){}
to if (el.AreaDesc != null){}

get xelement attribute value

I have an XElement that looks like this:
<User ID="11" Name="Juan Diaz" LoginName="DN1\jdiaz" xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/" />
How can I use XML to extract the value of the LoginName attribute? I tried the following, but the q2 "Enumeration yielded no results".
var q2 = from node in el.Descendants("User")
let loginName = node.Attribute(ns + "LoginName")
select new { LoginName = (loginName != null) };
foreach (var node in q2)
{
Console.WriteLine("LoginName={0}", node.LoginName);
}
var xml = #"<User ID=""11""
Name=""Juan Diaz""
LoginName=""DN1\jdiaz""
xmlns=""http://schemas.microsoft.com/sharepoint/soap/directory/"" />";
var user = XElement.Parse(xml);
var login = user.Attribute("LoginName").Value; // "DN1\jdiaz"
XmlDocument doc = new XmlDocument();
doc.Load("myFile.xml"); //load your xml file
XmlNode user = doc.getElementByTagName("User"); //find node by tag name
string login = user.Attributes["LoginName"] != null ? user.Attributes["LoginName"].Value : "unknown login";
The last line of code, where it's setting the string login, the format looks like this...
var variable = condition ? A : B;
It's basically saying that if condition is true, variable equals A, otherwise variable equals B.
from the docs for XAttribute.Value:
If you are getting the value and the attribute might not exist, it is more convenient to use the explicit conversion operators, and assign the attribute to a nullable type such as string or Nullable<T> of Int32. If the attribute does not exist, then the nullable type is set to null.
I ended up using string manipulation to get the value, so I'll post that code, but I would still like to see an XML approach if there is one.
string strEl = el.ToString();
string[] words = strEl.Split(' ');
foreach (string word in words)
{
if (word.StartsWith("LoginName"))
{
strEl = word;
int first = strEl.IndexOf("\"");
int last = strEl.LastIndexOf("\"");
string str2 = strEl.Substring(first + 1, last - first - 1);
//str2 = "dn1\jdiaz"
}
}

Don't have a nullReferenceException on XML Parsing

I have wrote a c# function in order to parse an XML Stream.
My XML can have several nodes.
Example :
<Stream>
<One>nnn</One>
<Two>iii</Two>
<Three>jjj</Three>
</Stream>
But sometimes, it is :
<Stream>
<Two>iii</Two>
</Stream>
Here is my c# code :
var XML = from item in XElement.Parse(strXMLStream).Descendants("Stream") select item;
string strOne = string.Empty;
string strTwo = string.Empty;
string strThree = string.Empty;
if ((item.Element("One").Value != "")
{
strOne = item.Element("One").Value;
}
if ((item.Element("Two").Value != "")
{
strTwo = item.Element("Two").Value;
}
if ((item.Element("Three").Value != "")
{
strThree = item.Element("Three").Value;
}
With this code, if my Stream is full ( Node On, Two and three), there's no problem! But, if my Stream has only the node "Two", I get a NullReferenceException.
Is there a way to avoid this exception (I cannot change my Stream).
Thanks a lot :)
You should check if item.Element("anything") is null before accessing it's Value property.
if (item.Element("Three") != null && item.Element("Three").Value != "")
You need to do:
if (item.Element("One") != null)
{
strOne = item.Element("One").Value;
}
.Element(String) returns null if an element of the name you requested does not exist.
Checking if value != "" is pointless, because all you are preventing is the reassignment of an empty string to the strOne variable, which is already an empty string. Also, if you really needed to do the empty string check, using String.IsNullOrEmpty(String) method is the preferred way.
Instead of accessing Value property (which raises NullReferenceException if element not exist, as you already know) cast elements to strings. You can use ?? to provide default value for non-existing elements:
string strOne = (string)item.Element("One") ?? String.Empty;
string strTwo = (string)item.Element("Two") ?? String.Empty;
string strThree = (string)item.Element("Three") ?? String.Empty;

Check if an element exists when parsing XML

I'm parsing XML. I normally parse it the way I show in the code below which is straightforward The problem is that I don't own the XML I'm parsing and I can't change it. Sometimes there is no thumbnail element (there are no tags) and I get an Exception.
Is there a way to maintain this simplicity and check if the element exists? Or do I have to get first an XElement list with LINQ, to then check it and fill only the existing object properties?
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
XDocument dataDoc = XDocument.Load(new StringReader(e.Result));
var listitems = from noticia in dataDoc.Descendants("Noticia")
select new News()
{
id = noticia.Element("IdNoticia").Value,
published = noticia.Element("Data").Value,
title = noticia.Element("Titol").Value,
subtitle = noticia.Element("Subtitol").Value,
thumbnail = noticia.Element("Thumbnail").Value
};
itemList.ItemsSource = listitems;
}
[Edit]Jon Skeet's answer should be the accepted answer. It is far more readable and easier to apply.[/edit]
Create an extension method like this :
public static string TryGetElementValue(this XElement parentEl, string elementName, string defaultValue = null)
{
var foundEl = parentEl.Element(elementName);
if (foundEl != null)
{
return foundEl.Value;
}
return defaultValue;
}
then, change your code like this :
select new News()
{
id = noticia.TryGetElementValue("IdNoticia"),
published = noticia.TryGetElementValue("Data"),
title = noticia.TryGetElementValue("Titol"),
subtitle = noticia.TryGetElementValue("Subtitol"),
thumbnail = noticia.TryGetElementValue("Thumbnail", "http://server/images/empty.png")
};
This approach allows you to keep a clean code with isolating the check of element presence. It also allow you to define a default value, which can be helpful
Instead of using the Value property, if you cast to string you'll just get a null reference instead:
void wc_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
XDocument dataDoc = XDocument.Load(new StringReader(e.Result));
var listitems = from noticia in dataDoc.Descendants("Noticia")
select new News()
{
id = (string) noticia.Element("IdNoticia"),
published = (string) noticia.Element("Data"),
title = (string) noticia.Element("Titol"),
subtitle = (string) noticia.Element("Subtitol"),
thumbnail = (string) noticia.Element("Thumbnail")
};
itemList.ItemsSource = listitems;
}
That uses the explicit conversion from XElement to string, which handles a null input by returning a null output. The same is true for all explicit conversions on XAttribute and XElement to nullable types, including nullable value types such as int? - you just need to be careful if you're using nested elements. For example:
string text = (string) foo.Element("outer").Element("inner");
will give a null reference if inner is missing, but will still throw an exception if outer is missing.
If you want a "default" value, you can use the null coalescing operator (??):
string text = (string) foo.Element("Text") ?? "Default value";
You could just use the System.Xml.Serialization.XmlSerializer to deserialize it from xml to an object. Then if the element doesn't exist the property of the object will just get it's default value.
Have a look here: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
or the new path
https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer
You may use the code below:
string content = item.Element("Content") == null ? "" : item.Element("Content").Value;

Categories

Resources