Deleting files from SharePoint (PL/SQL)

Developing with SharePoint web services is just painful sometimes. In order to delete a file, you must write a CAML (Collaborative Application Markup Language) batch with a delete command in it. The odd thing is you must include the absolute location and the ID of the file. Its odd because the ID just has to be any valid ID of a file, not actually the file you want to delete. Can you imagine the BS code logic behind this? This requires the developer to call the the web service once more to lookup the ID (unless you use a statically typed ID of a known persistent file). The call you must make to lookup this ID also retrieves the file contents, ugg, too much extra work when you obviously don't need it, MS.

In order to retrieve the file ID, I use the 'GetItem' call to the 'Copy' web service. If all goes well you well be returned a large set of attribute "Fields" and the file contents in base64, all we need is the "ID" so use something like the following, replace 'response' with the xml(in clob format) you are returned from the web service. ID can also be found on SharePoint if you enable the ID column for the view.
ID := XMLTYPE('response')
     .EXTRACT('//Fields/FieldInformation[@DisplayName="ID"]/@Value'
     ,'xmlns="http://schemas.microsoft.com/sharepoint/soap/')
     .GETSTRINGVAL();

The SOAP web service call to delete a file. The 'UpdateListItems' method in the 'Lists' web service.
Be sure to enter your 'list_name', 'file_id', and 'http://path_to_file'. Be sure to remove any extra whitespace between the batch tags "because CAML is strongly typed" (because MS cant handle squat).
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.microsoft.com/sharepoint/soap/">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:UpdateListItems>
         <soap:listName>list_name</soap:listName>
         <soap:updates>
       <Batch OnError="Continue" 
          ListVersion="1" 
          ViewName="">
         <Method ID="1" Cmd="Delete">
           <Field Name="ID">file_id</Field>
           <Field Name="FileRef">http://path_to_file</Field>
         </Method>
       </Batch>
    </soap:updates>
      </soap:UpdateListItems>
   </soapenv:Body>
</soapenv:Envelope>

6 comments:

  1. Hi Ross,

    I've been experimenting with XMLType and Sharepoint GetListItems web service (using PL/SQL). I am at the point of parsing the XML I got from Sharepoint and all tests that I did were all throwing errors.

    ..And then I came across this post. In my code I am also using XMLTYPE.extract. The bit that's giving me indigestion is the xpath "'//Fields/FieldInformation[@DisplayName="ID"]/@Value'". I've tried various combinations and they were all unsuccessful.

    To give you an idea, below is a sample XML that I get from Sharepoint:














    I hope you can shed some light on this. I basically just want to extract the information (like Title, filename, path, etc) from Sharepoint and save them into an Oracle table. So far I have no luck.

    Please help!


    Thanks!

    jed

    ReplyDelete
  2. For some reasons, my sample (edited) XML does not appear in the post above. Trying to send it again..

    rs:data ItemCount="2"
    z:row
    ows_LinkTitle='Test'
    ows_dtbo='test.docx'
    ows_i9bt='2013-01-07 00:00:00'
    ows_wizf='9;#jed'
    ows_djie='c:\test'
    ows_MetaInfo='1;#'
    ows__ModerationStatus='0'
    ows__Level='1'
    ows_Title='Test'
    ows_ID='1'
    ows_UniqueId='1;#{72E22F7C-C710-471F-B99C-E95A9C7D148F}'
    ows_owshiddenversion='1'
    ows_FSObjType='1;#0'
    ows_Created_x0020_Date='1;#2013-01-06 22:24:36'
    ows_Created='2013-01-06 22:24:36'
    ows_FileLeafRef='1;#1_.000'
    ows_PermMask='0x1b03c431aef'
    ows_Modified='2013-01-06 22:24:36'
    ows_FileRef='1;#sites/mycompany/Lists/JDC List/1_.000'

    z:row ows_LinkTitle='Test2'
    ows_dtbo='test2.jpg'
    ows_i9bt='2013-01-06 00:00:00'
    ows_wizf='9;#jed'
    ows_djie='C:\test'
    ows_MetaInfo='2;#'
    ows__ModerationStatus='0'
    ows__Level='1'
    ows_Title='Test2'
    ows_ID='2'
    ows_UniqueId='2;#{FB89547C-5133-486B-93DB-B3B68E79BE2D}'
    ows_owshiddenversion='1'
    ows_FSObjType='2;#0'
    ows_Created_x0020_Date='2;#2013-01-06 22:25:50'
    ows_Created='2013-01-06 22:25:50'
    ows_FileLeafRef='2;#2_.000'
    ows_PermMask='0x1b03c431aef'
    ows_Modified='2013-01-06 22:25:50'
    ows_FileRef='2;#sites/mycompany/Lists/JDC List/2_.000'

    ReplyDelete
  3. 1) If you replace all '<' with '& l t ;' (without spaces or quotes) and '>' with '& g t ;' it will make the xml safe for publishing. A find/replace should work quickly.

    <rs:data ItemCount="2">
    <z:row
    ows_LinkTitle='Test'
    ows_dtbo='test.docx'
    ows_ID='1'/>
    <z:row
    ows_LinkTitle='Test2'
    ows_dtbo='test2.jpg'
    ows_ID='2' />
    </rs:data>

    I wrote a bunch from my head but couldn't get anything to work with namespaces specifically. I dont have any more time at the moment to figure it out but i will post my notes about xpath anyway.

    Those are as follows:
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    To decrypt my own xpath I am getting the attribute 'Value' from one of many 'FieldInformation' rows in 'Field' that has the attribute DisplayName equal to "ID".

    to equate that to the xml you sent would be something like (this is untested)...


    To return ows_LinkTitle where ows_ID = 2;
    //data/row[@ows_ID='2']/@ows_LinkTitle

    So if you are using this to set a variable in a PL/SLQ function then you need to select a single value. So we chose a single row to get the title.

    You can also use this in a query to get a set of rows.

    Think of moving down the xml tree as you build your xpath. Everything /..something../ is a step into the tree.


    <namespace:parenttag attribute1=value1>
    <namespace:stuff attribute2=value2>
    text
    </namespace:stuff>
    <namespace:child attribute3=value3/>
    <namespace:child attribute3=value3/>
    </namespace:parenttag>

    The @ denotes an attribute, where none mean the contents of the tag.


    Returns "text"
    //parenttag/stuff (ignoring namespaces - for now)

    Returns "value2"
    //parenttag/stuff/@attribute2 (still ignoring namespaces)

    Would error because it returns a multi value (work in query)
    //parenttag/stuff/@attribute2 (still ignoring namespaces)





    ReplyDelete
  4. Hi Ross,

    You just shed (much needed) light on how xpath works. Just an update, I followed your logic of find/replace to remove the unnecessary stuff on the XML. I then parsed the resulting XML by following your explanation of xpath. It worked! :)

    Thank you so much and have a great day! :)

    ReplyDelete
  5. Ahh, good to hear. XPath is extremely useful but crazy as hell.

    Glad you got it to work, have a good one.

    Ross

    ReplyDelete
  6. I feel SQL and various other aspects really help professionals to provide more and more base and wider understanding about complex database technicalities.

    SQL Server Load Rest Api

    ReplyDelete