martes, 21 de septiembre de 2010

Crear una managed metadata column

Crear una managed metadata column no es tan fácil como seria crear una columna de tipo texto o numérica, etc. El proceso se parece más bien a la manera de crear una columna de tipo lookup.

Este sería el tag Field para una managed metadata column:

<Field Type="TaxonomyFieldTypeMulti"
DisplayName="MyName"
List="TaxonomyHiddenList"
WebId="/"
ShowField="Term1033"
Required="FALSE"
EnforceUniqueValues="FALSE"
Mult="TRUE"
Sorteable="FALSE"
ID="{71A679B9-B7A4-474D-B2EF-D5230C3285AD}"
StaticName="MyName"
Name="MyName"
Group="MyColumns"
Indexed="FALSE">
<Default />
<Customization>
<ArrayOfProperty>
<Property>
<Name>SspId</Name>
<Value xmlns:q1="http://www.w3.org/2001/XMLSchema"
p4:type="q1:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance"></Value>
</Property>
<Property>
<Name>GroupId</Name>
</Property>
<Property>
<Name>TermSetId</Name>
<Value xmlns:q2="http://www.w3.org/2001/XMLSchema"
p4:type="q2:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">MyTermSetId</Value>
</Property>
<Property>
<Name>AnchorId</Name>
<Value xmlns:q3="http://www.w3.org/2001/XMLSchema"
p4:type="q3:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance"></Value>
</Property>
<Property>
<Name>UserCreated</Name>
<Value xmlns:q4="http://www.w3.org/2001/XMLSchema"
p4:type="q4:boolean"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value>
</Property>
<Property>
<Name>Open</Name>
<Value xmlns:q5="http://www.w3.org/2001/XMLSchema"
p4:type="q5:boolean"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value>
</Property>
<Property>
<Name>TextField</Name>
<Value xmlns:q6="http://www.w3.org/2001/XMLSchema"
p4:type="q6:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{AD2D9982-10C9-4BDA-A04C-754EC1DCA9FA}</Value>
</Property>
<Property>
<Name>IsPathRendered</Name>
<Value xmlns:q7="http://www.w3.org/2001/XMLSchema"
p4:type="q7:boolean"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value>
</Property>
<Property>
<Name>IsKeyword</Name>
<Value xmlns:q8="http://www.w3.org/2001/XMLSchema"
p4:type="q8:boolean"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value>
</Property>
<Property>
<Name>TargetTemplate</Name>
</Property>
<Property>
<Name>CreateValuesInEditForm</Name>
<Value xmlns:q9="http://www.w3.org/2001/XMLSchema"
p4:type="q9:boolean"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value>
</Property>
<Property>
<Name>FilterAssemblyStrongName</Name>
<Value xmlns:q10="http://www.w3.org/2001/XMLSchema"
p4:type="q10:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Value>
</Property>
<Property>
<Name>FilterClassName</Name>
<Value xmlns:q11="http://www.w3.org/2001/XMLSchema"
p4:type="q11:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Microsoft.SharePoint.Taxonomy.TaxonomyField</Value>
</Property>
<Property>
<Name>FilterMethodName</Name>
<Value xmlns:q12="http://www.w3.org/2001/XMLSchema"
p4:type="q12:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">GetFilteringHtml</Value>
</Property>
<Property>
<Name>FilterJavascriptProperty</Name>
<Value xmlns:q13="http://www.w3.org/2001/XMLSchema"
p4:type="q13:string"
xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">FilteringJavascript</Value>
</Property>
</ArrayOfProperty>
</Customization>
</Field>


Además hay que tener en cuenta que al crear una managed metadata column en una lista, también se añade una columna de tipo Note, asociada a esta. Aquí mostramos un ejemplo.



<?xml version="1.0" encoding="utf-8" ?>
<Field Type="Note"
DisplayName="MyName_0"
StaticName="MyNameTaxHTField0"
Name="MyNameTaxHTField0"
ID="{AD2D9982-10C9-4BDA-A04C-754EC1DCA9FA}"
ShowInViewForms="FALSE"
Required="FALSE"
Hidden="TRUE"
CanToggleHidden="TRUE" />


Como podéis ver en el primer xml (reference al field de la managed metadata column) hay un conjunto de atributos o elementos que no los podemos saber cuando creamos el xml, sino que lo sabremos en tiempo de ejecución o de provisioning.



Estos elementos serían los siguientes:




  • WebId


  • List


  • SspId


  • TermSetId


  • AnchorId


  • *TextField (esto lo podemos saber si nosotros previamente hemos provisionado el field note que irá asociado a esta columna)



Esto lo hemos solucionando, con un feature receiver que introduce estos atributos (o elementos) en el xml, durante la ejecución, a continuación se muestra algún trozo de esta solución.



Los pasos a seguir serían los siguientes:



// Add Note Field

string fileManagedMetadataNoteField = @"C:\NoteField.xml";

var xmlDocNoteField = XDocument.Load(fileManagedMetadataNoteField);

web.Site.RootWeb.Fields.AddFieldAsXml(xmlDocNoteField);

// Get Managed Metadata Column xml
string filePath = @"C:\ManagedMetadataColumn.xml";

var xmlDoc = XDocument.Load(filePath);

// Modify WebId and ListId
ReplaceWebIdAndListId(xmlDoc, web);

// Modify Customization Element
ModifyCustomization(web, xmlDoc);

web.Site.RootWeb.Fields.AddFieldAsXml(xmlDoc);

private void ReplaceWebIdAndListId(XDocument doc, SPWeb web)
{
var attributeWebId = from f in doc.Elements("Field")
select f.Attribute("WebId");

var attributeList = from f in doc.Elements("Field")
select f.Attribute("List");

string webUrl = attributeWebId.First().Value;

string listName = attributeList.First().Value;

SPWeb referencedWeb = web;
if (!string.IsNullOrEmpty(webUrl))
{
referencedWeb = web.Site.OpenWeb(webUrl);
}

attributeWebId.First().SetValue(referencedWeb.ID.ToString());

SPList referencedList = referencedWeb.Lists[listName];

attributeList.First().SetValue(referencedList.ID.ToString("B"));

if (!string.IsNullOrEmpty(webUrl))
{
referencedWeb.Dispose();
}
}


private void ModifyCustomization(SPWeb web, XDocument doc)
{
var properties = from p in doc.Descendants("Property")
select p;

TermStore termStore = null;
TermSet termSet = null;

foreach (var property in properties)
{
switch (property.Element("Name").Value)
{
case "SspId":
termStore = GetDefaultSiteCollectionTermStore(web.Site);
property.Element("Value").SetValue(termStore.Id.ToString());
break;
case "TermSetId":
termSet = GetTermSet(termStore, property.Element("Value").Value);
property.Element("Value").SetValue(termSet.Id.ToString());
break;
case "AnchorId":
Guid termId = GetTermId(termSet, property.Element("Value").Value);
property.Element("Value").SetValue(termId.ToString());
break;
}
}

}

private TermStore GetDefaultSiteCollectionTermStore(SPSite site)
{
TaxonomySession session = new TaxonomySession(site);
return session.DefaultSiteCollectionTermStore;
}

private TermSet GetTermSet(TermStore termStore, String termSetName)
{
TermSetCollection termSets = termStore.GetTermSets(termSetName, termStore.WorkingLanguage);
return termSets[0];
}

private Guid GetTermId(TermSet termSet, String termNames)
{
TermCollection termCollection = termSet.Terms;
Term term = null;

if (!string.IsNullOrEmpty(termNames))
{
termNames.Split('/').ToList().ForEach(delegate(String termName)
{
term = termCollection[termName];
termCollection = term.Terms;
});
}

if (term == null) return Guid.Empty;
else return term.Id;
}

No hay comentarios: