Sunday, January 9, 2011

UML diagramming for Sitecore templates

A while ago, the guys from Hedgehog posted a teaser showing a diagram that supposedly was generated by a coming plugin. Because I do most of my diagramming in Enterprise Architect, which supports importing XMI files, I was wondering: How hard is it to generate a minimal version of XMI, that is constructed based on the template hierarchy in a Sitecore Solution?
If I would make it work, I could generate UML Class diagrams by importing a XMI file into Enterprise Architect!
As show below, this is very easy. What I did:
  1. create a simple class diagram (containing only 2 classes, 2 properties and inheritance)
  2. Exported the class diagram to a simple XMI file
  3. Pasted This XMI into a Layout
  4. Created some logic that supplies repeaters with template information
  5. added repeaters to the aspx, that made the XMI file dynamic
  6. visit a page that 'has' the layout bound to it
  7. voila! a valid XMI file that I can import into Enterprise Architect
Check the images below on the steps I took:

step 1: create a simple class diagram


  1. <packagedElement xmi:type="uml:Class" xmi:id="EAID_B16F5263_B589_479e_8588_CD3EA2BCF8A7" name="Class1" visibility="public">
  2.     <ownedAttribute xmi:type="uml:Property" xmi:id="EAID_49CFB4AF_DF06_48b1_824C_7025907761B1" name="name1" visibility="private" isDerived="false" isOrdered="false"></ownedAttribute>
  3. </packagedElement>
  4. <packagedElement xmi:type="uml:Class" xmi:id="EAID_AD064C48_D2D0_4d00_B739_6E3E8A78005A" name="subclass2" visibility="public">
  5.     <ownedAttribute xmi:type="uml:Property" xmi:id="EAID_AF11B4D8_CD8D_45a0_BC48_9D5E53F06FFB" name="Description2" visibility="private" isDerived="false" isOrdered="false"></ownedAttribute>
  6.     <generalization xmi:type="uml:Generalization" xmi:id="EAID_A05EA125_D602_4d01_B338_31C793A08B12" general="EAID_B16F5263_B589_479e_8588_CD3EA2BCF8A7"/>
  7. </packagedElement>
Step 2: a fragment of the XMI file,it contains the 2 classes, properties and de generalization (=inheritance)




  1.         public List<TemplateItem> Templates
  2.         {
  3.             get
  4.             {
  5.                 List<TemplateItem> lTemplates = new List<TemplateItem>();
  6.                 var lSelected = (from Item lItem in Sitecore.Context.Item.GetSelectedItems("IncludedRoots") select lItem);
  7.                 foreach (Item lItem in lSelected)
  8.                 {
  9.                     if(lItem.TemplateName == "Template")
  10.                     {
  11.                         lTemplates.Add(Factory.GetDatabase("master").GetTemplate(lItem.ID));
  12.                     }
  13.                     else
  14.                     {
  15.                         lTemplates.AddRange(from lTemplateItem
  16.                                             in lItem.GetChildrenDescendantOfTemplate("Template", 10)
  17.                                             where lTemplateItem.TemplateName == "Template"
  18.                                             select Factory.GetDatabase("master").GetTemplate(lTemplateItem.ID));
  19.                     }

  20.                 }
  21.                 return lTemplates.OrderBy(a => a.Name).ToList();
  22.             }
  23.         }
step 4: a collection of templates; I used an item with a "included roots" field, it contains selected template(folders)




  1. <asp:Repeater ID="Repeater1" runat="server" DataSource="<%#Templates%>">
  2.         <ItemTemplate>
  3.             <packagedElement xmi:type="uml:Class" xmi:id="<%#((CustomItemBase)Container.DataItem).ID.ToShortID()%>" name="<%#((CustomItemBase)Container.DataItem).Name%>" visibility="public">
  4.             <asp:Repeater ID="rptSections" runat="server" DataSource='<%#GetFields(((TemplateItem)Container.DataItem))%>'>
  5.                 <ItemTemplate><asp:PlaceHolder runat="server" visible="<%#((TemplateFieldItem)Container.DataItem).Section.Template.Name==((CustomItemBase)Container.GetParentContainerDataItem().DataItem).Name%>">
  6.                 <ownedAttribute xmi:type="uml:Property" xmi:id="<%#((TemplateFieldItem)Container.DataItem).ID.ToShortID()%>" name="<%#((TemplateFieldItem)Container.DataItem).Name%>" visibility="private" isDerived="<%#((TemplateFieldItem)Container.DataItem).Section.Template.Name!=((CustomItemBase)Container.GetParentContainerDataItem().DataItem).Name%>" isOrdered="false">
  7.                 <type xmi:idref="<%#((TemplateFieldItem)Container.DataItem).Type%>"/>
  8.                 <asp:PlaceHolder runat="server" visible="<%#!string.IsNullOrEmpty(((TemplateFieldItem)Container.DataItem).GetStandardValue())%>"><defaultValue xmi:id="<%#((TemplateFieldItem)Container.DataItem).ID.ToShortID()%>" value="<%#((TemplateFieldItem)Container.DataItem).GetStandardValue()%>"/></asp:PlaceHolder>
  9.                 </ownedAttribute>
  10.                 </asp:PlaceHolder></ItemTemplate>
  11.             </asp:Repeater>    
  12.             <asp:Repeater ID="rptBaseTemplates" runat="server" DataSource="<%#((TemplateItem)Container.DataItem).BaseTemplates%>">
  13.                 <ItemTemplate><!-- <%#((CustomItemBase)Container.DataItem).Name%> -->
  14.                 <generalization xmi:type="uml:Generalization" xmi:id="<%=Sitecore.Data.ID.NewID.ToShortID() %>" general="<%#((CustomItemBase)Container.DataItem).ID.ToShortID()%>"/> </ItemTemplate>
  15.             </asp:Repeater>  
  16.             </packagedElement>
  17.         </ItemTemplate>
step 5: the Repeater

Final: A class diagram, created from am imported XMI file!

Really nice, don't you think?
2 things I want do do next:
  1. make the XMI generation work in the Compiled Domain Model shared source module
  2. generate the rest of the documentation, with more info per template/field
That's it, ff you would like some sources, leave a note!
All links in this article are available here.

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Sounds very good and useful. We would like to use and test this software for our current project, to create and keep our technical documentation up-to-date. I sent you an e-mail with my contact information.

    ReplyDelete
  3. Could you please post all the code? I cannot find implementation for GetParentContainerDataItem(). Thanks.

    ReplyDelete