in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

Robert J Wheeler

...a blog to remember...

Building A Dynamic CAML Query


 

I started with creating a string builder object


StringBuilder sb = new StringBuilder();


Next I created a string array to hold the clauses I would eventually turn into my CAML values to test for.


StringCollection andClauses = new StringCollection();


Then, I checked the values of the controls by casting to the type which matched those on the page.  I used a switch statement to check the ID of the control.  For simplicity I have included only the <And> clauses and a couple of controls.  You can extend these to include more using a similar method.


switch (ctl.ID)

{

case "field1":

         if(((TextBox)ctl).Text != null && ((TextBox)ctl).Text != "")

         {

             andClauses.Add("<Eq><FieldRef Name=’field1’/><Value Type='Text'>" + ((TextBox)ctl).Text + "</Value></Eq>");

         }

         break;

case "field2":

         if(((DropDownList)ctl).SelectedValue != null && ((DropDownList)ctl).SelectedValue != "")

         {

             andClauses.Add("<Eq><FieldRef Name=’field2’/><Value Type='Choice'>" + ((DropDownList)ctl).SelectedValue + "</Value></Eq>");

         }

         break;

case "field3":

         if(((Microsoft.SharePoint.WebControls.DateTimeControl)ctl).IsDateEmpty == false)

         {

             andClauses.Add("<Geq><FieldRef Name=’field3’/><Value Type='DateTime'>" + Convert.ToDateTime 
             (((Microsoft.SharePoint.WebControls.DateTimeControl)ctl).SelectedDate).ToShortDateString() + "</Value></Geq>");

         }

         break;


Notice the casting for the SharePoint controls.  In order to get to the value that I need, and to trim the value and remove the time from the  DateTimeControl, I have converted the value using the Convert.ToDateTime() method.
 

After looping through the controls and checking for a value posted, it’s time to now loop through the values and build the CAML string.  It is important to note here that a check should be made validating any strings and check for the count of the items.  If there is a count of -1 then the loop will produce a wrong output.


Begin by appending the ‘Where’ clause to the string builder.  If the item is 1, we do not need to add any ‘And’ clauses.


sb = sb.Append("<Where>");

                                                //only 1 item

                                                if(andClauses.Count == 1)

                                                {

                                                                sb = sb.Append(andClauses[0].ToString());

                                                }


When the count is 2, we need to add one ‘And’ clause and add both item to be searched for.


                                                //two items

                                                else if(andClauses.Count == 2)

                                                {

                                                                sb = sb.Append("<And>" + andClauses[0].ToString() + andClauses[1].ToString() + "</And>");

                                                }


When the item count is greater than 2, we will add the ‘And’ clauses based on the count – 1.


                                                else if(andClauses.Count > 2)

                                                {

                                                                for(int i = andClauses.Count - 1; i > 0; i--)

                                                                {

                                                                                sb = sb.Append("<And>");

                                                                }


After adding the proper number of clauses we will add the first two items and close the first ‘And’ clause off.  Then, as we loop through the remaining items, we add another ‘And’ clause after each iteration and close then set.  If you were to add ‘Or’ clauses, you could do the same.


                                                               

                                                                sb = sb.Append(andClauses[0].ToString() + andClauses[1].ToString() + "</And>");

                                                                for(int j = 2; j < andClauses.Count; j++)

                                                                {

                                                                                sb = sb.Append(andClauses[j].ToString() + "</And>");

                                                                }

                                                }


Finally we close the entire set off by adding the closing ‘Where’ clause.


                                                sb = sb.Append("</Where>");


What you should have is a structure that is properly built to issue the query against the list.  As mentioned before, this will work for any number of items and is not limited to the ‘And’ element.  When building the array you can add additional checks, such as a comparison of ‘Or’, whereby you can test for additional parameters passed into the above loops and build an even more complex structure.


 

Comments

 

Robert J Wheeler said:

Occasionally the need arises to build dynamic CAML queries in order to get items from a SharePoint list

September 4, 2007 6:14 PM
 

Mike said:

Check these classes out:

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint;

using System.Data;

using System.Xml;

using System.IO;

using Microsoft.SharePoint.Utilities;

using System.Collections.Specialized;

namespace Staff

{

   public enum CamlConjunction

   {

       And, Or

   }

   public enum CamlOperator

   {

       Neq, Gt, Lt, Eq, DateRangesOverlap, Geq, Leq, Contains, BeginsWith, IsNotNull, IsNull

   }

   public interface ICaml

   {

       string Render();

   }

   public class ValueComparison : ICaml

   {

       ICaml FirstValue;

       ICaml SecondValue;

       CamlConjunction opera;

       public ValueComparison(ICaml firstValue, ICaml secondValue, CamlConjunction conjunction)

       {

           FirstValue = firstValue;

           SecondValue = secondValue;

           this.opera = conjunction;

       }

       #region ICaml Members

       public string Render()

       {

           StringBuilder sb = new StringBuilder("<");

           sb.Append(opera.ToString());

           sb.Append(">");

           sb.Append(FirstValue.Render());

           sb.Append(SecondValue.Render());

           sb.Append("</");

           sb.Append(opera.ToString());

           sb.Append(">");

           return sb.ToString();

       }

       #endregion

   }

   public class FieldRefValue : ICaml

   {

       CamlOperator opera;

       string fieldName; FieldType fieldType; string value;

       public FieldRefValue(string fieldName, FieldType fieldType, string value, CamlOperator opera)

       {

           this.fieldName = fieldName;

           this.fieldType = fieldType;

           this.value = value;

           this.opera = opera;

       }

       #region ICaml Members

       public string Render()

       {

           StringBuilder sb = new StringBuilder("<");

           sb.Append(opera.ToString());

           sb.Append("><FieldRef Name='");

           sb.Append(fieldName);

           sb.Append("' /><Value Type='");

           sb.Append(fieldType.ToString());

           sb.Append("' >");

           sb.Append(value);

           sb.Append("</Value>");

           sb.Append("</");

           sb.Append(opera.ToString());

           sb.Append(">");

           return sb.ToString();

       }

       #endregion

   }

   public enum FieldType

   {

       Text, Lookup, Number, DateTime, User

   }

 internal static class Util

   {

     internal static string DispFormUrl(SPList list)

     {

         SPWeb web = list.ParentWeb;

         string url = list.DefaultViewUrl;

         string siteUrl = web.Site.Url;

         url = url.Remove(url.LastIndexOf("/") + 1);

         url += "DispForm.aspx?ID=";

         if (web.Site.ServerRelativeUrl != "/")

             url = url.Remove(url.IndexOf(web.Site.ServerRelativeUrl), web.Site.ServerRelativeUrl.Length);

         if (siteUrl.EndsWith("/"))

             siteUrl = siteUrl.Remove(siteUrl.LastIndexOf("/"));

         return  web.Site.Url + url;

     }

     internal static string CombineUrls(string webUrl, string url)

     {

         string ret = webUrl.Trim();

         if (!ret.EndsWith("/"))

             ret += "/";

         return ret + url;

     }

     internal static SPQuery CreateQuery(ICaml caml)

     {

       SPQuery ret = new SPQuery();

         ret.Query = "<Where>" + caml.Render() + "</Where>";

         return ret;

     }

     internal static SPQuery CreateQuery(ICaml caml, string[] ViewFieldNames)

     {

         SPQuery ret = new SPQuery();

         ret.Query = "<Where>" + caml.Render() + "</Where>";

         ret.ViewFields = ViewFields(ViewFieldNames);

         return ret;

     }

     internal static SPQuery CreateQuery(string[] internalFieldNames)

     {

         SPQuery ret = new SPQuery();

         ret.ViewFields = ViewFields(internalFieldNames);

         return ret;

     }

     internal static void Log(Guid siteGuid, Guid webGuid, Exception ex, string title)

     {

         Log(siteGuid, webGuid, title, ex.Message, ex.Source, ex.StackTrace, "Exception");

     }

     internal static void Log(Guid siteGuid, Guid webGuid, string title, string message, string source, string stackTrace, string logType)

     {

         try

         {

             using (SPSite site = new SPSite(siteGuid))

             using (SPWeb web = site.OpenWeb(webGuid))

             {

                 SPList logList = web.Lists["NewsletterLog"];

                 SPListItem logItem = logList.Items.Add();

                 logItem["Title"] = title;

                 logItem["Message"] = message;

                 logItem["Source"] = source;

                 logItem["StackTrace"] = stackTrace;

                 logItem["LogType"] = logType;

                 logItem.Update();

             }

         }

         catch { }

     }

       internal static string FormatValue(string rawValue)

       {

           string val = rawValue;

           if (val.Contains(";#"))

           {

               try

               {

                   val = val.Substring(val.IndexOf(";#") + 2);

               }

               catch { }

           }

           return val;

       }

       internal static string CreateQuery(string fieldName, FieldType fieldType, string value)

       {

           return "<Where><Eq><FieldRef Name='" + fieldName + "' /><Value Type='" + fieldType.ToString() + "' >" + value + "</Value></Eq></Where>";

       }

       internal static string CreateQuery(string fieldName, string value)

       {

           // SPQuery q = new SPQuery();

           return "<Where><Eq><FieldRef Name='" + fieldName + "' /><Value Type='Text' >" + value + "</Value></Eq></Where>";

       }

       internal static string ViewFields(string[] internalFieldNames)

       {

           if (internalFieldNames.Length > 0)

           {

               StringBuilder ret = new StringBuilder();

               foreach (string field in internalFieldNames)

                   ret.Append("<FieldRef Name='" + field + "' />");

               return ret.ToString();

           }

           else

               return string.Empty;

       }

     internal static string ViewFields(StringCollection internalFieldNames)

     {

         if (internalFieldNames.Count > 0)

         {

             StringBuilder ret = new StringBuilder();

             foreach (string field in internalFieldNames)

                 ret.Append("<FieldRef Name='" + field + "' />");

             return ret.ToString();

         }

         else

             return string.Empty;

     }

     internal static bool GetFieldValueBool(SPListItem item, string fieldName)

     {

         bool res = false;

         try

         {

        res =     bool.Parse(item[fieldName].ToString());

         }

         catch { }

         return res;

     }

     internal static string GetFieldValue(SPListItem item, string fieldName)

     {

         string res = string.Empty;

         try

         {

          res =   FormatValue(item[fieldName].ToString());

         }

         catch { }

         return res;

     }

   }

}

February 8, 2008 6:54 PM
 

SharePoint tips and tricks - 20 Feb 08 « Patrick’s Bytes said:

Pingback from  SharePoint tips and tricks - 20 Feb 08 &laquo; Patrick&#8217;s Bytes

February 19, 2008 11:17 AM
 

Dustin Frenton said:

I like the Staff Classes!

I've been looking them over quite a bit.

Were these custom or provided from somewhere?

March 5, 2008 2:44 PM
 

Mike said:

I wrote them a while back.

April 11, 2008 10:18 AM
 

yhyuiyui said:

yiyuiyiyui

May 9, 2008 5:21 AM
 

sondergaard said:

Great stuff!

Heads-up: Getting more conditions in a query is a bit tedious. Here's a good explanation:

sharepointsharpener.wordpress.com/.../several-ands-in-a-caml-query

June 30, 2008 3:59 AM

Leave a Comment

(required )  
(optional )
(required )  
Add

Need SharePoint Training? Attend a SharePoint Bootcamp!

Posts (c) their respective authors. Everything else (c) 2007 SharePoint Experts