OpenXML

SharePoint 2013 : OpenXML Excel Generation sur CodePlex

Posted on

Et voilà le dernier projet faisant suite à la génération de document Excel sur CodePlex !

Lien : https://openxmlexcel.codeplex.com/

Enjoy !

Advertisements

SharePoint 2013 : OpenXML au service de SharePoint 4/5 et 5/5

Posted on

Quatrième de la série, après avoir vu la génération de document Word, puis PowerPoint, attaquons l’utilisation d’OpenXML avec Excel.

L’exemple présenté va nous permettre de générer des lignes de façon dynamique et de les remplir depuis nos listes SharePoint.

 

ExcelProcessing

Nous créons un simple document Excel de ce type :

image

 

Côté SharePoint, une liste simple avec 2 Champs ( Title & Description), une fois créée regardons le code.

Helper Class

Dans cette classe, nous retrouvons quelques méthode très utile qui vont nous permettre d’effectuer des manipulations dans notre tableau.

  • CreateCell : Création de cellule
  • InsertCellInWorksheet :  Insertion d’une cellule ( dépend de CreateCell)
  • InsertRow: Insertion d’une ligne
  • GetCellInWorksheet : Récupération d’une cellule
  • UpdateCell : Mise à jour d’une cellule
public static class Helper
    {
        public static Cell CreateCell(string text, string column, uint lineNumber,
        Worksheet wsheet)
        {
            Cell newCell = InsertCellInWorksheet(column, lineNumber, wsheet);
            newCell.CellValue = new CellValue(text);
            newCell.DataType = new EnumValue<CellValues>(CellValues.String);
            return newCell;
        }

        public static Cell InsertCellInWorksheet(string columnName, uint rowIndex,
       Worksheet worksheet)
        {
            SheetData sheetData = worksheet.GetFirstChild<SheetData>();
            string cellReference = columnName + rowIndex;
            Row row;
            Cell refCell = null;
            if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
            {
                row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
            }
            else
            {
                row = new Row() { RowIndex = rowIndex };
                sheetData.Append(row);
            }
            if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
            {
                refCell = row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
            }
            else
            {
                foreach (Cell cell in row.Elements<Cell>())
                {
                    if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
                    {
                        refCell = cell;
                        break;
                    }
                }

                Cell newCell = new Cell() { CellReference = cellReference };
                row.InsertBefore(newCell, refCell);


                refCell = newCell;
                worksheet.Save();
            }

            return refCell;
        }
        public static void InsertRow(Worksheet worksheet)
        {
            SheetData sheetData = worksheet.GetFirstChild<SheetData>();
            Row lastRow = sheetData.Elements<Row>().LastOrDefault();

            if (lastRow != null)
            {
                sheetData.InsertAfter(new Row() {
                RowIndex = (lastRow.RowIndex + 1) }, lastRow);
            }

        }

        public static void UpdateCell(Worksheet worksheet, string text, uint rowIndex,
        string columnName)
        {
            if (worksheet != null)
            {
                Cell cell = GetCellInWorksheet(columnName, rowIndex, worksheet);

                cell.CellValue = new CellValue(text);
                cell.DataType = new EnumValue<CellValues>(CellValues.String);


            }

        }
        public static Cell GetCellInWorksheet(string columnName, uint rowIndex,
        Worksheet worksheet)
        {
            SheetData sheetData = worksheet.GetFirstChild<SheetData>();
            string cellReference = columnName + rowIndex;
            Row row;
            Cell refCell = null;
            if (sheetData.Elements<Row>().
                          Where(r => r.RowIndex == rowIndex).Count() != 0)
                row = sheetData.Elements<Row>().
                            Where(r => r.RowIndex == rowIndex).First();
            else
                return null;

            if (row.Elements<Cell>().
              Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
                refCell = row.Elements<Cell>().
                Where(c => c.CellReference.Value == cellReference).First();

            return refCell;
        }
    }

 

Code de génération

Maintenant il ne nous reste à appliquer ces méthodes dans notre code :

 

using (SpreadsheetDocument outDoc = SpreadsheetDocument.Open(docstream, true))
     {
          WorkbookPart wbPart = outDoc.WorkbookPart;
          Sheet tabSheet = wbPart.Workbook.Descendants<Sheet>().
          Where(s => s.Name != null && s.Name.Value.ToString().Trim() == "Demo").FirstOrDefault();

          if (tabSheet != null)
            {
                Worksheet wsheet = ((WorksheetPart)(wbPart.GetPartById(tabSheet.Id))).Worksheet;
                 SheetData sheetData = wsheet.GetFirstChild<SheetData>();
                 SPList spList = web.Lists.TryGetList("demo");
                  if (spList != null)
                  {
                     SPQuery qry = new SPQuery();
                     qry.ViewFields = @"<FieldRef Name='Description' /><FieldRef Name='Title' />";
                     SPListItemCollection listitems = spList.GetItems(qry);

                     uint startline = 6;

                     foreach (SPListItem item in listitems)
                    {
                       Helper.InsertRow(wsheet);//Insert after the last row
                       Cell cellA = Helper.CreateCell(item["Title"].ToString(), "A", startline , wsheet);
                       Cell cellB = Helper.CreateCell(item["Description"].ToString(), "B", startline, wsheet);
                        startline++;
                    }
                }
              //Update a Simple Cell
             Helper.UpdateCell(wsheet, "New Value in Cell", 3, "A");
             wsheet.Save();
}}

Résultat :

image

SharePoint 2013 : OpenXML Word AltChunk sur CodePlex

Posted on

Hello,

Faisant suite à l’article sur l’utilisation de l ‘API Open XML 2.5 pour générer des documents WORD avec l’utilisation du ALTCHUNK via SharePoint 2013, je vous met à disposition le projet CodePlex.

Lien ici : http://openxmlaltchunk.codeplex.com/

Enjoy !

SharePoint 2013 : OpenXML au Service de SharePoint 3/5

Posted on

Troisième article de notre série consacré à l’utilisation d’OpenXML avec SharePoint 2013 ou 2010, celui-ci sera dédié

à l’utilisation des AltChunk dans nos générations de document WORD.

La problématique est la suivante, comment intégrer du contenu HTML provenant de SharePoint et l’injecter dans notre document.

 

AltChunk Késako ?

 

Dans l’univers OpenXML et normalisé ISO/IEC-29500 Standard Compliance, AltChunk  est défini comme une possibilité d’intégrer des Contenus Externe.

En l’occurrence tout type de format, puisque AltChunk va simplement dans le cadre de document externe établir un lien de relation propre

à l’unicité du Altchunk.  Si l’on schématise cela donne :

image

WordAltChunkProcessing

Dans notre démo nous allons créer un document Word Template en y ajoutant un Content Control en mode Bounding Box :

image

Côté SharePoint, une liste avec une colonne de type HTML où j’ai ajouté un tableau.

image

Dans un premier temps je déclare une classe HTMLBUILDER qui me permettra de mettre mon code SharePoint entre mes balises HTML, dans cette classe j’y déclare une méthode StringBuilder.

public StringBuilder BuilderHtml(string paramhtml)
        {
            StringBuilder xhtmlBuilder = new StringBuilder();
            xhtmlBuilder.Append("<html>");
            xhtmlBuilder.Append("<body>");
            xhtmlBuilder.Append(paramhtml);
            xhtmlBuilder.Append("</body>");
            xhtmlBuilder.Append("</html>");

            return xhtmlBuilder;
        }

 

Une fois ma classe mise en place, j’entame la création d’une méthode qui s’intitule AltChunkMethod

qui aura la capacité de lire mon document word, de récupérer le ContentControl avec

l’alias défini et ensuite de renseigner un nom (ID, de préférence unique) pour créer un altchunk.

    protected static void AltChunkMethod(WordprocessingDocument outDoc, string htmlbuilder, string alias,
string chunkid)
        {
            string altChunkId = chunkid;//se doit d'être unique
            AlternativeFormatImportPart chunk = outDoc.MainDocumentPart.AddAlternativeFormatImportPart
                (AlternativeFormatImportPartType.Xhtml, altChunkId);
            //Utilisation en mémoire d'html
            using (MemoryStream xhtmlStream = new MemoryStream(Encoding.UTF8.GetBytes(htmlbuilder)))
            {
                chunk.FeedData(xhtmlStream);//Injection html

                AltChunk altChunk = new AltChunk();
                altChunk.Id = altChunkId;

                //Parcours dans le document à la recherche d'alias
                var resprocess = from bm in outDoc.MainDocumentPart.Document.Body.Descendants<SdtAlias>()
                                 where bm.Val.Value == alias
                                 select bm;
                var process = resprocess.SingleOrDefault();
                var parent = process.Parent;

                parent.InsertAfterSelf(altChunk);//Insertion dans le ContentControl

            }
        }

Il ne me reste plus qu’a injecter mon contenu HTML. de la façon suivante :

foreach (SPListItem item in listitems)
 {
    /*HTML-RTE*/
    HtmlBuilder html_builder = new HtmlBuilder();
    StringBuilder xhtmlBuilder = html_builder.BuilderHtml(item["Description"].ToString());
    AltChunkMethod(outDoc, xhtmlBuilder.ToString(), "altchunk", "chunkid");
}

Résultat

image

Remarques

Si vous avez plusieurs ContentControl pouvant héberger de l’html, vous vous devrez de rendre l’id du Altchunk unique à chaque parcours, ainsi lors du parcours des items de la liste,vous ne vous retrouverez pas avec toutes vos données dans un seul ContentControl

Projet CodePlex

Vous pouvez trouvez les ressources sur codeplex : http://openxmlaltchunk.codeplex.com/

SharePoint 2013 : OpenXML PowerPoint Generation sur CodePlex

Posted on

Faisant suite à l’article sur l’utilisation de l ‘API Open XML 2.5 pour générer des documents PowerPoint via SharePoint 2013, je vous met à disposition le projet CodePlex, vous permettant de mieux apprendre la techno.

Lien ici : http://openxmlppt.codeplex.com/

Enjoy !

SharePoint 2010 : OpenXML au Service de SharePoint 1/5

Posted on

Commençons par notre première série d’article à travers l’utilisation de “Open XML” pour la génération de documents sous SharePoint.

Le but de cette série est de partager sur les différentes problématiques rencontrées lors de l’utilisation de l’API Open XML sous SharePoint.

Rappel sur le format Open XML

Plutôt que de vous faire une è-nième présentation d’Open XML je vous envoie vers quelques ressources qui vous seront forte utiles pour la compréhension des différentes codes abordés.

Je me baserai sur des exemples du SDK 2.0 plutôt que sur la version CTP 2.5.

Bien que certaines classes ont été dépréciées bon nombre des codes utilisés sont maintenable et ne présentent pas une grande difficulté a porter.

Open XML SDK 2.0 for Microsoft Office: http://www.microsoft.com/en-us/download/details.aspx?id=5124

Open XML MSDN : http://msdn.microsoft.com/en-us/library/bb448854(office.14).aspx

Open XML Developer : http://openxmldeveloper.org/

WordProcessing

Rentrons dans le vif du détail par un petit exemple ou j’ai besoin d’alimenter un tableau dont mes données sont stockées dans SharePoint.

Je créé un tableau de 4 colonnes puis dans mon onglet Développeur, je rajoute un Content Control de type “ Rich Text” au dessus de mon tableau de façon à l’entourer et je lui donne comme nom “tabA”

image_thumb3

Ce document fera office de Template une fois que cela est j’ai une liste SharePoint qui contient 3 items que je vais répéter en ajoutant de façon dynamique à mon tableau.

image_thumb5

Code Inside

using System;
using Microsoft.SharePoint;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using W = DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Linq;
using System.Collections.Generic;


namespace OpenXMLDemo
{
    public class Program
    {
        private const string url = "http://spvm/sites/demo";

        public static void Main(string[] args)
        {
            Console.WriteLine("/*Génération Document Word Sample*/n");
            GenerateDocument();
            Console.WriteLine("/*Fin*/n");
            Console.ReadKey();
        }


    private static void GenerateDocument()
    {
      Stream docstream = null;
      using (SPSite site = new SPSite(url))
       {
        SPWeb web = site.OpenWeb();
        SPFile spf = web.GetFile("Shared Documents/word-demo.docx");
         if (!spf.Exists)
           { Console.WriteLine("Le Document n'éxiste pasn");}
         else
          { docstream = spf.OpenBinaryStream(); }
         if (docstream != null)
           {Console.WriteLine("Début de la phase de WordProcessingn");
             using (WordprocessingDocument outDoc = WordprocessingDocument.Open(docstream, true))
            {
               MainDocumentPart mainPart = outDoc.MainDocumentPart;
               List<SdtElement> sdtListB = mainPart.Document.Descendants<SdtElement>().ToList();
               SdtElement sB = mainPart.Document.Body.Descendants<SdtElement>().
               Where(r => r.SdtProperties.GetFirstChild<W.Tag>().Val == "tabA").Single();
               W.Table theTable = sB.Descendants<W.Table>().Single();
               W.TableRow theRow = theTable.Elements<W.TableRow>().Last();


                SPList spList = web.Lists.TryGetList("demo");

                 if (spList != null)
                  {
                   SPQuery qry = new SPQuery();
                   qry.ViewFields = @"<FieldRef Name='_x0063_ol1' />" +
                   "<FieldRef Name='_x0063_ol2' /><FieldRef Name='_x0063_ol3' />" +
                    "<FieldRef Name='_x0063_ol4' />";

                    SPListItemCollection listItems = spList.GetItems(qry);
                    foreach (SPListItem item in listItems)
                    {
                        W.TableRow rowCopy = (W.TableRow)theRow.CloneNode(true);

                        rowCopy.Descendants<W.TableCell>().ElementAt(0).Append(new Paragraph
                           (new Run(new W.Text(item["_x0063_ol1"] as string))));
                        rowCopy.Descendants<W.TableCell>().ElementAt(1).Append(new Paragraph
                            (new Run(new W.Text(item["_x0063_ol2"] as string))));
                        rowCopy.Descendants<W.TableCell>().ElementAt(2).Append(new Paragraph
                           (new Run(new W.Text(item["_x0063_ol3"] as string))));
                        rowCopy.Descendants<W.TableCell>().ElementAt(3).Append(new Paragraph
                          (new Run(new W.Text(item["_x0063_ol4"] as string))));
                        theTable.AppendChild(rowCopy);

                    }



                }


               outDoc.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);

             }

           CREATE_OUTPUT_DOC(web, docstream, "word_output", ".docx");

                }
            }

    }


        private static void CREATE_OUTPUT_DOC(SPWeb web, Stream outputStream, string filename, string ext)
        {
            try
            {
                SPList outputLibrary = web.Lists.TryGetList("Shared Documents");


                if (outputLibrary != null)
                {

                    string outputFileUrl = string.Format("{0}/{1}",
                        outputLibrary.RootFolder.ServerRelativeUrl, filename + ext);

                    web.AllowUnsafeUpdates = true;
                    outputLibrary.RootFolder.Files.Add(outputFileUrl, outputStream);
                    web.Update();

                    if (outputStream != null)
                    {
                        outputStream.Dispose();
                    }
                    Console.WriteLine("Le Document a bien été générén");

                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("Erreur de création de Documentn :" + ex.ToString());

            }
        }
    }
}

Lançons notre Application

Vous lancez le code Snippet fournit et normalement si tout ce passe bien vous devriez avoir un nouveau document office avec vos données à l’intérieur

image_thumb7

Résultat

image_thumb10

A bientôt pour le prochain article !