I've got it working. I needed both the destructiveChanges.xml and the package.xml in the same zip file. Reference - Deleting Files from an Organization.
Zip file contents:
- package.xml
- destructiveChanges.xml
package.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<version>23.0</version>
</Package>
destructiveChanges.xml (Note that I needed to delete the corresponding unit tests in the same deployment):
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>classname</members>
<members>classname_TestCases</members>
<name>ApexClass</name>
</types>
<version>23.0</version>
</Package>
Incidentally, make sure the quotes in the xml files don't get mangled when copying and pasting from the web.
Folders are strange things indeed, there are four types of folders, document, email, report and dashboard, they do not exist as a physical Metadata Type, hence you don't see them listed here. Most of the time they don't work like regular Metadata components with the rest of the API either. The Folder documentation also further hints at their slightly 'special' nature!
Folders are stored in the corresponding component directory of the package. These directories are named documents, email, reports, and dashboards. Folders do not have a text file representation—they are containers for files. For each folder, an accompanying metadata file named FolderName-meta.xml is created at the same directory level. The FolderName-meta.xml metadata file contains the metadata information for that folder, such as the accessType. For example, for a documents folder named sampleFolder, there’s a sampleFolder-meta.xml within the documents folder of the package.
You cannot retrieve just the folder itself with the Metadata API retrieve operation, you have to request at least one file for it to create the folder and the associated metadata XML file for the folder. In my testing just now i can see that you can effectively put anything you like as the type when using retrieve and it just ignores (unlike other operations that throw errors) invalid ones, most misleading!
Fortunately you can use the latest readMetadata operation combined with the listMetadata to retrieve them instead! Here is an example using the Apex Metadata API to do just that...
MetadataService.MetadataPort service = new MetadataService.MetadataPort();
List<MetadataService.ListMetadataQuery> queries = new List<MetadataService.ListMetadataQuery>();
service.SessionHeader = new MetadataService.SessionHeader_element();
service.SessionHeader.sessionId = UserInfo.getSessionId();
MetadataService.ListMetadataQuery queryDocumentFolder = new MetadataService.ListMetadataQuery();
queryDocumentFolder.type_x = 'DocumentFolder';
queries.add(queryDocumentFolder);
MetadataService.FileProperties[] fileProperties = service.listMetadata(queries, 30);
List<String> folderNames = new List<String>();
for(MetadataService.FileProperties fileProperty : fileProperties)
folderNames.add(fileProperty.fileName.replace('documents/', ''));
List<MetadataService.DocumentFolder> folder =
(List<MetadataService.DocumentFolder>)
service.readMetadata('DocumentFolder', folderNames).getRecords();
Retrieve Metadata Demo Further Info
This screenshot shows the Retrieve Demo from the Apex Metadata API retrieving a document file and the document folder, you can see it retrieves the document metadata file. Again this only works IF you also retrieve a file as well sadly.
NOTE: Take a look at this code to see how the above works, to try it out enter the name of your folder in the Folder field, select Document from the drop down, select any file in the folder and click Retrieve.
Best Answer
You should contain the package within a single folder of the ZIP file, like this:
The system saw a single folder in the ZIP file, and assumed that that was the wrapper folder.