Dominic Cronin's weblog
Getting the complete component XML
One of the basic operations that a Tridion developer needs to be able to do is getting the full XML of a Component. Sometimes you only need the content, but say, for example that you're writing an XSLT that transforms the full Component document - you need to be able to get an accurate representation of the underlying storage format (OK - for now let's just skate over the fact that different versions have different XML formats under the water)
In the balmy days of early R5 versions, this was pretty easy to do. The Tridion installation included a "protocol handler", which meant that if you just pasted a TCM URI into the address bar of your browser, you'd get the XML of that item displayed in the browser. This functionality was actually present so that you could reference Tridion items via the document() function in an XSLT, but this was a pretty useful side effect. OK... you had to be on the server itself, but hey - that's not usually so hard for a developer. If you couldn't get on the server, or you found it less convenient, another option was to configure the GUI to be in debug mode, and you'd get an extra button that opened up some "secret" dialogs that gave you access to, among other things, the XML of the item you had open in the GUI.
Moving on a little to the present day, things are a bit different. Tridion versions since 2011 have a completely different GUI, and XSTL transforms are usually done via the .NET framework, which has other ways of supporting access to "arbitrary" URIs in your XSLT. The GUI itself is built on a framework of supported APIs, but doesn't have a secret "debug" setting. However, this isn't a problem, because all modern browsers come fully loaded with pretty powerful debugging tools.
So how do we go about getting the XML if we're running an up-to-date version of Tridion? This question cropped up just a couple of days ago on my current project, where there's an upgrade from Tridion 2009 to 2013 going on. I didn't really have a simple answer - so here's how the complicated answer goes:
My first option when "talking to Tridion" is usually the core service. The TOM.NET API will give you the XML of an item directly via the .ToXml() methods. Unfortunately, someone chose not to surface this in the core service API. Don't ask me why? Anyway - for this kind of development work, you could use the TOM.NET. You're not really supposed to use the TOM.NET for code that isn't hosted by Tridion (such as templates) but on your development server, what the eye doesn't see the heart won't grieve over. Of course, in production code, you should take SDL's advice on such things rather more seriously. But we're not reduced to that just yet.
Firstly, a brief stop along the way to explain how we solved the problem in the short term. Simply enough - we just fired up a powershell and used it to access the good-old-fashioned TOM.COM. Like this:
PS C:\> $tdse = new-object -com TDS.TDSE PS C:\> $tdse.GetObject("tcm:2115-5977",1).GetXml(1919)
Simple enough, and it gets the job done... but did I mention? We have the legacy pack installed, and I don't suppose this would work unless you have.
So can it be done at all with the core service? Actually, it can, but you have to piece the various parts together yourself. I did this once, a long time ago, and if you're interested, you can check out my ComponentFactory class over on a long lost branch of the Tridion power tools project. But that's probably too much fuss for day to day work. Maybe there are interesting possibilities for a powershell module to make it easier, but again.... not today.
But thinking about these things triggered me to remember the Power tools project. One of the power tools integrates an extra tab into your item popup, giving you the raw XML view. I'd been thinking to myself that the GUI API (Anguilla) probably had reasonably easy support for what we're trying to do, but I didn't want to go to the effort of figuring it all out. Never fear: after a quick poke around in the sources I found a file called ItemXmlTab.ascx.js, and there I found the following gem:
var xmlSource = $display.getItem().getXml();
That's all you need. The thing is... the power tool is great. It does what it says on the box, and as far as I'm concerned, it's an exceedingly good idea to install it on your development server. But still, there are reasons why you might not. Your server might be managed by someone else, and they might not be so keen, or you might be doing some GUI extension development yourself and want to keep a clear field of view without other people's extensions cluttering up the system. Whatever - sometimes it won't be there, and you'd still like to be able to just suck that goodness out of Tridion.
Fortunately - it's not a problem. Remember when I said most modern browsers have good development tools? We use them all the time, right? F12 in pretty much any browser will get you there - then you need to be able to find the console. Some browsers will take you straight there with Ctrl+Shift+J. So you just open the relevant Tridion item, go to the console and grab the XML. Here's a screenshot from my dev image.
So now you can get the XML of an item on pretty much any modern Tridion system without installing a thing. Cool, eh? Now some of you at the back are throwing things and muttering something about shouldn't it be a bookmarklet? Yes it should. That's somewhere on my list, unless you beat me to it.
The Tridion bookmarklet challenge: an update
A couple of weeks ago, I issued the Tridion bookmarklet challenge. OK - that sounds pretty grand, but really it's not. It's only that having come across the idea of using bookmarklets to enhance the Tridion GUI, this seemed like a great chance to see what inventiveness people could come up with - so why not a challenge? The day after I issued the challenge, my web server went down, so the initial burst of publicity was kind of wasted. Anyway - I hadn't really thought through the details then, so now's my chance to flesh it out a bit, and attempt another deluge of publicity.
So how is it going to work? Here's how:
What you need to do
- Create a useful and well-constructed bookmarklet which enhances the Tridion GUI in some way. It should work with SDL Tridion 2013, but you may wish to consider making it work for 2011 as well.
- Publish it on-line. You can put it on your own web site, or host it somewhere else. (SDL Tridion world, Google code... whatever - I don't care, as long as it's available via the Internet.)
- Publicise it. You should tweet a link to your entry using #tridionlet. You also need to link to it in an answer to this question on meta.tridion.stackexchange.com. Use whatever other means are at your disposal to publicise your entry.
- Apportion the credit correctly. You can enter as a team if you like - so if one person is responsible for the functional aspects, and another for hacking out gnarly javascript, you should say so. Just as long as it's clear who should get the kudos.
- Get this all done by the end of 31 December 2014.
What happens once you've done this?
The judging will be done by the community. This is the reason why you need to answer the question on meta.
We'll wait until the end of January, which should give people a chance to finish their New Year celebrations, and actually read the code... maybe try the bookmarklets out in real life. There'll be a burst of publicity during January to make sure people think about voting, and then whoever has the most votes by the end of 31 January 2015 will be the winner.
Is it better to wait until January to vote?
Yes - the entries might be improved right up to the deadline. Who knows? Also - some people may prefer not to put their entry on-line until quite late on, or may feel pressured by seeing other entries getting more votes (or less). Entrants: remember that many people will wait until January to vote, so don't read too much into it until then. Voters: I'm putting you on your honour to vote for the best entries. So please don't just vote for your mates, and please don't vote to show some kind of company loyalty. This is personal, not corporate.
Tridion GUI Extensions - the bookmarklet challenge
Yesterday I answered a question on tridion.stackexchange.com. Robert Curlette had asked how to clear the messages from the message centre and I was lucky enough to find the answer almost immediately. So I posted it. It had turned out to be a single line of javascript that you could run from the browser console.
Tridion.MessageCenter.getMessages().forEach(function(message){message.doArchive();})
Very shortly afterwards, it dawned on me that if this worked as a bookmarklet, it would be superb. So I updated the answer with the same code as a bookmarklet. Unfortunately (OK, fortunately), Stack Exchange won't let you post links with JavaScript in them, and a really nice way to install a bookmarklet is to drag such a link to your browser's bookmark bar. So here's the bookmarklet as a link (although actually I've used Alex Klock's improved version):
Update: the bookmarklet as I had it didn't work in 2013 because of the extra frames added for the slide-out navigation. It's now updated (thanks to Peter and Orlov) to take account of this.
Clear Messages (2013 version)
I am very pleased with the idea of a GUI Extension as a bookmarklet. Using this approach, we have the possibility of carrying around our own personal toolkit in our browsers (or on a web page we can quickly drag links from), and not having to rely on whatever power tools or other extensions may or may not be installed on a given server. And don't be put off by the idea that a bookmarklet needs to be a one-liner. As an example of what can be done, I'd like to draw your attention to a bookmarklet I use regularly for checking accessibility - the excellent Html_Codesniffer by Squiz. This shows that you can have serious functionality, user interface etc. all in a bookmarklet.
So on to the challenge. Who can come up with the best SDL Tridion GUI Extension bookmarklet? It doesn't have to be complex or clever, as long as it's useful. Just tweet your entries with #tridionlet and I'll compile a list. If there are enough entries, I'll throw together a panel of judges and we'll pick a winner. (Yes - I know that's a bit relaxed, but I just thought of this.)
Why should your Tridion GUI extension 'model' have it's own service layer on top of the core service?
I've spent some time lately looking at the architecture for the next phase of implementing the Component Synchroniser for the Tridion Power Tools project. This meant looking through most of the other power tools, because, of course, they are a great resource for anyone wanting to build a Tridion GUI extension. The down side of this is sometimes, reading the code, you can observe a pattern being used, but it can be hard to tell why this would be a good or bad design. I'd noticed that the model of pretty much every power tool is implemented as a WCF service, often acting as a very thin wrapper around the core service client. As I was wondering about this, I posed the following question in the private chat channel used by the Tridion MVPs and community builders:
So if you're doing a gui extension, is it reckoned to be bad form to access the core service directly from your aspx. Or is it just coincidence that most (all?) of the power tools have an additional service layer?
This was enough to spark quite an informative debate, and in keeping with the spirit of the thing, I promised to write it up for general consumption. The contributors were Frank van Puffelen, Nuno Linhares, Peter Kjaer and Jeremy Grand-Scrutton.
The general feeling was that you ought to stick to the pattern I had observed in the power tools. The reasons were as follows:
- Ease of coding - The Anguilla framework can automatically generate a JavaScript proxy for your service.
- Maintainability - if you talk directly from JavaScript to the core service, you will not get any compile-time checks, whereas your own service layer would be built in .NET and would therefore have some defences against future (likely) changes in the core service client.
- Consistency with the rest of the CME - In the CME, views are typically considered fully client-side. Where the CME does use Aspx, this is only to generate some HTML on the server, and typically not to for implementation logic.
- Known issues - ASP.NET postbacks in Anguilla views have been known to cause problems for some people, since e.g. popups won't keep their state through a postback (or an F5 press for that matter).
According to these criteria, the actual design I was looking at could use the core directly, as my idea was to generate some HTML. In practice, it turns out that there are other reasons to stick with the extra service layer. Even so, I'm very glad I asked the question, and that the answers I got were so informative. Thanks guys!
Batching components for the component synchronizer
Although the Tridion power tools are currently undergoing a major overhaul to bring them in line with SDL Tridion 2011 and its Anguilla extensibility framework, many of us will be working on pre-2011 systems for some time to come. This being so, the "old" power tools remain a useful resource. Today I was working on a 2009 system, where we are busy with a data migration. This means using the component synchronizer. We've been using it for a few things, but today we wanted to remove some redundant fields from a schema, and then have that reflected in the data. The schema in question had about 8500 components based on it, and processing the entire list in one go was going to slow the whole team down. (We're doing this on a relatively under-powered image that can run quite slowly sometimes - it's easy to max it out!)
So what to do? The way of using the component synchronizer that I'm most familiar with is simply to select the schema and then process all it's components. However, the synchronizer also has an option to process a specific list of components; you have to paste a comma-separated list of TCM URIs into a text box. So then the question was how to get such lists with a reasonable amount of effort. Powershell to the rescue. Here's the approach:
> $tdse = new-object -com TDS.TDSE
> $alg = $tdse.GetObject("tcm:12-1255-8",1)
> $f = $tdse.CreateListRowFilter()
> $f.SetCondition("ItemType", 16)
> $docAlgItems = [xml]$alg.Info.GetListUsingItems(1,$f)
> $AlgTcms = $docAlgItems.ListUsingItems.Item | %{$_.ID}
> $algTcms[0..999] -join "," | out-file first1000.txt
> notepad .\first1000.txt
As you can see, we start with instantiating TDSE and getting hold of the schema. To protect the innocent, let's pretend that this schema is called Algernon. $alg is the variable representing the schema.
So - after a quick where-used, we do the standard Powershell trick of casting the results to an XmlDocument and reading off the ID attributes. By this time, $AlgTcms contains an array of TCM URIs and it's almost trivial to dump the first thousand into a file by specifying an array range (obviously you can get the second thousand by saying $AlgTcms[1000..1999] and so on) and doing a -join
So instead of maxing out the system for several hours, we were able to schedule the work in reasonable batches through the day.