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;
}
How to check if xml node exists? To verify if node or tag exists in XML content, you can execute an xpath expression against DOM document for that XML and count the matching nodes. matching nodes > zero – XML tag / attribute exists. matching nodes <= zero – XML tag / attribute does not exist.
Use the fn:nilled XPath function to test whether the value of an input element has the xsi:nil attribute set. Use the fn:exists XPath function to test whether the value of an input element is present. Note: An XML element that has the xsi:nil attribute set is considered to be present.
You can try to load the XML into XML document and catch the exception. Here is the sample code: var doc = new XmlDocument(); try { doc. LoadXml(content); } catch (XmlException e) { // put code here that should be executed when the XML is not valid. }
[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";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With