This tip come from one of my colleagues, but it’s a good ‘un:
For those of you familiar with the Lists.asmx web service in SharePoint, you’ll know that the UpdateListItems() method allows you to apply metadata to a list item. The following XML provides a simple example of how I’ve been using it so far….
<Method ID=’1’ Cmd=’Update’> <Field Name=’ID’ /> <Field Name=’FileRef’>http://site/library/folder1/folder2/mydoc.pdf</Field> <Field Name=’ContentType’>Invoice</Field> <Field Name=’InvoiceNumber’>12345</Field> </Method>
Under normal circumstances, the above XML works just fine. However, if you enable fine grained permissions [Item Level Permissions] in a document library it will break with a permissions related error (even though you have permissions to perform the action!)In this situation what you MUST do is also pass in a value for the ID field, otherwise it won’t work. E.g.:
<Method ID=’1’ Cmd=’Update’> <Field Name=’ID’ >57</Field> <Field Name=’FileRef’>http://site/library/folder1/folder2/mydoc.pdf</Field> <Field Name=’ContentType’>Invoice</Field> <Field Name=’InvoiceNumber’>12345</Field> </Method>
If you’re performing a HTTP PUT to upload your document, you won’t know the ID value, so you’ll need make another web service call to retrieve it. E.g.
XmlNode query = xmlDoc.CreateNode(XmlNodeType.Element, "Query", string.Empty);
query.InnerXml = "<Where><Eq><FieldRef Name='FileRef'/><Value Type='Note'>" + EscapeXmlValue(uri.Path.Substring(1)) + "</Value></Eq></Where>";
XmlNode viewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", string.Empty);
viewFields.InnerXml = "<FieldRef Name='ID'/>";
XmlNode queryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", string.Empty);
queryOptions.InnerXml = "<QueryOptions><ViewAttributes Scope='Recursive' /></QueryOptions>";
XmlNode node = _listsWebService.GetListItems(listGuid, null, query, viewFields, "1", queryOptions, null);
XmlNodeList items = node.SelectNodes("rs:data/z:row", _nsm);
if (items.Count == 0) {
return null;
} else {
//document found. Return the ID
return items[0].Attributes["ows_ID"].Value;
}
}
I would recommend that peeps check through their code to see where they use the UpdateListItem() method and make sure they’re populating the ID value; otherwise things could go pop when the customer switches on fine grained permissions.
By “enable fine grained permissions [Item Level Permissions]” -do you mean that you changed a specific item’s security in the library or do you mean the library itself is no longer inheriting from the site?
I have a situation very similar to yours -except that the ContentType field “refuses” to change. All calls result in the content type being set to the library’s default content type regardless of what I pass in. My library is not inheriting form the site.
Any thoughts?
thanks,
Dan
Hi Dan,
I mean that the Items no longer inherits permissions from the Library – so yes, we changed a specific item’s security without affecting security for other items in the library. Once you’ve done that, by the way, that library ALWAYS has fine grained permissions, even if you change the permissions back.
Anyway, to your question – what message do you get back from the web service? Would it be something like the document is uploaded as a default content type and checked in? Then you update on the content type & metadata might be refused ‘cos checkout was required.
Are you updating an item that you just uploaded or something?
It does not work !!!
the xml missing the Batch tag For exmp
befor Method Tag
Well, yes. I don’t know what else you might be wanting to do in the Batch. You’ve got to figure out some of what you want to do yourself! But the code I’ve posted was the core of what I was having to do, and it worked for me
Hi Andy,
I believe this is applicable to SharePoint 2010 as well. I’m trying to associate the ID of a file I previously uploaded to my SP2010 server and was wondering about the XmlNamespaceManager _nsm object you reference. Where and how should I declare it?
thanks!
-Paul
This post was GREAT and saved me a TON of time after racking my brain over why I was getting a “The URL provided contains an invalid Command or Value. Please check the URL again.” error in the responseXml. I thought having the ID in the Method would’ve been enough, didn’t think it was needed as a field, too. Again, GREAT POST and THANK YOU!!!!
-Tom
For anyone trying to use that Method group alone, you can’t – you need to do it like this:
[edit] Ok, fields messed up when copying, above, because of the “less than” and “greater than” tags in the code, so let’s do it like this: wherever you see “%”, that means use the “less than” or “greater than” sign.
var xmlFields = "";xmlFields += "<Method ID='1' Cmd='Update'>";
xmlFields += "<Field Name='ID'>1</Field>";
xmlFields += "<Field Name='MyColumn'>" + valueToUpdate + "</Field%>";
xmlFields += "</Method%";
var xmlEnvelope = "";
xmlEnvelope += "<?xml version='1.0' encoding='utf-8' ?>";
xmlEnvelope += "<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'%";
xmlEnvelope += "<soap:Body>";
xmlEnvelope += "<UpdateListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'>";
xmlEnvelope += "<listName>My List</listName>";
xmlEnvelope += "<updates>";
xmlEnvelope += "<Batch OnError='Return'>";
xmlEnvelope += xmlFields;
xmlEnvelope += "</Batch>";
xmlEnvelope += "</updates>";
xmlEnvelope += "</UpdateListItems>";
xmlEnvelope += "</soap:Body>";
xmlEnvelope += "</soap:Envelope>";
var xmlResult = new ActiveXObject("MSXML2.XMLHTTP");
var xmlDoc = new DOMParser();
var xmlCommand = new DOMParser();
var bOK = false;
xmlCommand = xmlEnvelope;
HTTP.open("POST",webServiceUrl,false);
HTTP.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/" + webServiceName);
HTTP.setRequestHeader("Content-Type", "text/xml; charset=utf-8);
HTTP.send(xmlCommand);
bOK = xmlDoc.parseFromString(HTTP.responseText, "text/xml");
HTTP = null;
xmlCommand = null;
if (!bOK) {
alert("Error loading XML from HTTP");
}
else
return bOK;
Hi Tom, I took the liberty of fixing your post, and also I’ve enabled < code > tags
Andy –
I have code to update the meta-data on a document in a document library. The code is working perfectly for SharePoint 2007 Versions 12.0.0.6219 and 12.0.0.6421. However moving to a new SharePoint instance, 12.0.6545, the call to UpdateListItems() returns 0×81020030. (“Invalid file name”). This fails only for document libraries.
xml = “” +
“” +
“4″ +
“http://xxx/sites/training/Test/test.doc” +
“2007-12-02T00:00:00Z” +
“”;
doc.LoadXml(xml);
XmlNode batchNode = doc.SelectSingleNode(“//Batch”);
listProxy.Url = “http://xxxx/sites/training/_vti_bin/lists.asmx”;
listProxy.UseDefaultCredentials = true;
XmlNode resultNode = listProxy.UpdateListItems(listID, batchNode);
The result is:
0x81020030Invalid file name
The file name you specified could not be used. It may be the name of an existing file or directory, or you may not have permission to access the file.
<z:row
ows_Modified="2011-03-30 14:18:31"
ows_Modified_x0020_By="2011-03-24 14:34:22"……etc……
Notice the ows_Modified_x0020_By is changed, but ows_Modified is not.
Have you ever seen this error? Thanks if you have any ideas, I've been working on this for days (and days) now……
Oops – sorry, I forgot the code tags – hopefully this looks better:
xml = "<Batch OnError='Continue' PreCalc='TRUE'>" +"<Method ID='1' Cmd='Update'>" +
"<Field Name='ID'>1</Field>" +
"<Field Name='FileRef'>http://xxx/sites/training/Test/test.doc</Field>" +
"<Field Name='Modified'>2011-03-24 14:34:22</Field>" +
"</Method></Batch>";
Nope, sorry, that’s a new one on me. However, Modified By should be a user, not a datetime – so I wonder how that happened. That’s a pretty big error!