📜 ⬆️ ⬇️

Camlex 3.2: reverse engineering CAML and adding conditions to string queries in Sharepoint using lambda expressions

Some time ago came the next release of our open source project Camlex.Net . In version 3.2, quite interesting functionality was added, which I would like to talk about in this article.

First, a few words about what Camlex is and how it helps in development. If you are working with Sharepoint, then you are most likely faced with the need to write CAML requests. CAML (Collaborative Application Markup Language) is a special language used in Sharepoint for various purposes. One of its applications is to write Sql-like queries for fetching data from sheets and document libraries. For example, in order to select all the items from the list, in the Title field which is set to “Meeting”, and in the Description - “Sharepoint”, you need to use the following query:
<Where> <And> <Eq> <FieldRef Name="Title" /> <Value Type="Text">Meeting</Value> </Eq> <Eq> <FieldRef Name="Description" /> <Value Type="Text">Sharepoint</Value> </Eq> </And> </Where> 


If you need to add more conditions to the query, you will have to rebuild the entire Xml-tree (in the CAML, the elements And and Or can have only 2 operands). In addition, if you work with strings, the compiler does not help you, catching errors at the compilation stage.

With Camlex, you can write this query using C # lambda expressions:
 string query = Camlex.Query() .Where(x => (string)x["Title"] == "Meeting" && (string)x["Description"] == "Sharepoint").ToString(); 

In addition, there are many useful things for application developers in Camlex. More details can be found in another article on Habré, which was published about 2 years ago, when we released the first version of the project (we are Vladimir Timashkov and I): Using lambdas to build CAML requests in SharePoint and My blog has articles tagged with Camlex.Net: http://sadomovalex.blogspot.fi/search/label/Camlex.NET .
')
Now directly to the topic of the post. About six months ago, we added quite a non-trivial functionality to the project: reverse engineering CAML. It allows you to parse string queries and create an expression tree (expression tree) based on them. Using reverse engineering, we launched a free online service http://camlex-online.org , with which you can convert string CAML requests to C # code. Those. Camlex turned out the opposite. If the details are interesting, the generation of C # code from the expression tree is made using another open source project, ExpressionToCode (albeit a little doped by us).

We recently received several requests: developers asked if it was possible to add additional conditions to existing CAML requests? The task seemed interesting to me, given the fact that we already have reverse engineering, which is quite doable. In version 3.2 this functionality has been added. Now you can use Camlex together with tools that work with ordinary string queries, expand them with Camlex and transfer the result back as a string.

Let's see an example. Imagine that we have the following query:
 <Where> <Eq> <FieldRef Name="Title" /> <Value Type="Text">Sharepoint</Value> </Eq> </Where> 

He will return the items with the title “Sharepoint”. Suppose that we need to add another condition to the query in order to also get elements with the heading "Office". Now it can be done like this:
 string query = Camlex.Query().WhereAny(existingQuery, x => (string)x["Title"] == "Office").ToString(); 

those. just pass a string query and a new condition in the form of a lambda expression. The result will be as follows:
 <Where> <Or> <Eq> <FieldRef Name="Title" /> <Value Type="Text">Sharepoint</Value> </Eq> <Eq> <FieldRef Name="Title" /> <Value Type="Text">Office</Value> </Eq> </Or> </Where> 

You can also add several conditions at once to more complex string queries. Here is a list of methods that extended the IQuery interface:
 public interface IQuery { // ... IQuery WhereAll(string existingWhere, Expression<Func<SPListItem, bool>> expression); IQuery WhereAll(string existingWhere, IEnumerable<Expression<Func<SPListItem, bool>>> expressions); IQuery WhereAny(string existingWhere, Expression<Func<SPListItem, bool>> expression); IQuery WhereAny(string existingWhere, IEnumerable<Expression<Func<SPListItem, bool>>> expressions); IQuery OrderBy(string existingOrderBy, Expression<Func<SPListItem, object>> expr); IQuery OrderBy(string existingOrderBy, Expression<Func<SPListItem, object[]>> expr); IQuery OrderBy(string existingOrderBy, IEnumerable<Expression<Func<SPListItem, object>>> expressions); IQuery GroupBy(string existingGroupBy, Expression<Func<SPListItem, object>> expr); IQuery GroupBy(string existingGroupBy, Expression<Func<SPListItem, object[]>> expr); } 

Those. You can extend not only query conditions (WhereAll and WhereAny), but also OrderBy and GroupBy. You can also extend the ViewFields, but these methods are in a different interface, because are not part of the overall call chain when constructing a query.

Consider a more complex example. Add to the string query that we received above, two conditions at once: select also elements in which the number of participants is greater than 1 and the status is not empty:
 string existingQuery = "<Where>" + " <And>" + " <Eq>" + " <FieldRef Name=\"Title\" />" + " <Value Type=\"Text\">Sharepoint</Value>" + " </Eq>" + " <Eq>" + " <FieldRef Name=\"Title\" />" + " <Value Type=\"Text\">Office</Value>" + " </Eq>" + " </And>" + "</Where>"; var query = Camlex.Query().WhereAny(existingQuery, x => (int)x["Participants"] > 1 && x["Status"] != null).ToString(); 

As a result, we get:
 <Where> <Or> <And> <Gt> <FieldRef Name="Participants" /> <Value Type="Integer">1</Value> </Gt> <IsNotNull> <FieldRef Name="Status" /> </IsNotNull> </And> <And> <Eq> <FieldRef Name="Title" /> <Value Type="Text">Sharepoint</Value> </Eq> <Eq> <FieldRef Name="Title" /> <Value Type="Text">Office</Value> </Eq> </And> </Or> </Where> 

Those. Camlex takes all the work on the formation of a fairly complex CAML request to itself.

In conclusion, I would like to say that Camlex is a project that evolves from community requests. If you have ideas and suggestions for adding new functionality, write them on the project website in the Discussions section. We try to answer all the questions and, to the extent possible, add new functionality.

Source: https://habr.com/ru/post/146313/


All Articles