Comment extraire le fichier Manifest.xml ou RootObjectMap.xml d’un fichier *.CMP généré par l’API SharePoint Content Migration

Microsoft fournit un API afin d’extraire et restaurer du contenu SharePoins depuis la version WSS 3.0. Vous pouvez obtenir plus de détails à ce sujet directement sur le site de Microsoft:

http://msdn.microsoft.com/en-us/library/ms453426(office.12).aspx

Personnellement j’ai découvert cet API grâce à l’outil SharePoint Content Deployment Wizard qui est excellent pour extraire des listes et des sites afin de les restaurer dans un autre environnement SharePoint:

http://spdeploymentwizard.codeplex.com/

image

J’ai eu besoin d’écrire un programme spécialisé qui automatiserait la migration de contenu SharePoint et c’est alors que j’ai découvert que SharePoint Content Deployment Wizard utilisait cet API.

En gros, il suffit de créer et configurer un objet SPExportSettings/SPImportSettings puis de créer un objet SPExport/SPImport et d’exécuter la méthode Run.

L’objet SPExport va générer un ou plusieurs fichier *.CMP (par défaut leur taille maximale est 24 mo mais il est possible de spécifier jusqu’à 1023 mo).

/* 1-1023, default = 24 same Manifest.xml and RootObjectMap.xml
http://maxshulga.blogspot.com/2010/03/spexportsettingsfilemaxsize-limitations_10.html */
pExportSettings.FileMaxSize = 1023;

En fait ces fichiers *.CMP sont des fichiers *.CAB. Il est donc possible de les décompresser dans Windows pour voir leur contenu (ex. avec 7-zip).

image

Il y a deux fichiers intéressants dans chacun des fichiers *.CMP: Manifest.xml et RootObjectMap.xml. Le premier liste la totalité du contenu SharePoint tandis que le second ne contient que les fichiers du premier niveau (ex. un site, une liste).

Il peut donc être intéressant (ou même requis) d’extraire un de ces fichiers (Manifest.xml ou RootObjectMap.xml) afin de connaître la liste des objets exportés (ex. pour détuire ces mêmes objets dans la destination afin de les réimporter).

Alors, comment extraire un seul de ces éléments du fichier *.CMP en C#? J’ai cherché et la solution que j’ai retenue utilise Microsoft Shell Controls And Automation (Shell32). Cet API COM permet d’extraire un seul fichier à la fois mais il faut absolument passer par le disque.

image

Voici ce que mon code fait:

  1. Renommer le fichier *.CMP en *.CAB, autrement le code va échouer avec E_FAIL
  2. Créer un répertoire temporaire afin de décompresser un fichier.
  3. Extraire un fichier XML du *.CAB vers le répertoire temporaire.
  4. Charger un XmlDocument à partir de ce fichier XML.
  5. Détruire le répertoire temporaire.
  6. Renommer le fichier *.CAB en *.CMP.
private XmlDocument ParseXMLFileFromCMP(string sCompressedFileName, string sFileName)
{
  bool bNeedRename = String.Compare(Path.GetExtension(sCompressedFileName), "cab", true) != 0;
  string sCabFilePath = null;
  string sTempDirPath = Path.GetDirectoryName(Path.GetTempFileName());
  string sDestDirPath = Path.Combine(sTempDirPath, Guid.NewGuid().ToString("N"));
  XmlDocument pDOM = null;

  Directory.CreateDirectory(sDestDirPath);

  if (bNeedRename)
  {
    sCabFilePath = Path.Combine(Path.GetDirectoryName(sCompressedFileName), Path.GetFileNameWithoutExtension(sCompressedFileName) + ".cab"); // We must rename the CMP file otherwise the COM call will E_FAIL
    File.Move(sCompressedFileName, sCabFilePath);
  }

  Shell pShell = new Shell();
  Folder pCMP = pShell.NameSpace(sCabFilePath);
  Folder pDestinationFolder = pShell.NameSpace(sDestDirPath);
  string sFileNameWithoutExtension = Path.GetFileNameWithoutExtension(sFileName);

   foreach (FolderItem pCurFolderItem in pCMP.Items())
   {
     if (String.Compare(Path.GetFileNameWithoutExtension(pCurFolderItem.Name), sFileNameWithoutExtension, true) == 0)
     {
      string sXmlPath = Path.Combine(sDestDirPath, sFileName);
      pDestinationFolder.CopyHere(pCurFolderItem, 0);
      pDOM = new XmlDocument();
      pDOM.Load(sXmlPath);
      Directory.Delete(sDestDirPath, true);
      break;
    }
  }

  if (bNeedRename)
  {
    File.Move(sCabFilePath, sCompressedFileName);
  }

  return pDOM;
}

N’oubliez pas que ces fichiers XML utilisent des namespace par défaut et que pour les utiliser vous devez déclarer ce namespace, lui associer un préfixe et ajuster vos expressions XPath en conséquence:

XmlNamespaceManager pNSManager = new XmlNamespaceManager(pDOM.NameTable);
pNSManager.AddNamespace(« dns », « urn:deployment-manifest-schema »);

foreach (XmlNode pNodeCur in pDOM.DocumentElement.SelectNodes(« dns:SPObject[@ObjectType =’SPDocumentLibrary’] », pNSManager))
{
(…)

2 réflexions sur “Comment extraire le fichier Manifest.xml ou RootObjectMap.xml d’un fichier *.CMP généré par l’API SharePoint Content Migration

  1. Mis à jour le code car le FolderItem aura ou non une extension selon la configuration de l’utilisateur courant en ce qui a trait à l’affichage des extensions des fichier connu dans le Windows Explorer … Le code marche désormais qu’il y ait une extension ou non.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s