String Writer

my tech stuffs…

Posts Tagged ‘Tridion

Get TcmId from web dav url

leave a comment »

Many of tridion developer would have tried to get tcm id from web dav. This might be one of the common scenarios where we are using web dav when we are rendering embedded components (in another component template).

I think this is simple scenario so I’m just sharing C# code snippet for this. I’m posting this snippet becoz somebody was googling this yesterday ;) ))


IdentifiableObject identifiableObject = engine.GetObject("<<Web dav url>>");
package.PushItem("TCMID", package.CreateStringItem(ContentType.Text, identifiableObject.Id));

Written by visvabalaji

January 10, 2012 at 5:52 pm

Posted in SourceCode, Tridion

Tagged with ,

Dreaweaver templating in Tridion

leave a comment »

Unless we are familiar with XSLT, I believe, most of us would prefer developing Dreamweaver TBB (DWT) for CT/PT layout!

So just thought of sharing basic Dreamweaver syntax which are commonly used anyway. There are few Dreamweaver extensions are available, developed by Tridion Community, to simplify and enhance DWT templating. But I didn’t get a chance to work on these extensions. So below code syntax would work without any DWT extensions.

I’ve created few simple building blocks for this DWT example.

 Schema & Component

Below is the sample content created based on a simple schema. So assume that component will have this below content.

<Blog xmlns="uuid:18db19ea-b584-4f97-9ac6-8a6e269c9f60">
				<Author>
					<Name>Thotta</Name>
					<TwitterHandle>thotta</TwitterHandle>
					<Genere>Tamil</Genere>
				</Author>
				<Title>TwiTamils</Title>
				<Body>This post is to discuss about active twitters.</Body>
				<Tweeters>
					<Name>Sathish</Name>
					<TwitterHandle>sathm</TwitterHandle>
					<Genere>Tamil</Genere>
				</Tweeters>
				<Tweeters>
					<Name>Nuno</Name>
					<TwitterHandle>nunolinhares</TwitterHandle>
					<Genere>Tridion</Genere>
				</Tweeters>
				<Tweeters>
					<Name>Sowbarnika</Name>
					<TwitterHandle>sowmi_</TwitterHandle>
					<Genere>Tamil</Genere>
				</Tweeters>
				<Tweeters>
					<Name>Srinivasan</Name>
					<TwitterHandle>DKCBE</TwitterHandle>
					<Genere>Tamil</Genere>
				</Tweeters>
				<Tweeters>
					<Name>Alvin Reyes</Name>
					<TwitterHandle>Nivlong</TwitterHandle>
					<Genere>Tridion</Genere>
				</Tweeters>
			</Blog>

And the component layout is defined in DWT as follows

<div>
<h1>@@Component.Fields.Title@@</h1>
 by <a href="twitter.com/@@Component.Fields.Author.TwitterHandle@@">@@Component.Fields.Author.Name@@</a>
 @@Component.Fields.Body@@
<hr />
<table border="1">
 <tr>
  <td><strong><span style="text-decoration: underline;">Tweeters</span></strong></td>
  <td><strong><span style="text-decoration: underline;">Tamil Tweeters</span></strong></td>
 </tr>
 <tr>
  <td>
   <ul>
     <li><strong><a href="twitter.com/@@TwitterHandle@@">@@Name@@</a></strong></li>
   </ul>
   <ul>
	<li><em><a href="twitter.com/@@TwitterHandle@@">@@Name@@</a></em></li>
   </ul>
  </td>
  <td>
   <ul>
	<li><a href="twitter.com/@@TwitterHandle@@">@@Name@@</a></li>
   </ul>
  </td>
 </tr>
 </table>
</div>

Using template builder, we would need to execute this component template against the above component and that would render the output as,

TwiTamils

by
Thotta

This post is to discuss about active twitters.


Tweeters Tamil Tweeters

Accessing a field value

There are many ways to retrieve the field of a component : @@Component.Fields.<field name>@@ or @@<field name>@@ or ${field name}.

Calling simply the field name, like @@Title@@, would work but we should be clear that the same field name was not used on CT/PT level. Otherwise it would return title of the component template since Title is the default attribute for Component Template also.

It’s always better to use full path like @@Component.Fields.Title@@.

 Accessing sub field’s value

If embedded schema’s field needs to be accessed, we can extend the call by adding the sub field name.

As you can see in the above component xml source of a component, Name is the sub field of Author. So it can be accessed like

@@Component.Fields.Author.Name@@

 Accessing a value from Collection

If there are any collection of fields, that can be looped using TemplateBeginRepeat. In the above content, Tweeters is the collection , the sub fields can be accessed inside the loop.


<!-- TemplateBeginRepeat name="Component.Fields.Tweeters" -->
   Name: @@Name@@
   Handle : @@TwitterHandle@@
<!-- TemplateEndRepeat -->

Please note that the sub fields cannot be called like Component.Fields.Tweeters.Name as it cannot navigate right through the Component.

I wish to have something like Component.Fields.Tweeters[0].Name … Component.Fields.Tweeters[3].Name… but unfortunately, it won’t work :(

 Getting loop index

When we are iterating a collection, obviously we would require to have an index of the loop. Unlike other languages, we can’t declare any variables here but Dreamweaver provides a default variable (TemplateRepeatIndex) which holds the index value of the loop.

@@ TemplateRepeatIndex@@ -> this will print the index value on the page.

 Conditional loop

Dreamweaver also provides conditional loop which is similar to If conditions in other languages.


<!-- TemplateBeginIf cond="conditions" -->
  ….
<!-- TemplateEndIf -->

For example,

If I want to render a footer component on bottom of the page, we can try something like


<!-- TemplateBeginRepeat name="Components" -->
   <!-- TemplateBeginIf cond="ComponentTemplate.Metadata.Position = 'Footer'" -->
     @@RenderComponentPresentation(Component.ID, ComponentTemplate.ID)@@
   <!-- TemplateEndIf -->
<!-- TemplateEndRepeat -->

Hope this helps for beginners!

Written by visvabalaji

November 28, 2011 at 5:27 pm

Posted in Tridion

Tagged with , , ,

Publication URL TBB

leave a comment »

In most cases, you will not be publishing the binary files (images/css/js) in the same location of where you publish pages. As a good practice, these external files will be stored in separate folders. In such cases, you will need to  specify path (relative) in the page DWT template.

Generally external css files will be declared like

<link href="/styles/main.css" rel="stylesheet" type="text/css"/>

This would work only if you have styles folder immediately after server path.


http://<server>/styles/main.css

In Tridion, default publication URL is “/” but if you have specified any path in the Publication,  you will need to append that path also. It should be accessed like.

http://<server>/<pub url>/styles/main.css

The below C# TBB will get the publication URL of the current publication.


//gets the current session object
 Session session = engine.GetSession();
 //gets page object from the package
 Item item = package.GetByType(ContentType.Page);
 //gets TcmUri object of Page
 TcmUri tcmObj = new TcmUri(item.GetValue("ID"));
 //generate tcm string format with publication id
 string publicationId = string.Format("tcm:0-{0}-1", tcmObj.PublicationId);
 //gets publication object from the current session
 Publication publication = new Publication(new TcmUri(publicationId), session);
 //writes the publication URL into the package
 package.PushItem("PublicationUrl", package.CreateStringItem(ContentType.Text, publication.PublicationUrl));

As you aware, variable “PublicationUrl” will be included in the package so this variable is accessible when you include this TBB on your page template.
Now you need to call this variable on the page DWT like below,

<link href="@@PublicationUrl@@/styles/main.css" rel="stylesheet" type="text/css"/>

Written by visvabalaji

November 22, 2011 at 3:49 pm

Posted in C#, SourceCode, Tridion

Tagged with , ,

Get object types in C#/Tridion 2009

leave a comment »

In C#, the general usage to identify the object type is using “is” keyword. This is okay to some extent but you have to write “switch” of “if”, for multiple types. If there are more object types, code will be lengthy. Recently I came across a easy way of checking the object’s type. This is helpful when the object is of COM type.

Just add the below reference in your project and call its TypeName method.

image


using Microsoft.VisualBasic;
.
.
.
.
.
public string GetTypeOf(object obj)
{
   return Microsoft.VisualBasic.Information.TypeName(obj);
}

Output:

image

This was very handy for me in my migration project where I needed to write all the object details in log file.

Written by visvabalaji

August 11, 2011 at 11:10 pm

Tridion .Net Template Building Blocks (package) – 2

with one comment

As part of previous post, this will just explain about package object in .Net Templating.

Just to understand what is package in the context of Tridion…During publishing Content Manager provides the publishable contents to Content Distributor. That is the publisher packages all the contents, metadata and instructions for publishing and deploying, in the form of XML. The transport service will send this package to a receiver in the Content Deployer and the Content Deployer will process the content according to the instruction given in the package. (Can refer the process here)

This package can be accessed through .Net templating(TBB) using C# fragments or .Net assemblies. Actually TBB will be executed in the context of given package. In order to customize the contents/instructions, package (typeof Package) object must be edited during templating process. TBB retrieves the relevant items from the package and store the modified contents back into the package object.

Both .Net templating approaches transforms the package object.

Using C# fragments

C# fragments will be a part of Transform(…) in a predefined class so the package variable is accessible by default.

Using .Net Assemblies

A class must inherit ITemplate interface in order to make it as TBB, which will have Transform(…) as part of interface implementation.

public class SampleTemplate : ITemplate
{

   public void Transform(Engine engine, Package package)
   {

   }
}

Execute using Template Builder

TBB can be executed using Template Builder, which is an add-on tool in Tridion. After including TBB for compilation, Default Finish Actions will be included as last TBB. During this process, the package contains only the contents before processing Default Finish Actions; and after Default Finish Actions has been executed, all the publishable contents will be stored in the Output of package object.

package object:

This is a stack type of object and gives access to the contents of the package being processed by the current template (Component or Page). Any ContentType items can be pushed in or popped out from the package.

Package class is defined in Tridion.ContentManager.Templating namespace.

When the package is being processed against Component Template, the package will contain Component Item, through which the Component details can be accessed.

Example,

package.PushItem("Title", package.CreateStringItem(ContentType.Text, package.EvaluateExpression("Component.Title")));

In case of Page Template, the package will contain Page Item.

Example,

package.PushItem("Title", package.CreateStringItem(ContentType.Text, package.EvaluateExpression("Page.Title")));

Finally the Output Item of Component or Page Template must contain the contents to publish.

Package variables

To access a value in the package, the following string format should be used.

[Item name].([Item name]).[value selector]

Example,

To access Component title => Component.Title

To access CreatedBy from metadata => Component.MetaData.CreatedBy

Here’s some predefined/reserved item names in Templating which are constants of Package class.

Names

Details

Example

Component Contains the component currently being processed Component.Title
Components Contains the list of components associated with the page currently being processed
Page Contains the page currently being processed Page.Title
ComponentTemplate Contains the current component template being processed against the Component
Field Contains the Field of the Component that is being processed Component.MetaData.CreatedBy
Output Contains the content to publish, in XML format
TemplateRepeatIndex Used to looping through the collections in a Dreamweaver template <!– TemplateBeginRepeat name=”Fields.locations” –>${RenderComponentField(“Fields.locations”, TemplateRepeatIndex)}<!– TemplateEndRepeat –>

Some frequently used methods in package:

PushItem(…) – Items will be added in the package using this method, LIFO (Last In, First Out) approach. Each item should be defined with a name in order to insert it in the package but multiple items can have same name.

package.PushItem("PageTitle", package.CreateStringItem(ContentType.Text, package.EvaluateExpression("Page.Title")));

GetByType(…) – Retrieves an item based the specific content type

Item item = package.GetByType(ContentType.Component);

GetAllByType(…) – Retrieves all items based on the specific content type

Items items = package.GetAllByType(ContentType.Component);

GetByName(…) – Retrieves an item by its name

package.GetByName(Package.OutputName);

GetValue(…) – Retrieves the value of an item

Component component = engine.GetObject(package.GetValue("Component.ID")) as Component;

Remove(…) – Removes an item from the package

Item componentsItem = package.GetByName(Package.ComponentsName);
package.Remove(componentsItem); //it will remove only the first item if many items used same name

CreateStringItem(…) – creates string type of an item

package.PushItem("PageTitle", package.CreateStringItem(ContentType.Text, “Sample Page")));

CreateHtmlItem(…) – creates html type of an item

String marketUrl = package.EvaluateExpression("Components.Fields.MarketUrl");
package.PushItem("MarketLink", package.CreateHtmlItem(marketUrl));

EvaluateExpression(…) – evaluates an expression (predefined variables or user defined)

package.PushItem(package.CreateStringItem(ContentType.Text, package.EvaluateExpression("3>=3"))); //user defined
package.PushItem("PageTitle", package.CreateStringItem(ContentType.Text, package.EvaluateExpression("Page.Title"))); //predefined variables

Written by visvabalaji

July 11, 2011 at 11:58 pm

Posted in Tridion

Tagged with , , , ,

Tridion .Net Template Building Blocks – 1

leave a comment »

During my internal training to freshers, most of the folks raised questions about template building blocks. I’m glad that they understood Tridion basics quickly and done few hands-ons successfully. But I had to organize another quick discussion to clarify their doubts on TBBs and I’m just documenting our discussions in this blog.

We are yet to get Tridion 2011 access so these are all based on Tridion 2009 :(

Generally SDL Tridion templating helps to transform the content from Content Manager and publish them to target location (or presentation server).

Few points about Template Building Blocks (TBB)

  • It transforms the content from Content Manager into publishable content to target location (or presentation server), in other words, it just transforms the content from XML to (X)HTML.
  • Template building blocks are inserted in a component template (or) page template in an order.
  • Collections of building blocks can be grouped together to form a Compound Template using the Template Builder.
  • Each TBB can be used in multiple Compound Templates.

Tridion supports following .Net template building blocks,

  1. C# fragments
  2. .Net assembly

Here are few details about these types,

C# fragments

We can simply write C# code fragments in the Content Manager Explorer interface (in the Source tab of TBB). These code snippets will be a part of ITemplate.Transform(…) in a predefined class. Hence package, engine and log objects are accessible without any additional reference and all the items in the Content Manager can be accessible through C# code.

Usual practice is to use when you are writing small junk of codes on a package.

Limitations:

  • Cannot create classes as these codes are already part of another class.
  • Cannot debug the code as we are writing in Content Manager Explorer interface.

.NET assembly

This is the typical way of creating C# class library projects which will return dll file. Here a class should implement ITemplate interface to create a TBB. If there are more classes that implements ITemplate, then TBB will be created for each classes.


using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.ContentManagement.Fields;
using Tridion.ContentManager.Publishing;
using Tridion.ContentManager.Templating;
using Tridion.ContentManager.Templating.Assembly;

namespace TridionSamples
{
  public class SampleTemplate : ITemplate
  {

     /// <summary>
     /// Transform as defined by ITemplate.
     /// </summary>
     /// <param name="engine">Templating engine</param>
     /// <param name="package">Package to process</param>
     public void Transform(Engine engine, Package package)
     {

     }
  }
}

If we are making further changes in the .Net assembly, the latest dll can be uploaded to Tridion Content Manager using TCMUploadAssembly.exe command-line utility. Hope this can be posted later.

In both cases, the following objects are important to write TBBs

  • package – contains the content to be published.
  • engine – gives you the access to Content Manager in the current context.
  • log – writes log messages through template logger.

I believe these 3 objects should be detailed, to understand better.

Written by visvabalaji

July 9, 2011 at 2:15 pm

Posted in Tridion

Tagged with , ,

SDL Tridion Classroom sessions

with 2 comments

Before I started working on Tridion projects, almost nobody in my DC was aware of Tridion CMS. When we got a project from one of our client, we didn’t want to miss that opportunity. So we had to arrange a professional training from SDL Tridion. Those two weeks sessions was good enough to get started on our project.

Now I’m on the verge of signing another Tridion project and also we are expecting few more opportunities. We realized that its good time to train others and, of course its always good to have additional hands. So we randomly selected 10 peoples from a bunch of .Net developers and discussed with them on their interest in learning Tridion. When everything was set, we prepared a schedule for two weeks. Theories in the first week, 2 hours daily, and lab sessions in the second week.

This is our second week so team is fully involved in doing lab exercises. I can say that people are more interested in learning Tridion than we thought. Good to know that bunch of Tridion developers are coming out. Now its all rely on getting into right projects :)

Since we are concentrating primarily on technical front, we focused only on core topics.

Topics Details
Basics of Content Management Systems & SDL Tridion 1) Introduction of CMS, WCM, ECM
2) Basics of SDL Tridion
3) Demo on creating building blocks
Template Building Blocks 1) Basics of TBB
2) Template Builder
3) Demo of creating TBBs in all types
Event Systems 1) Basics of Tridion Events
2) Customizing Event Systems
3) Deploying, Enabling and Debugging Event Systems
Workflows 1) Basics of Tridion Workflows
2) Linking workflows with Tridion
3) Services related to Workflows
Content Broker 1) Basics of Content Broker 
2) Dynamic Publishing

 

This schedule was based on SDL Tridion 2009 and we are trying to setup a lab on Tridion 2011, which would definitely need another week session ;)

Written by visvabalaji

July 8, 2011 at 3:19 am

Posted in Tridion, WCM

Tagged with , ,

Delete keywords in Tridion

with 5 comments

As posted earlier, I completed the keyword deletion tool. I’ve tried both approaches (explained in my earlier post) to implement this keyword deletion. Finally I’ve decided to go with deleting keywords from bottom to top that’s 2nd approach.

How to call it

All you need is just to create class object with TCM Uri of a parent keyword whose child keywords are to be deleted and call its delete method.


//initialize the class with keyword TCM Uri value
TCMKeywords keywords = new TCMKeywords(ConfigurationManager.AppSettings["TCMURI"]);
//deletes keyword branch
keywords.Delete();

Here we don’t need to pass its publication TCM Uri since that can be retrieved from its keyword TCM Uri. I’ve given TCM Uri in my app.config file so that I can change it whenever I needed.

Call child keywords recursively

Tridion API does not provide direct method to get all child keywords in hierarchical order. But we can write a recursive call just like the way we do it for any other tree structure objects.


/// <summary>
/// Recursive method to navigate all keywords
/// </summary>
/// <param name="parentTCM">TCM Uri of parent keyword</param>
/// <param name="level">Hierarchy level of keyword</param>
private void NavigateKeywords(string parentTCM, int level)
{
   //gets all child keywords from given parent
   XmlNode keyNode = this.GetListChildKeywords(parentTCM);

   foreach (XmlNode key in keyNode.ChildNodes)
   {
      //loops through its next level
      NavigateKeywords(key.Attributes["ID"].Value, level + 1);

      //deletes keyword if it doesn't have any child
      this.DeleteKeyword((Keyword)this.GetObject(key.Attributes["ID"].Value), level);
   }
}

Obviously a keyword cannot be deleted if it is being used by other items. So all other associations should be removed before deleting it. That’s the reason DeleteKeyword(…) is being called after NavigateKeywords(…). That means if keyword (A) do not have any child, keyword (A) will be considered for deletion.

GetListChildKeywords(…) is a private method to retrieve all child keywords in Xml type of object.


/// <summary>
/// Gets all child keywords in xml object
/// </summary>
/// <param name="parentKeywordTCM">Parent <see cref="Keyword">Keyword</see></param>
/// <returns>Child keywords in <see cref="XmlNode">XmlNode</see> object</returns>
private XmlNode GetListChildKeywords(string parentKeywordTCM)
{
   //gets all child keywords
   string keyXML = ((Keyword)this.GetObject(parentKeywordTCM)).GetListChildKeywords(EnumKeywordSortType.SortTypeTitle,ListColumnFilter.XMLListID, (ListRowFilter)TObj.CreateListRowFilter());

   //returns output as xml object
   return this.PopulateXMLNode(keyXML);
}

ListColumnFilter –Other attributes also can be retrieved other than ListID. But we need only list id for this tool.

ListRowFilter – Here we are getting all rows so we are not setting any filter conditions. This can be set based upon our requirements. Let’s look at this code sample if filtering condition is needed.

Deleting a keyword

The keywords in Tridion can be used in following ways.

  1. Classified with other building blocks
  2. Used in component or metadata fields
  3. Localized in its child publications

A keyword should be released from the all above associations before deleting it.


//releases keyword from its all dependencies
if (this.ReleaseKeyword(keyword, keyLevel))
{
   //deletes keyword
   keyword.Delete();

   Console.WriteLine("{0}{1} deleted...", keyLevel, keyword.Title);
}

ReleaseKeyword(…) is a private method to unclassify and unlocalize the keywords.


/// <summary>
/// Releases the keyword from its dependencies
/// </summary>
/// <param name="keyword"><see cref="Keyword">Keyword</see> object to be released</param>
/// <param name="keyLevel">Hirarchical level of a keyword</param>
/// <returns>Returns <see cref="bool">bool</see> if released or not</returns>
private bool ReleaseKeyword(Keyword keyword, string keyLevel)
{
   //default status
   bool released = false;

   //unclassifies the keyword
   released = this.Unclassify(keyword, keyLevel);

   //unlocalizes the keyword from its all child publications
   if (released)
      released = UnLocalize(keyword, keyLevel);

   //returns released status
   return released;
}

Unclassifying keywords

In Tridion, the content or building blocks are generally classified with keywords.

Classified means that it can be in either way,

1) Keyword can be used in any of field values in metadata or components.

2) An Tridion object is classified against keyword.

These two associations should be removed as part of unclassification.

For example, if a keyword is classified with 10 Tridion objects, we need to retrieve those 10 objects and call them separately its own unclassify method.

The problem here is a keyword in one publication would be derived into its child publications. In child publications, these keywords might have classified with other objects. Hence the appropriate keyword from the same publication should be retrieved to unclassify it.


/// <summary>
/// Unclassifies the keyword
/// </summary>
/// <param name="keyword"><see cref="Keyword">Keyword</see> object to be released</param>
/// <param name="keyLevel">Hierarchical level of a keyword</param>
/// <returns>Returns <see cref="bool">bool</see> if unclassified or not</returns>
private bool Unclassify(Keyword keyword, string keyLevel)
{
   try
   {
      //gets all using items from all publications
      string classifiedItemsXML = keyword.Info.GetListUsingItems(ListColumnFilter.XMLListDefault,(ListRowFilter)TObj.CreateListRowFilter());

      //converts xml string to xml object
      XmlNode xmlDoc = this.PopulateXMLNode(classifiedItemsXML);

      string tcmChild = null;
      //default publication is set to current publication

      string pubURI = this.PublicationURI;

      foreach (XmlNode child in xmlDoc.ChildNodes)
      {
         //gets keyword tcm uri
         tcmChild = child.Attributes["ID"].Value;

         //checks if publication of child object is same as its parent keyword
         if (!this.IsSamePublication(tcmChild))
         {
            //gets publication tcm uri from given tcm uri
            pubURI = GeneratePublicationTCM(tcmChild);

            //gets the same keyword object from its child object publication
            keyword = (Keyword)this.GetObject(pubURI, ReplacePublicationID(keyword.ID, this.GetPublicationID(tcmChild)));
         }

         //checks its child object type and unclassify
         switch (child.Attributes["Type"].Value)
         {
            case "2":
               ((Folder)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
               break;
            case "4":
               ((StructureGroup)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
               break;
            case "16":
               ((Component)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
               break;
            case "32":
               ((ComponentTemplate)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
               break;
            case "64":
               ((Tridion.ContentManager.Interop.TDS.Page)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
               break;
            case "128":
               ((PageTemplate)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
               break;
         }
      }

      //display the output if any of child is unclassified
      if (xmlDoc.ChildNodes.Count != 0)
         Console.WriteLine("{0}{1} unclassified...", keyLevel, keyword.Title);

      return true;
   }
   catch (Exception ex)
   {
      Console.WriteLine("Unclassification Failed!");
      Console.WriteLine(ex.Message);
      return false;
   }
}

GetListUsingItems(…) is the common method in all Tridion objects to retrieve its associated items. In this case, this method will return all the objects wherever the keyword is being used.

Here important note is that if a keyword is unclassified, the parent object will not get republished automatically. If you need to republish the parent object while keyword unclassification, you need to set some code and trigger workflow events.

Unlocalizing keywords

Unlocalizing is not a straight forward approach unlike unclassification. There is no method to write all localized keywords.

If there is a keyword in publication, the same keyword has to be checked in its all child publications whether it is localized in child publication level.


/// <summary>
/// Unlocalizes keyword
/// </summary>
/// <param name="keyword"><see cref="Keyword">Keyword</see> object to be released</param>
/// <param name="keyLevel">Hirarchical level of a keyword</param>
/// <returns>Returns <see cref="bool">bool</see> if unlozalized or not</returns>
private bool UnLocalize(Keyword keyword, string keyLevel)
{
   try
   {
      //gets all child publications
      List<string> childPublications = this.GetChildPublications(keyword.Publication.ID);

      foreach (string cPub in childPublications)
      {
         //gets the keyword in each child publication
         Keyword childKey = (Keyword)this.GetObject(cPub, ReplacePublicationID(keyword.ID, this.SplitURI(cPub, 1)));

         //checks if it is localized
         if (childKey.Info.IsLocalized)
         {
             childKey.UnLocalize();
             Console.WriteLine("{0}{1} unlocalized from {2}...", keyLevel, childKey.Title, childKey.Publication.Title);
         }
      }
      return true;
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
      return false;
   }
}

GetChildPublications(…) posted earlier (Get Child publications in Tridion)

Output

I created these keywords for my testing. All keywords are classified against a component and two of them are localized in child publications.

clip_image001[1]

I ran the tool and got the following output.

clip_image002[1]

The source code can be copied from this link.

Written by visvabalaji

April 12, 2011 at 10:53 pm

Get Child publications in Tridion

leave a comment »

This code sample will give you all the derived child publications from the specific parent publication. There is no direct method to get all child publications but can be easily retrieved from GetListUsingItems(…).

I needed this method to get a status of a component in all child levels.

/// <summary>
/// Gets all child publications
/// </summary>
/// <param name="parent">TCM Uri of parent publication</param>
/// <returns>Collection of child publications</returns>
private void GetChildPublications(string parentTCM)
{
  //gets current publication object
  Publication pub = tdse.GetPublication(parentTCM);
  //gets row filter object
  ListRowFilter filter = tdse.CreateListRowFilter();
  //filter only publication type
  filter.SetCondition("ItemType", 1);
  //returns using publications as xml
  string itemsXML = pub.Info.GetListUsingItems(ListColumnFilter.XMLListID, filter);

  //initialize xml document object
  XmlDocument xmlDoc = new XmlDocument();
  //loads items xml
  xmlDoc.LoadXml(itemsXML);

  foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
  {
    //loops id attribute in each child node
    Console.WriteLine(node.Attributes["ID"].Value);
  }
}

The below code returns all derived publications and remember that this will return all using items if ItemType is not specified.

  //filter only publication type
  filter.SetCondition("ItemType", 1);
  //returns using publications as xml
  string itemsXML = pub.Info.GetListUsingItems(ListColumnFilter.XMLListID, filter);

Output of above line is,

<?xml version="1.0" encoding="utf-8"?>
<tcm:ListUsingItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
  <tcm:Item ID="tcm:0-123-1" />
  <tcm:Item ID="tcm:0-124-1" />
  <tcm:Item ID="tcm:0-125-1" />
  <tcm:Item ID="tcm:0-142-1" />
  <tcm:Item ID="tcm:0-143-1" />
  <tcm:Item ID="tcm:0-144-1" />
</tcm:ListUsingItems>

Written by visvabalaji

April 11, 2011 at 11:38 pm

Blockers for deleting keywords in Tridion

leave a comment »

Some months back I had written a custom tool to import all keywords from XML to Tridion. I thought it was a one time activity, so I didn’t care much about the tool. Completed the tool in 3 days and imported all keywords. But last week there was a change in imported keywords. That was a not major change but we had a very very tough time just to implement the changes.

Problem:

Initially we were thinking of deleting all the keywords manually and run the tool again. But there comes a difficult part, we had around 5000 keywords and at least 30% of them have been used by other items. so we couldn’t just delete manually.

After few trail runs, identified that most of the keywords

  1. Classified by other building blocks
  2. Localized in any of child

I understand that its ridiculous to do it manually. But as part of testing itself, we have partially done it manually :(

As I was held up in various activities, I couldn’t develop the tool immediately but thinking of developing it for future purpose.

Solutions:

Soon after I realized that there is a need for a tool, I began thinking a way of writing it. I didn’t write up anything but two approaches came into my mind immediately.

  1. Simple and Easy
    1. Get category object and retrieve all keywords in xml
    2. Loop though each keyword
      1. unclassify if classified
      2. unlocalize if localized
    3. Find root keyword and delete it.
  2. Nice Programming
    1. Get root keyword and navigate through its child recursively
    2. If the child is
      1. classified then unclassify
      2. localized then unlocalize
    3. Once the focus is back to its parent object while looping, delete the child keyword. It is something like deleting the nodes from its bottom.

I like the 2nd approach but eager to finish up the tool quickly so I’m going to try the 1st one now. But 2nd is the nice approach to do, just becoz of its algorithmic approach :)

Will share the source code for both approaches soon.

Written by visvabalaji

April 6, 2011 at 10:01 pm

Posted in Tridion

Tagged with , ,

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: