views:

98

answers:

2

Notice in this code I am trying to check for the existence of the rdfs:range element before trying to select it. I do this to avoid a possible null reference exception at runtime.

        private readonly XNamespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    private readonly XNamespace rdfs = "http://www.w3.org/2000/01/rdf-schema#";
    private readonly XElement ontology;

    public List<MetaProperty> MetaProperties
    {
        get
        {
            return (from p in ontology.Elements(rdf + "Property")
                    select new MetaProperty
                               {
                                   About = p.Attribute(rdf + "about").Value,
                                   Name = p.Element(rdfs + "label").Value,
                                   Comment = p.Element(rdfs + "comment").Value,
                                   RangeUri = p.Elements(rdfs + "range").Count() == 1
                                              ? p.Element(rdfs + "range").Attribute(rdf + "resource").Value
                                              : null
                    }).ToList();
        }
    }

This is kinda bugging me, what I really want to do is something like this:

                                       RangeUri = p.HasElements(rdfs + "range")
                                              ? p.Element(rdfs + "range").Attribute(rdf + "resource").Value
                                              : null

However there is no

p.HasElement(string elementName)

method available.

I guess I could create a method extension to do this, but am wondering if there is something already built in or if there are other ways to do this?

+2  A: 

You can use:

p.Elements(rdfs + "range").SingleOrDefault()

which will return null if there are no elements. It will throw an exception if there's more than one matching element - FirstOrDefault() will avoid this if it's not the desired behaviour.

EDIT: As per my comment, and taking advantage of the conversion from XAttribute to string also handling nulls:

return (from p in ontology.Elements(rdf + "Property") 
        select new MetaProperty 
                   { 
                       About = p.Attribute(rdf + "about").Value, 
                       Name = p.Element(rdfs + "label").Value, 
                       Comment = p.Element(rdfs + "comment").Value, 
                       RangeUri = (string) p.Elements(rdf + "range")
                                            .Attributes(rdf + "resource")
                                            .FirstOrDefault()
                    }).ToList(); 

If you have the same thing in many places, you could write an extension method to encapsulate that very easily:

public static XAttribute FindAttribute(this XElement element,
    XName subElement, XName attribute)
{
    return element.Elements(subElement).Attributes(attribute).FirstOrDefault();
}

So the RangeUri bit would be:

RangeUri = (string) p.FindAttribute(rdf + "range", rdf + "resource")
Jon Skeet
@Jon Good to know, I forgot about the FirstOrDefault functionality. The only potential issue I see with that is that I can't just call .Attribute on it because I don't know if it will return null or not.
Paul Fryer
@Paul: True. You might want to write your own extension method `AttributeOrNull` which accepts nulls appropriately. Alternatively, you could use `Elements(rdfs + "range").Attributes(rdf + "resource").FirstOrDefault()`
Jon Skeet
+1  A: 

Same basic thing, but neater

return (from p in ontology.Elements(rdf + "Property") 
let xRange = p.Element(rdfs + "range") 
                    select new MetaProperty 
                               { 
                                   About = p.Attribute(rdf + "about").Value, 
                                   Name = p.Element(rdfs + "label").Value, 
                                   Comment = p.Element(rdfs + "comment").Value, 
                                   RangeUri = xRange == null ? null :
                                              xRange.Attribute(rdf + "resource").Value 
                                }).ToList(); 
Binary Worrier
@Binary Yes, this is neater. I like it, think I'll use it to do checks on some other properties also.
Paul Fryer