teams - Edición programática del contenido Wiki de Sharepoint
office 365 wiki (2)
Una wiki de SharePoint es solo un tipo especial de biblioteca de documentos. Hay algunas rarezas que me he encontrado al intentar hacer esto.
Una página wiki de SharePoint consiste en un archivo de plantilla y un elemento de lista. Cuando ve la página, los campos del elemento de la lista se insertan en el archivo de la plantilla. Entonces, para actualizar una página wiki, solo tiene que actualizar los campos correctos en el elemento de la lista. (Por cierto, eso también significa que no puede acceder a la plantilla original como lo haría con un archivo en una biblioteca de documentos normal. Hasta ahora, la única forma que he encontrado para obtener la plantilla es descargarla a través de SharePoint Designer).
Además, SharePoint representa automáticamente el contenido wiki cuando accede al elemento de la lista mediante programación. Por lo tanto, nunca pude obtener el contenido que contenía "[[My Link Name]]", por ejemplo, SharePoint siempre devolvería el HTML procesado, como:
<A class=ms-wikilink href="/MyWikiLibrary/MyLinkName.aspx">My Link Name</A>
Sin embargo, con un poco de trabajo de expresiones regulares, debería ser capaz de convertir esto al contenido original de la wiki.
Me gustaría editar programáticamente mi contenido de Sharepoint Wiki. Una de las ventajas sería agregar índices al entorno Wiki automáticamente.
¿Fue alguien capaz de hacer esto? El lenguaje no importa, pero busca una solución de scripting.
Sí. He rodado mi propia API de Metaweblog que gestiona de forma programática páginas wiki en Sharepoint 2010 y 2007.
Mis fuentes:
- http://sites.google.com/site/sharepointwikiuploader/
- http://blogs.msdn.com/b/dwinter/archive/2008/06/28/migrating-wiki-pages-remotely-part-01.aspx (Partes 1 - 6)
El código de servicio para SP 2010 y 2007 es bastante idéntico, pero hay algunas advertencias:
- En 2010, no tiene que preocuparse por administrar el marcado del enlace wiki (por ejemplo, [[corchetes]]).
- En 2007, el marcado de wiki se convierte a su pedido, por lo que debe volver a convertirlo en formato Wiki antes de volver a publicarlo. Al publicar de nuevo, no puede usar UpdateListItems, debe usar el servicio de Copia. Esto se debe a que UpdateListItems escapará a cualquier marcado de wiki, haciendo que sus esfuerzos sean inútiles.
- En nuestro entorno, requerimos que se complete el tipo de registro antes de registrarnos. ¿Tal vez esto sea estándar? Si no configura este campo, su página se mantendrá. Entonces, tengo un condicional que establece este campo para SP2007.
- En 2010, SP agrega un montón de marcado en el valor crudo de WikiField, y si falta, podría estropear los diseños. Solo lo inserto alrededor del valor que WLW está publicando, luego lo quito para obtenerlo. Vea abajo.
Uso el servicio Copiar como en el primer enlace para crear Y actualizar las páginas wiki. En 2010, puede usar el servicio de Listas para actualizar, pero no para agregar. Uso el servicio Imaging para subir imágenes automáticamente a una biblioteca de imágenes.
Aquí hay una función para reemplazar los "ms-wikilinks" por el marcado de wiki:
Nota: utilizo HTMLAgilityPack en caso de que el marcado devuelto esté mal formado. Podría usar Regex para hacer esto también. También utilizo la biblioteca Microsoft Anti-XSS 4.1 para sanitizar el marcado.
Nota 2: Mi función UrlDecode no toma una dependencia en System.Web, tomada desde aquí .
/// <summary>
/// Sharepoint 2007 is mean and converts [[wiki links]] once the page is saved in the Sharepoint editor.
/// Luckily, each link is decorated with class="ms-wikilink" and follows some conventions.
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
private static string ConvertAnchorsToWikiLinks(this string html)
{
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
var anchorTags = (from d in htmlDoc.DocumentNode.Descendants()
where d.Attributes.Contains("class") && d.Attributes["class"].Value == "ms-wikilink"
select d).ToList();
foreach (var anchor in anchorTags)
{
// Two kinds of links
// [[Direct Link]]
// [[Wiki Page Name|Display Name]]
var wikiPageFromLink = UrlDecode(anchor.Attributes["href"].Value.Split(''/'').LastOrDefault().Replace(".aspx", ""));
var wikiPageFromText = anchor.InnerText;
HtmlNode textNode = null;
if (wikiPageFromLink == wikiPageFromText)
{
// Simple link
textNode = HtmlTextNode.CreateNode("[[" + wikiPageFromText + "]]");
}
else
{
// Substituted link
textNode = HtmlTextNode.CreateNode(String.Format("[[{0}|{1}]]", wikiPageFromLink, wikiPageFromText));
}
if (textNode != null)
{
anchor.ParentNode.ReplaceChild(textNode, anchor);
}
}
return htmlDoc.DocumentNode.InnerHtml;
}
La función para quitar el HTML de SharePoint es:
/// <summary>
/// Gets editable HTML for a wiki page from a SharePoint HTML fragment.
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public static string GetHtmlEditableContent(string html)
{
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
HtmlNode divNode = (from d in htmlDoc.DocumentNode.Descendants()
where d.Attributes.Contains("class") && d.Attributes["class"].Value == "ms-rte-layoutszone-inner"
select d).FirstOrDefault();
HtmlNode divNode2 = (from d in htmlDoc.DocumentNode.Descendants()
where d.Attributes.Contains("class") && d.Attributes["class"].Value.StartsWith("ExternalClass")
select d).FirstOrDefault();
if (divNode != null)
{
// SP 2010
return divNode.InnerHtml;
}
else if (divNode2 != null)
{
// SP 2007 or something else
return divNode2.InnerHtml.ConvertAnchorsToWikiLinks();
}
else
{
return null;
}
}
Y finalmente, la función que agrega ese marcado a todos:
/// <summary>
/// Inserts SharePoint''s wrapping HTML around wiki page content. Stupid!
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public static string InsertSharepointHtmlWrapper(string html, SharePointVersion spVersion)
{
// No weird wrapper HTML for 2007
if (spVersion == SharePointVersion.SP2007)
return Microsoft.Security.Application.Sanitizer.GetSafeHtmlFragment(html);
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(@"<table id=''layoutsTable'' style=''width:100%''>
<tbody>
<tr>
<td>
<div class=''ms-rte-layoutszone-outer'' style=''width:99.9%''>
<div class=''ms-rte-layoutszone-inner'' style=''min-height:60px;word-wrap:break-word''>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<span id=''layoutsData'' style=''display:none''>false,false,1</span>");
HtmlNode divNode = (from d in htmlDoc.DocumentNode.Descendants()
where d.Attributes.Contains("class") && d.Attributes["class"].Value == "ms-rte-layoutszone-inner"
select d).FirstOrDefault();
divNode.InnerHtml = Microsoft.Security.Application.Sanitizer.GetSafeHtmlFragment(html);
return htmlDoc.DocumentNode.InnerHtml;
}
Esto funciona genial
- Las páginas aún conservan el último usuario modificado y correcto
- Las páginas retendrán toda su historia
- Las páginas son más fáciles de administrar
Estoy pensando en publicar mi API, no es una gran cantidad de código, creo que es muy útil para aquellos de nosotros que queremos administrar mejor nuestros wikis Sharepoint. Con WLW obtengo carga automática de imágenes, mejor soporte de edición de HTML y soporte para complementos como PreCode Snippet. ¡Es impresionante!