Here is an example of running a batch update process on Sharepoint 2007 using web services. It was written in C# in Visual Studio 2008.
In this example, I take the value of a text field "Date_x0020_of_x0020_Birth", turn this into a DateTime value, and then use this to update the the value of a DateTime field "Date_x0020_of_x0020_Birth0". Obviously this section of the code will not be particularly generalisable, however I have left in all the code in order to show you the principles involved, and hopefully you will find it useful in building your own batch routines.
In order to get it running, you must create a reference to the Sharepoint Lists web service and call it "ListsService". The SDK shows you how to do this, and is available here:
http://www.microsoft.com/downloads/en/details.aspx?FamilyId=6D94E307-67D9-41AC-B2D6-0074D6286FA9&displaylang=en
The GetListItems() method of the Lists web service is used to query the data, and the UpdateListItems() method is used to update items.
I used an XPathNavigator object to filter only rows that contain data. You could just loop through the nodes if you prefer.
CAML is used to query the Sharepoint list and look for items where the "Date_x0020_of_x0020_Birth" is null. Tailor this to your own needs.
For CAML reference, look at the MSDN article here:
http://msdn.microsoft.com/en-us/library/lists.lists.getlistitems%28v=office.12%29.aspx
The CAML update command uses owshiddenversion, and so is useful in situations where versioning is enabled. Lists without versioning do not need this field.
If the UpdateListItems command returns an error, in my experience this is usually caused by using an incorrect internal name for a field. You may need to add the
URI prefix "urn:schemas-microsoft-com:office:office#" to the field name (e.g. change line 42 to something like: "<Field Name=\"urn:schemas-microsoft-com:office:office#{4}\">{5}</Field>").
Full code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Net;
namespace BatchUpdateDOB
{
class Program
{
static string LogFile = "D:\\BatchUpdateLog.txt"; // Log file location
static void Main(string[] args)
{
try
{
StatusMessage("Writing log file to: " + LogFile);
// Set up the variables to be used.
StringBuilder methodBuilder = new StringBuilder();
string batch = string.Empty;
DateTime currentDate = DateTime.Now;
string formattedDate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(currentDate);
string fieldToReference = "Date_x0020_of_x0020_Birth";
string fieldToUpdate = "Date_x0020_of_x0020_Birth0";
string batchFormat = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<ows:Batch OnError=\"Return\">{0}</ows:Batch>";
// CAML update command for web service
string methodFormat = "<Method ID=\"1\" Cmd=\"Update\">" +
"<Field Name=\"ID\">{1}</Field>" +
"<Field Name=\"FileRef\">{2}</Field>" +
"<Field Name=\"owshiddenversion\">{3}</Field>" +
"<Field Name=\"{4}\">{5}</Field>" +
"</Method>";
//UPDATE THESE TWO LINES TO SITE SPECIFIC VALUES
string siteName = "http://<your site root uri here>";
string listName = "<your list name here>";
//string viewName = ""; // No need for viewname
int rowLimit = 10; //The number of items returned per batch (not used)
StatusMessage("Processing " + siteName + ", List: " + listName + "...");
//Web service setup
//ListService should be the name of your web service reference
ListService.Lists listService = new ListService.Lists();
listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
listService.Url = siteName + "/_vti_bin/Lists.asmx";
//Build CAML query to search for records
XmlDocument camlDocument = new XmlDocument();
XmlNode queryNode = camlDocument.CreateElement("Query");
//queryNode.InnerXml = "<Where><IsNull><FieldRef Name='Date_x0020_of_x0020_Birth'/></IsNull></Where>";
//queryNode.InnerXml = "<OrderBy><FieldRef Name='Country' /></OrderBy>";
XmlNode viewFieldsNode = camlDocument.CreateElement("ViewFields");
viewFieldsNode.InnerXml = "<FieldRef Name='Title' />" +
"<FieldRef Name='owshiddenversion' />" +
"<FieldRef Name='" + fieldToReference + "' />" +
"<FieldRef Name='" + fieldToUpdate + "' />" +
"<FieldRef Name='FileRef' />";
XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");
queryOptionsNode.InnerXml = "<ViewAttributes Scope=\"Recursive\" /><IncludeMandatoryColumns>True</IncludeMandatoryColumns>";
// Get the GUID of the list
XmlNode ndListView = listService.GetListAndView(listName, "");
string listGuid = ndListView.ChildNodes[0].Attributes["Name"].Value;
string listVersion = ndListView.ChildNodes[0].Attributes["Version"].Value;
// Run the CAML query
XmlNode resultNode = listService.GetListItems(listGuid, null, queryNode, viewFieldsNode, rowLimit.ToString(), queryOptionsNode, null);
// If you want to put a rowlimit on, then use this command:
//XmlNode resultNode = listService.GetListItems(listGUID, null, queryNode, viewFieldsNode, rowLimit.ToString(), queryOptionsNode, null);
long totalRecords = 0;
//string itemDOB;
string dob;
DateTime dtDOB;
string owsHiddenVersion;
string fullFileRef;
string owsFileRef;
// Create xpath navigator
XPathNavigator navigator = resultNode.CreateNavigator();
// Set up namespace manager for XPath
XmlNamespaceManager ns = new XmlNamespaceManager(navigator.NameTable);
ns.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
ns.AddNamespace("z", "#RowSetSchema");
// Select only the z:row nodes
XmlNodeList nodes = resultNode.SelectNodes("//*[name()='z:row'] ", ns);
// Iterate through the returned nodes
foreach (XmlNode node in nodes)
{
string itemID = node.Attributes["ows_ID"].InnerText;
try
{
dob = node.Attributes["ows_" + fieldToReference].InnerText;
owsHiddenVersion = node.Attributes["ows_" + "owshiddenversion"].InnerText;
owsFileRef = node.Attributes["ows_" + "FileRef"].InnerText;
// For some reason my data is returned in the format: 2#/listname/path,
// where 2 seems to be an id or version number, and listname/path points to the file in relation to the root site.
// The following strips that out and gets the full path (required for the CAML update)
fullFileRef = siteName + "/" + owsFileRef.Remove(0, owsFileRef.IndexOf("#") + 1);
}
catch(Exception ex)
{
// Ignore this row
//StatusMessage("ERROR: Cannot process: " + node.InnerXml.ToString() + ": " + ex.Message); // If you want to see why, uncomment
continue;
}
if (String.IsNullOrEmpty(dob)) continue; // Ignore list items with no value
dtDOB = Convert.ToDateTime("01/01/1900"); // Set default value for dates before 1900
// Convert date text to DateTime
try
{
dtDOB = Convert.ToDateTime(dob);
}
catch (Exception ex)
{
StatusMessage("Cannot process: " + siteName + "/" + fullFileRef + " DOB: " + dob + ". Setting to 01/01/1900. " + ex.Message);
}
MessageToFile("Processing: " + fullFileRef + ", DOB = " + dob);
methodBuilder.AppendFormat(methodFormat, listGuid, itemID, fullFileRef, owsHiddenVersion, fieldToUpdate, SPUtility.CreateISO8601DateTimeFromSystemDateTime(dtDOB));
// Put the pieces together.
batch = string.Format(batchFormat, methodBuilder.ToString());
//MessageToFile(batch);
//Build CAML command to update using Web service
XmlDocument xmlDoc = new XmlDocument();
XmlElement elBatch = xmlDoc.CreateElement("Batch");
elBatch.SetAttribute("OnError", "Continue");
elBatch.SetAttribute("ListVersion", listVersion.ToString());
elBatch.SetAttribute("ViewName", "");
elBatch.InnerXml = methodBuilder.ToString();
// This line runs the CAML update command
XmlNode updatesResponse = listService.UpdateListItems(listGuid, elBatch);
if (updatesResponse.FirstChild.FirstChild.InnerText != "0x00000000") throw new Exception("Could not update properties.\n\n" + updatesResponse.InnerText + "\n" + updatesResponse.FirstChild.FirstChild.InnerText);
StatusMessage(fullFileRef + " processed...");
totalRecords++;
}
StatusMessage("Completed - " + totalRecords + " processed.");
}
catch (Exception exp)
{
StatusMessage("ERROR: " + exp.Message);
}
}
/// <summary>
/// Display a message
/// </summary>
/// <param name="myMessage"></param>
static void StatusMessage(string myMessage)
{
Console.WriteLine(myMessage.ToString());
MessageToFile(myMessage);
}
/// <summary>
/// Write message to the log file
/// </summary>
/// <param name="myMessage"></param>
static void MessageToFile(string myMessage)
{
using (StreamWriter sw = new StreamWriter(LogFile, true))
{
DateTime now = DateTime.Now;
sw.WriteLine(now.ToString() + ": " + myMessage.ToString());
}
}
}
}