{"id":2335,"date":"2016-03-31T12:01:58","date_gmt":"2016-03-31T10:01:58","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=2335"},"modified":"2025-05-07T12:52:39","modified_gmt":"2025-05-07T10:52:39","slug":"jezyk-caml-jako-jezyk-zapytan-do-list-sharepoint","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/jezyk-caml-jako-jezyk-zapytan-do-list-sharepoint\/","title":{"rendered":"J\u0119zyk CAML jako j\u0119zyk zapyta\u0144 do list SharePoint"},"content":{"rendered":"\n<p>Jednym z fundament\u00f3w platformy <a href=\"http:\/\/sii.pl\/offer-page\/sharepoint\/\">SharePoint<\/a> s\u0105 listy. Listy to obiekty, w kt\u00f3rych przechowywane s\u0105 r\u00f3\u017cnego rodzaju dane. Mo\u017cna je w bardzo du\u017cym uproszczeniu por\u00f3wna\u0107 do tabel w bazie danych. Listy tak jak tabele maj\u0105 swoj\u0105 struktur\u0119 i mog\u0105 si\u0119 mi\u0119dzy sob\u0105 r\u00f3\u017cni\u0107 rodzajem przechowywanych danych. Listy maj\u0105 swoje kolumny oraz typy zawarto\u015bci (przy czym kolumny i typy zawarto\u015bci mo\u017cna zdefiniowa\u0107 r\u00f3wnie\u017c na wy\u017cszym poziomie w celu ich ponownego u\u017cycia). Nieod\u0142\u0105czn\u0105 cz\u0119\u015bci\u0105 programowania na platformie SharePoint jest pobieranie danych z list. W niniejszym artykule postaram si\u0119 w skr\u00f3cie przedstawi\u0107 j\u0119zyk zapyta\u0144 u\u017cywany w SharePoint oraz biblioteki usprawniaj\u0105ce prac\u0119 z nim.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">CAML<\/h2>\n\n\n\n<p>W zwi\u0105zku z tym, \u017ce bezpo\u015brednie odpytywanie bazy <a href=\"https:\/\/sii.pl\/blog\/sharepoint-dla-poczatkujacych-cz-1\/\">SharePoint<\/a> nie jest zalecanym i dopuszczalnym przez Microsoft sposobem pracy z platform\u0105, j\u0119zyk SQL nie jest wykorzystywany do pracy z listami SharePoint. Na potrzeby platformy powsta\u0142 dedykowany j\u0119zyk <a href=\"http:\/\/sii.pl\/client-story\/proces-akceptacji-i-publikowania-procedur-workflow\/\">CAML<\/a>. CAML (Collaborative Application Markup Language) to j\u0119zyk oparty na XML, przy czym wykorzystywany jest nie tylko do odpytywania list, ale te\u017c w wielu innych miejscach (np. przy definicji r\u00f3\u017cnego rodzaju artefakt\u00f3w SharePoint). Mo\u017cemy z niego korzysta\u0107 w ka\u017cdym API SharePoint \u2013 Server Side Object Model, Client Side Object Model, JavaScript Object Model i REST API. Przyk\u0142adowe zapytanie mo\u017ce wygl\u0105da\u0107 tak:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;Query&gt;\n    &lt;Where&gt;\n        &lt;And&gt;\n            &lt;Eq&gt;\n                &lt;FieldRef Name=&quot;LastName&quot; \/&gt;\n                &lt;Value Type=&quot;Text&quot;&gt;Kowalski&lt;\/Value&gt;\n            &lt;\/Eq&gt;\n            &lt;In&gt;\n                &lt;FieldRef Name=&quot;FirstName&quot; \/&gt;\n                &lt;Values&gt;\n                    &lt;Value Type=&quot;Text&quot;&gt;Jan&lt;\/Value&gt;\n                    &lt;Value Type=&quot;Text&quot;&gt;Andrzej&lt;\/Value&gt;\n                    &lt;Value Type=&quot;Text&quot;&gt;Maciej&lt;\/Value&gt;\n                &lt;\/Values&gt;\n            &lt;\/In&gt;\n        &lt;\/And&gt;\n    &lt;\/Where&gt;\n    &lt;OrderBy&gt;\n        &lt;FieldRef Name=&quot;Modified&quot; Ascending=&quot;FALSE&quot; \/&gt;\n    &lt;\/OrderBy&gt;\n&lt;\/Query&gt;\n<\/pre><\/div>\n\n\n<p>Jak wida\u0107 sk\u0142adnia zapytania CAML jest ca\u0142kiem prosta, natomiast jej zwi\u0119z\u0142o\u015b\u0107 pozostawia troch\u0119 do \u017cyczenia. Gdyby\u015bmy zechcieli na przyk\u0142ad doda\u0107 kolejny warunek AND, to nie mogliby\u015bmy doda\u0107 kolejnego warunku do istniej\u0105cego elementu AND, tylko musieliby\u015bmy tworzy\u0107 kolejny i zagnie\u017adzi\u0107 jeden w drugim, poniewa\u017c AND czy OR s\u0105 tutaj wprost traktowane jak operatory dwuargumentowe. Samodzielne pisanie takich zapyta\u0144 i sklejanie ich w kodzie na d\u0142u\u017csz\u0105 met\u0119 mo\u017ce by\u0107 m\u0119cz\u0105ce, nawet przy wykorzystaniu narz\u0119dzi takich jak U2U CAML Query Builder czy podobnych. Przyjrzyjmy si\u0119 zatem innym rozwi\u0105zaniom.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Camlex.NET<\/strong><\/h2>\n\n\n\n<p>Camlex.NET to biblioteka open source napisana w .NET, kt\u00f3ra powsta\u0142a by u\u0142atwi\u0107 tworzenie zapyta\u0144 CAML. Pozwala na wykorzystanie drzew wyra\u017ce\u0144 w spos\u00f3b analogiczny jak w LINQ w celu dynamicznego budowania zapyta\u0144 CAML. Mo\u017cna wi\u0119c powiedzie\u0107, \u017ce pozwala ona na translacj\u0119 drzew wyra\u017ce\u0144 do CAML. Biblioteka ta wspiera prawie wszystkie funkcje CAML i jest na tyle dojrza\u0142a, \u017ce mo\u017cna jej spokojnie u\u017cywa\u0107 na \u015brodowiskach produkcyjnych. Powy\u017csze zapytanie CAML mo\u017cna by sformu\u0142owa\u0107 z wykorzystaniem tej biblioteki w nast\u0119puj\u0105cy spos\u00f3b:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nstring&#x5B;] firstNames = {&quot;Jan&quot;, &quot;Andrzej&quot;, &quot;Maciej&quot;};\nstring caml = Camlex.Query()\n    .Where(x =&gt;\n        (string)x&#x5B;&quot;LastName&quot;] == &quot;Kowalski&quot; &amp;&amp;\n        firstNames.Contains((string)x&#x5B;&quot;FirstName&quot;]))\n    .OrderByDescending(x =&gt; x&#x5B;&quot;Modified&quot;])\n    .ToString();\n<\/pre><\/div>\n\n\n<p>Z pewno\u015bci\u0105 ten spos\u00f3b pisania zapyta\u0144 jest prostszy i bardziej naturalny dla programist\u00f3w C#. Z oczywistych wzgl\u0119d\u00f3w nie wykorzystamy tej biblioteki z poziomu kodu JavaScript \u2013 w tym obszarze na ratunek przychodzi inna biblioteka.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>CamlJs<\/strong><\/h2>\n\n\n\n<p>CamlJs to biblioteka open source napisana w TypeScript, kt\u00f3r\u0105 mo\u017cemy wykorzysta\u0107 z poziomu kodu TypeScript\/JavaScript w spos\u00f3b bardzo podobny do tego z biblioteki Camlex.NET. Tak jak poprzednio biblioteka ta wspiera wi\u0119kszo\u015b\u0107 funkcji CAML i spokojnie mo\u017cna jej u\u017cywa\u0107 w kodzie produkcyjnym. Powy\u017csze zapytanie mogliby\u015bmy zbudowa\u0107 za pomoc\u0105 tej biblioteki w spos\u00f3b nast\u0119puj\u0105cy:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nvar caml = new CamlBuilder()\n    .Where()\n    .TextField(\"LastName\").EqualTo(\"Kowalski\")\n    .And()\n    .TextField(\"FirstName\").In(&#x5B;\"Jan\", \"Andrzej\", \"Maciej\"])\n    .OrderByDesc(\"Modified\")\n    .ToString();\n<\/pre><\/div>\n\n\n<p>Jak wida\u0107 tworzenie zapyta\u0144 w ten spos\u00f3b jest r\u00f3wnie przyjazne jak w przypadku biblioteki Camlex.NET. Warto w zwi\u0105zku z tym rozwa\u017cy\u0107 jej u\u017cycie, je\u015bli programujemy w TypeScript\/JavaScript.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wywo\u0142anie zapyta\u0144 CAML<\/strong><\/h2>\n\n\n\n<p>Gdy mamy ju\u017c zbudowane zapytanie, musimy je jako\u015b wywo\u0142a\u0107 na odpowiedniej li\u015bcie. Oto przyk\u0142ady jak mo\u017cemy to zrobi\u0107 z wykorzystaniem r\u00f3\u017cnych API SharePointa (nie s\u0105 to jednak jedyne sposoby):<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>SSOM (Server Side Object Model)<\/strong><\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nusing (SPSite site = new SPSite(siteUrl))\nusing (SPWeb web = site.OpenWeb())\n{\n    SPList list = web.GetList(listUrl);\n    SPQuery query = new SPQuery { Query = caml };\n    SPListItemCollection items = list.GetItems(query);\n    \/\/ Do something with items\n}\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>CSOM (Client Side Object Model)<\/strong><\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nusing (ClientContext context = new ClientContext(siteUrl))\n{\n    List list = clientContext.Web.Lists.GetByTitle(listTitle);\n    CamlQuery camlQuery = new CamlQuery { ViewXml = caml };\n    ListItemCollection items = list.GetItems(camlQuery);\n    clientContext.Load(items);\n    clientContext.ExecuteQuery();\n    \/\/ Do something with items\n}\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>JSOM (JavaScript Object Model)<\/strong><\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nfunction getItems(siteUrl, listTitle, caml) {\n    var clientContext = new SP.ClientContext(siteUrl);\n    var list = clientContext.get_web().get_lists().getByTitle(listTitle);\n    var camlQuery = new SP.CamlQuery();\n    camlQuery.set_viewXml(caml);\n    this.items = list.getItems(camlQuery);\n    clientContext.load(this.items);\n    clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));        \n}\n \nfunction onQuerySucceeded(sender, args) {\n    \/\/ Do something with this.items\n}\n \nfunction onQueryFailed(sender, args) {\n    \/\/ On query error\n}\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>REST API (z wykorzystaniem jQuery)<\/strong><\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n$.ajax({\n    url: _spPageContextInfo.webAbsoluteUrl + \"\/_api\/Web\/Lists\/getbytitle('listTitle')\/GetItems\",\n    type: \"POST\",\n    headers: {\n        \"Accept\": \"application\/json;odata=verbose\",\n        \"Content-Type\": \"application\/json;odata=verbose\",\n        \"X-RequestDigest\": $(\"#__REQUESTDIGEST\").val()\n    },\n    data: JSON.stringify({\n        query : {\n        __metadata: {\n            type: \"SP.CamlQuery\"\n        },\n        ViewXml: caml\n        }\n    }),\n    success: function (data) {\n        \/\/ On success\n    },\n    error: function (error) {\n        \/\/ On Error\n    }\n});\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Niniejszy artyku\u0142 z pewno\u015bci\u0105 nie wyczerpuje tego do\u015b\u0107 z\u0142o\u017conego tematu. Warto zapozna\u0107 si\u0119 z dokumentacj\u0105 j\u0119zyka CAML na MSDN oraz opisanych wy\u017cej bibliotek. Warto r\u00f3wnie\u017c wiedzie\u0107, \u017ce zapytania CAML to nie jedyny spos\u00f3b w jaki mo\u017cemy odpytywa\u0107 listy SharePoint. W SSOM mo\u017cemy np. jeszcze skorzysta\u0107 z SPMetal (narz\u0119dzie stworzone przez Microsoft), za pomoc\u0105 kt\u00f3rego mo\u017cemy wygenerowa\u0107 kod encji z istniej\u0105cych list i korzysta\u0107 z nich podobnie jak z Entity Framework. W REST API mo\u017cemy z kolei u\u017cy\u0107 jeszcze OData. Postaram si\u0119 przybli\u017cy\u0107 te tematy w przysz\u0142o\u015bci.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Dodatkowe informacje<\/strong><\/h2>\n\n\n\n<p><a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/office\/ms467521.aspx\" rel=\"nofollow\" >MSDN &#8211; Query Schema<\/a><br><a href=\"https:\/\/camlex.codeplex.com\" rel=\"nofollow\" >Camlex.NET<\/a><br><a href=\"https:\/\/camljs.codeplex.com\" rel=\"nofollow\" >CamlJs<\/a><\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;2335&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;3&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 3)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;J\u0119zyk CAML jako j\u0119zyk zapyta\u0144 do list SharePoint&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 3)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Jednym z fundament\u00f3w platformy SharePoint s\u0105 listy. Listy to obiekty, w kt\u00f3rych przechowywane s\u0105 r\u00f3\u017cnego rodzaju dane. Mo\u017cna je w &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/jezyk-caml-jako-jezyk-zapytan-do-list-sharepoint\/\">Continued<\/a><\/p>\n","protected":false},"author":94,"featured_media":2425,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[1512,56,324],"class_list":["post-2335","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-poradnik","tag-sharepoint","tag-caml"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/03\/jezyk-cml-sharepoint.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2335"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/94"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=2335"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2335\/revisions"}],"predecessor-version":[{"id":23484,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2335\/revisions\/23484"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/2425"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=2335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=2335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=2335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}