SDL Tridion introduced a new target language in the 2011 release – rather mysteriously named REL. Discussions on what exactly this is for tend to very quickly get rather technical and revolve around Dynamic Rendering, developing custom tags in Java, the new Content Delivery web service and such.
Category Archives: Development and templating
Search engine sitemap.xml generation using SDL Tridion
If you’re looking to generate a sitemap.xml file, this post contains a handy TBB to use as a starting point for your development.
Using XPath to find XML Elements with Inline/Default Namespace and Null Prefix
On the last SDL Tridion Community Webinar, Dominic Cronin suggested a great alternative to Regex for finding, adding, removing, or replacing certain elements or attributes, such as Component Links within Components (or Pages). Â The more data-safe approach is to manipulate the Component source as an XML document [via XPath] rather than regex. Â I gave it a shot, except that getting (what seems like) a simple XPath query to work took way more effort than I anticipated. Â All of this due to a little unknown detail about XPath queries for items in the default namespace without a prefix.
Generating Web.Sitemap from Tridion (SiteMapDataSource)
In spirit of Nuno’s post last week (http://nunolinhares.blogspot.com/2012/01/its-little-things-creating-page.html) regarding website navigation and more specifically, how to generate a Breadcrumb from Structure Groups in Tridion, I thought it was time to publish a related post (and a TBB) I’ve been baking for a while now. Behold: hooking up Tridion to .NET’s standard Navigation Controls. I’m talking about Menu, SiteMapPath, and TreeView. Turns out they all feed off the same, rather basic, XML file called web.sitemap. Here is the C# code for a generic TBB that creates such a file from your SDL Tridion Web Structure Group and Pages hierarchy.
SDL Tridion Webinar January 11, 2012: Presentations and resources
For anyone that would like the slides from today’s SDL Tridion community webinar here are the downloads:
Thanks Jules/SDL for having us and we’re looking forward to the next one.
SDL Tridion Application Integration
When I first got the opportunity to work with Tridion, the biggest question I needed an answer to was how to integrate various applications with SDL Tridion.  At the time, I was running a project that required migrating about 20 J2EE applications tightly integrated with a legacy Plumtree Portal to a .NET platform driven by  SDL Tridion. The organization was moving away from J2EE to become a .NET shop, so the apps needed to be rewritten in .NET – our #1 task. All we had was a barebone Tridion installation and a bunch of manuals that did not mention anything about how to integrate apps into it. SDL Tridion training also did not cover this topic – although we got some useful hints, we needed to see a proven design. My intent with this article is to help any new Tridion teams to keep their project moving forward if faced with a similar situation.
The approaches discussed here are not limited to .NET. They can be leveraged to integrate Tridion content into J2EE apps, mobile apps, or anything that you want, such as PHP, Perl, C++. In other words, the sky is the limit.
JavaScript Compression in SDL Tridion (minification and obfuscation. CSS too)
I’ve been building up my jot notes throughout the year and finally got the chance to make them into publishable form, which lead me to this sudden series of articles. Thanks, John, for letting me post on your site.
To achieve maximum compression on a JavaScript file, minification is not enough. Obfuscation is where it’s at. This means replacing variable names to the shortest amount of characters (or bytes) that the language syntax allows. For example: var myReallyLongVariableName=”foobar” would become var a=”foobar”; but only within its scope, and so on. You basically have to implement a decent chunk of code that usually comes as part of any language interpreter or compiler. It’s quite a bit more involved than minification alone. My point is, use a proven package that does this and just hook it up to the best CMS known to man.
My preferred way is actually to not store JavaScript or CSS in Tridion. Put it with the rest of your website’s code into the repository like TFS or Subversion. Basically, bundle it into your build process which should go through Change Management with the likes of JAR/DLL files and DB packages. JS is code after all. This way you can just add a step to your build process. Ask the build master to crunch the JS/CSS through a compressor (possibly as a manual step) before or automate within an ANT, NANT or MSBuild script. If, however, you are a content author or Support person that hates dealing with your org’s Change Management process or have some other reason to store js and/or CSS code as easily publishable as content, then this is for you.
More fun with Dreamweaver Templates – TemplateRepeatCount
Quite a while back (in ’09’ I think) I replied to a thread on the sdltridionworld forum regaring how to get the total count of your elements when doing a TemplateBeginRepeat inside a DWT.
For example when you have a special css class that needs to be applied to the last item in the list.
<ul>
<li><a href="/contact/">Contact Us</a></li>
<li><a href="/sitemap/">Site Map</a></li>
<li class="last"><a href="/terms-of-use/"></a></li>
</ul>
An intuitive approach is to have a function or a variable that provides the count so that you can use syntax like this:
<ul>
<!– TemplateBeginRepeat name="Component.LinkList" –>
<li><a href="@@MyUrlField@@">@@MyUrlText@@</a></li>
<!– TemplateBeginIf cond="TemplateRepeatIndex == TemplateRepeatCount()-1 –>
<li class="last"><a href="@@MyUrlField@@">@@MyUrlText@@</a></li>
<!– TemplateEndIf –>
<!– TemplateEndRepeat –>
</ul>
Here is the code for it:
[TemplateCallable] public string TemplateRepeatCount(string componentTcmId, string fieldName) { Logger.Info("Start of Count"); IdentifiableObject item = _engine.GetObject(componentTcmId); int count = 0; if (item.GetType().Name == "Component") { Component c = item as Component; //find the field collection and get the count ItemFields fields = new ItemFields(c.Content, c.Schema); Logger.Debug("Got component itemfields"); if (fields.Contains(fieldName)) { Logger.Debug("Found item field: " + fieldName); ItemField field = fields[fieldName]; Logger.Debug("Field type: " + field.GetType().Name); switch (field.GetType().Name) { case "ComponentLinkField": { Logger.Debug("Field is ComponentLinkField"); ComponentLinkField typedField = field as ComponentLinkField; count = typedField.Values!=null?typedField.Values.Count:0; } break; case "EmbeddedSchemaField": { Logger.Debug("Field is EmbeddedSchemaField"); EmbeddedSchemaField typedField = field as EmbeddedSchemaField; count = typedField.Values != null ? typedField.Values.Count : 0; } break; case "SingleLineTextField": case "ExternalLinkField": case "XhtmlField": case "MultiLineTextField": { Logger.Debug("Field is TextField"); TextField typedField = field as TextField; count = typedField.Values != null ? typedField.Values.Count : 0; } break; case "DateField": { Logger.Debug("Field is DateField"); DateField typedField = field as DateField; count = typedField.Values != null ? typedField.Values.Count : 0; } break; case "NumberField": { Logger.Debug("Field is NumberField"); NumberField typedField = field as NumberField; count = typedField.Values != null ? typedField.Values.Count : 0; } break; case "KeywordField": { Logger.Debug("Field is KeywordField"); KeywordField typedField = field as KeywordField; count = typedField.Values != null ? typedField.Values.Count : 0; } break; } } } return count.ToString(); }
Though, here is another approach which I used one late night in the office wanting to finish a template. Â It was past my sys admin’s office time, so I couldn’t ask him to deploy a new Custom Functions DLL to the CM server’s GAC/bin, but I just had to get the template done by end of day – I was in the zone. Â Besides, I couldn’t let it linger the next day. Â
So here is a quick C# fragment that should be used in sequence after Will Price’s “Get Linked Components” extension (just Google it if you don’t know. Â It’s the best thing since the combustion engine/sliced bread/eh…SDL Tridion CMS).
Anyway, just drop this C# Fragment in after “Get Linked Components”:
<%@ Import Namespace="Tridion.ContentManager.ContentManagement.Fields"%>
<%@ Import Namespace="System.Collections.Generic"%>
/// This TBB loops through all the items in the package and for any items which are Component Arrays
/// adds a new package item with the array entry count. This is useful when a Dreamweaver TBB needs to know
/// the total count of components or when needing to know if you're on the last component.
List<KeyValuePair<string, Item>> extractedComponentLists = new List<KeyValuePair<string, Item>>();
foreach (KeyValuePair<string, Item> kvp in package.GetEntries())
{
if (kvp.Value.ContentType == ContentType.ComponentArray)
{
//get count
extractedComponentLists.Add(kvp);
}
}
// This code has to be kept in a separate loop since you can't modify the package.GetEntries collection while looping through it.
foreach (KeyValuePair<string, Item> kvp in extractedComponentLists)
{
IComponentPresentationList linkCollectionCPList = ComponentPresentationList.FromXml(kvp.Value.GetAsString());
int componentCount = linkCollectionCPList.Count;
package.PushItem(kvp.Key + "Count", package.CreateStringItem(ContentType.Number, componentCount.ToString()));
}
After this TBB runs, you’ll get a new entry on the package with the count for each “Tridion/Component[]” item type that “Get Linked Components” fetches. Â So if we had a multi-value component link field in the component called “LinkList”, then “Get Linked Components” should fetch a component array and call it after your field name – something like “LinkList”. Â Then after this DWT a new entry will appear called “LinkListCount”.
Use it like this in your DWT:
<ul>
<!-- TemplateBeginRepeat name="Component.LinkList" -->
<li><a href="@@MyUrlField@@">@@MyUrlText@@</a>
<li><!-- TemplateBeginIf cond="TemplateRepeatIndex == LinkListCount-1 -->Â
<li><a href="@@MyUrlField@@">@@MyUrlText@@</a>
<li><!-- TemplateEndIf -->
<!-- TemplateEndRepeat -->
</ul>
Get and Set Variables in DWTs
Here is a creative and useful set of Dreamweaver Custom Functions that allow instantiating your own variables in a Dreamweaver Tridion template. Credit goes out to my fellow team members Trevor Bartlett and Riyaz Hameed.
You can do stuff like this:
<!-- TemplateBeginRepeat name="Field.columnSection" --> <div class="wpsPortlet"> <div class="wpsPortletTitle"> <br />@@Field.title@@</div> @@SetVariable(“columnSectionIndexâ€, "${TemplateRepeatIndex}")@@ <!-- TemplateBeginRepeat name="Field.subColumnSection" --> @@GetVariable("columnSectionIndex")@@ <!-- TemplateBeginRepeat name="Field.subTitle" --> … <!-- TemplateEndRepeat --> </div> <!-- TemplateEndRepeat -->
Here is the code:
/// <summary> /// Sets a varialbe in the package to the name and value specifed. Also removes any other variable that was set with the same name before. /// </summary> /// <param name="variableName">Name of the varialbet</param> /// <param name="value">Value of the variable</param> [TemplateCallable()] public string SetVariable(string variableName, object value) { //Remove the old variable and set the new variable _engine.PublishingContext.RenderContext.ContextVariables.Remove(variableName); _engine.PublishingContext.RenderContext.ContextVariables.Add(variableName, value); return ""; } /// <summary> /// Gets a varialbe from the publishing context. /// </summary> /// <param name="variableName">Name of the variable</param> [TemplateCallable()] public object GetVariable(string variableName) { //Get the varialbe return _engine.PublishingContext.RenderContext.ContextVariables[variableName]; }
Getting used items using the core service
Just wanted to post up a quick code snippet showing how to get a list of used items XML using the SDL Tridion 2011 core service. Why? Well previously the API typically used to work like itemType.GetListUsedItems() (where itemType is a Component or Page object etc), where as now the ‘Using’ and ‘Used’ items are read using a filter via the core service client method .GetListXML().