Thoughts on CAML.Net

So first off... for those who don't know SharePoint...  CAML is a bit of swiss army knife... if you understand it, can stand it, and know where to stick it you can pull off some interesting and useful results with SharePoint... I'm no expert however, having only touched it for querying and tweaking it here and there for some custom views. Though I think I can confidently say CAML is a wonderful example of XML Abuse :)

At any rate, one aspect of CAML is being able to write CAML queries to query data sources i.e. SharePoint Lists.... I'm against constructing strings for querying data sources, because they're ugly - and difficult to mutate with code, so I decided to give CAML.Net a try (and ended up using it, albeit reluctantly) - here's an example query in CAML:

    My Content Type      

And then in CAML.Net - at first glance it looks ok:
Console.WriteLine(CAML.Where( CAML.Or( CAML.Eq( CAML.FieldRef("ContentType"), CAML.Value("My Content Type")), CAML.IsNull( CAML.FieldRef("Description")))));

But of course then you look a little closer and see that CAML.Where, CAML.Or, CAML.Eq etc. all return strings... so your not actually building a model of your query - which to me immediately removes a large part of the value for this solution.

Looking around the blog-sphere I see lots of people using CAML.Net, and yet nobody seems to have a problem with the way it works?... it puzzles me... At any rate.. let's dive into why I don't like this approach... with another example:

Console.WriteLine(CAML.Where( CAML.Or( CAML.Eq( CAML.FieldRef("Title"), CAML.Value("My Title")), CAML.Or( CAML.Eq( CAML.FieldRef("ContentType"), CAML.Value("My Content Type")), CAML.IsNull( CAML.FieldRef("Description"))))));

And here's the CAML for that:
    My Title     My Content Type       

Notice the Or inside an Or... this is direct feedback from the CAML query language itself - notably that you can't construct a query with multiple root-level criteria, so your left to construct a tree of Or and And's as required to represent your query - which is ugly, and ultimately confusing - it doesn't express intent well... So my first problem with the CAML.Net approach is it makes me aware of the problems in CAML, when they could've been abstracted away for me... now let's look at a reasonably dynamic CAML query.
string title = "My Title"; string contentType = "My Content Type"; List orFragments = new List(); if (!string.IsNullOrEmpty(title)) { orFragments.Add(CAML.Eq( CAML.FieldRef("Title"), CAML.Value(title))); } if (!string.IsNullOrEmpty(contentType)) { orFragments.Add(CAML.Eq( CAML.FieldRef("ContentType"), CAML.Value(contentType))); } orFragments.Add(CAML.IsNull(CAML.FieldRef("Description"))); string query = CAML.Where( OrCamlRange(orFragments.ToArray()));

And suddenly I'm forced into a world of pain - having to manage the various criteria myself, and strings no less - in this case I'm only using Or's - so I can use a little function to stitch everything into a valid query:
private static string OrCamlRange(string[] items) { if ((items == null) || (items.Length < 1))="" throw="" new="" argumentnullexception("items");="" if="" (items.length="=" 1)="" return="" items[0];="" string[]="" remainingitems="new" string[items.length="" -="" 1];="" array.copy(items,="" 1,="" remainingitems,="" 0,="" remainingitems.length);="" return="" caml.or(items[0],="" orcamlrange(remainingitems));="">

But I can't help feeling that an opportunity for CAML.Net to really shine has been tarnished by an initial design choice of returning strings, instead of models.  At least for my use cases, I would've been much happier with something that returned a model which I could post-parse - to smarten up the experience so I could identify misspelled fields, mutate the query based on user choices etc.

Finally, just to be clear - this is not a dig at John Holliday - CAML.Net's author, he's a smart guy who knows a lot more then I ever will about SharePoint!  It's merely an opinion/observation on the negatives of query building approaches which don't embrace an intermediate model which can be parsed or mutated.

Written on November 11, 2007