Friday, February 15, 2013

CAML, IntApp, SharePoint


I just got done doing a bunch of work in IntApp Integration Builder where I had to do things like reading/updating SharePoint lists and libraries.

This post/blog is never going to be highly detailed in any one area. I have no interest in explaining CAML, XML, IntApp, web services, logic, etc. There are plenty of resources online to find out how to write a CAML query. The reason I write this stuff down at all is because I have spent a lot of time looking for solutions that have been solved by others... but they don't usually share the information. Lots of questions with few answers. The goal here is to share the answers that I've found so someone else doesn't have to go through the try/fail/try again steps to get the answer.


If you use IntApp, they have a lot of great resources. You'll need to sign up on their customer community portal, but you can then find templates for solutions. This is the barebones "here is how we did this" kind of template that lets you skip past the first 20% of the setup.

So here are the basics:

SharePoint Web Services:
Every MS SharePoint site has a set of web services.
You can access them via URL by adding "_vti_bin/lists.asmx" to the end of your site URL like this:
http://yoursite/_vti_bin/lists.asmx
You'll need to us WSDL format (web services description language) so you add "?wsdl" to the end of the URL.
http://yoursite/_vti_bin/lists.asmx?wsdl
"Lists.asmx" is one of many web services. Lists.asmx gives you access to the lists in your SharePoint site. A library is a sub-type of list, so from now on, I'll just call it a list.

On to the CAML:
(Collaborative Application Markup Language)


You'll need a SOAP (Simple Object Access Protocol) wrapper around your query.
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
     <soap12:Body>

          Your web service call goes here
     </soap12:Body>
</soap12:Envelope>
 You'll also need the web service call. Each web service has multiple functions. I'll use "GetListItems" as the example. The name should be self-explanatory... it "Get"s a "List"s "Items". At least one piece of information you need... "listName" is the GUID of  the list or library that you wish to query.

 <GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">
     <listName>_YOURLISTGUID_</listName>
     <viewName>_YOURVIEWGUID_</viewName>
     Your CAML query goes here (or somewhere in the "GetListItems" tag.) The order shouldn't matter)
     <ViewFields>
          <FieldRef Name="ID" />
          <FieldRef Name="Title" />
          <FieldRef Name="yourfield" />
          ...etc
     </ViewFields>
     <rowLimit>0</rowLimit>
</GetListItems>

Quirk #1:
When querying a SharePoint web service, the "ViewFields" don't matter. You need to have the tag there, and it can be empty "<ViewFields></ViewFields>", but don't bother listing the fields you want to have returned in the dataset. The fields that are returned are defined in the view.
The "viewName" GUID is optional. If you leave it out, the list's "default" view will be used and you will only be able to access the fields that are returned in that default view. So if you've added a custom column into your list and it's not in the default view, you will need to add it there or create another view containing the fields you need and then use "viewName" to tell the web service which view to return.

** How you find your SharePoint list or view GUID? **

OK, So new we just need a query. There a lot of good resources online to figure out how to write a CAML query.

Quirk #2:
Normally your CAML query is wrapped in this:
<Query>...</Query>
With these web services you'll need to put an extra <query> tag (lower-case "q") wrapping the whole thing, like this:
<query><Query>...</Query></query>
If you don't do this, your query will be ignored, the web service will be called, and your dataset will be all values from the view sorted in the default sort order for the view that you've chosen (or the default view if you've not set a viewName GUID). If you've got data returned and the filter or sort doesn't work, this is probably why.


By the way the "<rowLimit>" tag works just fine. Use "0" to return all, or another number to limit the dataset to that number of records.


Here are some MORE TIPS for working with IntApp Relationship Builder and SharePoint web services.

SharePoint Web Service Dataset Basics

More useful information:
The "GetListItems" function of the http://yoursite/_vti_bin/lists.asmx?wsdl SharePoint web service returns XML and you need to have this path to access the returned data:
soap:Envelope/soap:Body/GetListItemsResponse/GetListItemsResult/listitems/rs:data/z:row
The nodes involved (and therefore the path) will differ depending on which web service and function you are calling.

If you work with XML you'll understand nodes and how to decipher the path.
Logically, XML is simply nested data. the first node is soap:Envelope. Inside that is soap:Body, inside that is GetListItemsResponse, and so on.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
            <GetListItemsResult>
                <listitems xmlns:s='uuid:yourGUID' xmlns:dt='uuid:yourGUID' xmlns:rs='urn:schemas-microsoft-com:rowset' xmlns:z='#RowsetSchema'>
                    <rs:data ItemCount="X">
                        <z:row ows_FieldName1='FieldValue' ows_FieldName2='FieldValue'/>
                        <z:row... etc>
                    <rs:data>
                <listitems>
            </GetListItemsResult>
        </GetListItemsResponse>
    </soap:Body>
</soap:Envelope>
Tips:
  • SharePoint prepends "ows_" onto the field names.  i.e. "Title" becomes "ows_Title".
  • Any space in the field name is replaced with "_x0020_". i.e. "My Field" becomes "My_x0020_Field".
  • Calculated fields return "string;#" before the value. i.e. a value of "Jimmy" becomes "string;#Jimmy" and you'll have to strip that or at least compensate for it before you use the data.

Here is a good post on SharePoint field naming conventions over at Web BorG. 

SharePoint GUIDs


A GUID is a Globally Unique Identifier.
Here is how you find your SharePoint list or view GUID:
The easiest way is to go to the list's default view (SP2010) and hover over the "Add Document"/Add New Item" link on the bottom of the page. In the browser status bar you'll see the URL for that link. That URL contains the bare GUID for the list.

http://yoursite/_layouts/Upload.aspx?List={EFG33460-E1F4-4E78-A2F8-CDEG5BE0420B}&RootFolder=

Your GUID is in curly brackets: {EFG33460-E1F4-4E78-A2F8-CDEG5BE0420B}

If you don't have that link to click on, you can go to the list settings, copy the URL and see the GUID in its HTML encoded form in the "List" querystring variable (List=listGUID):
http://yoursite/_layouts/listedit.aspx?List=%7BEFG33460%2DE1F4%2D4E78%2DA2F8%2DCDEG5BE0420B%7D
It takes 5 seconds to manually transform this to a valid GUID. %7B = "{", %7D = "}", and %2D = "-".

List=%7BEFG33460%2DE1F4%2D4E78%2DA2F8%2DCDEG5BE0420B%7D
becomes
List={EFG33460-E1F4-4E78-A2F8-CDEG5BE0420B}

You can get your "view" GUID this way:
Go to the list settings, scroll all the way down to the views, and get the URL from your view (right-click "copy shortcut" or just click on it and copy the page URL). The view GUID is stored in its HTML encoded form in the "View" querystring variable (View=viewGUID). You can then manually decode that using the same logic as described above.
http://yoursite/_layouts/ViewEdit.aspx?List=%7B1637E544%2D5183%2D417B%2DB9DC%2DCD0E2E4EDEE1%7D&View=%7B7E510143%2DD7EA%2D4CFD%2D9A4D%2D65FF5AE909CC%7D&Source=

So.... This
View=%7B7E510143%2DD7EA%2D4CFD%2D9A4D%2D65FF5AE909CC%7D
becomes
View={7E510143-D7EA-4CFD-9A4D-65FF5AE909CC}

Thursday, February 14, 2013

Surface Update 2/12/2013

  • This release will address several 'Limited' Wi-Fi connections issues.
  • Contains driver updates improving performance with Windows, Volume and Power buttons
  • Source: MS Community

    That's pretty limited information. I've not had any problem with the wifi, nor lag of the buttons. Lucky me?

    VMWare View on Surface RT

    Around the first of February, 2013, we finally got a Surface RT app for VMWare View. For me, this turns the device into a work capable device. The app isn't perfect, no PCoIP support, but it's better than nothing.

    Citrix did a good job releasing the Citrix Receiver app last year. Kudos to them.