Conceptual Content - Adding Custom Content to API Documentation created with GhostDoc

Table of Content


GhostDoc Pro Enterprise Edition includes a feature that lets you add Conceptual Content pages in your help files. Conceptual Content can include all those useful pieces of information that your users need, but which won't be picked up directly from the compiled comments in your code. This information will vary from project to project, but may include things like code snippets, hints and tips, tutorials, notes for users, and so on. In fact, any additional information you want your users to find in the help file.

If you don't have GhostDoc Enterprise installed, you can download the free 14 day evaluation copy here.

In order to build this additional content and incorporate it into the compiled help file, you have to create and edit a number of files. These are then added to the help file that GhostDoc Pro generates. These files use Microsoft Assistance Markup Language (MAML), an XML markup with a schema that describes the structure of the conceptual help content. MAML includes several distinct content types, each one aimed at creating a type of document with a specific task.

The Conceptual Content model was introduced as Sandcastle by Microsoft in 2007 and that concept allows us to extend the documentation that's generated from the API XML comments by adding custom content. This tutorial will walk you through GhostDoc's implementation of the original Sandcastle conceptual content feature.

The schema for the conceptual content type is shown below:


The ClassLibrary1 Sample Project

To help you learn how to add conceptual content, we have included a sample project in the GhostDoc Enterprise Edition installation. To locate this project, navigate to the Program Files Installation folder of GhostDoc Pro (typically C:\Program Files or C:\Program Files (x86)) then navigate down through the path - /SubMain/GhostDoc Enterprise/Samples/Conceptual Content, and then extract the files from the file. For your convenience we also included the sample project download link – see #1 under Additional Resources at the end of this post.

This very simple project has been created to introduce you to the files that are required and examples of content you could include. When you're ready to create your own conceptual content, you can copy files from the sample and paste them into your own project. All that's needed then is for you to edit the content to meet your own needs.

The screenshot below shows the generated help file for the sample project, including the conceptual content files that will be described in this tutorial.


For ease of reference, the next screenshot shows the file and folder structure of the sample project.


Summary of the Files Used to Create Conceptual Content

Although I'll work through the conceptual content related files in detail in the sections that follow, you might find it useful to have a quick summary from the start.

ClassLibrary1.content : The role of this file is to keep an index of all the core required information about topics that are included in the conceptual content.

ClassLibrary1.sln.GhostDoc.xml :This file is used by GhostDoc to keep track of your choices about the kind of help file you want to generate. You'll manually edit this file as part of the conceptual content creation process.

ClassLibrary1.snippets :If you include a Code Snippets topic in the help file, the details of the code will be stored in this file.

ClassLibrary1.tokens :If you include links to external sites in a topic, this file is where you store the details of those links.

MediaContent.xml :If you include media - like the Ghost image shown in the screenshot above - in any of your topics, details of that media will be stored in this file.

Content Folder :This folder contains a separate file for each conceptual content topic page you include in your help file.

Help Folder :This folder will contain the generated help file once you've created it with GhostDoc. You can regenerate the help file as many times as you like, so you can check progress of your conceptual content creation.

Media Folder :Media files, such as the GhostDoc PNG file used in the example above are stored in this folder.

Content Layout File - ClassLibrary1.content

One of the key files you need to know about is the Content Layout file. As its name implies, this file identifies the topics that will be included in the conceptual content section of the help file. It dictates the order of the topics, assigns an id, a title and help keywords for each topic. The content layout file used in the sample project is shown below:

<?xml version="1.0" encoding="utf-8"?> <Topics> <Topic id="90a1d911-0315-4865-a414-58189cca1ecb" visible="True" isDefault="true" title="Welcome"> <HelpKeywords> <HelpKeyword index="K" term="Welcome" /> </HelpKeywords> </Topic> <Topic id="24504fda-d3ef-4dd9-8335-6db8b25d00f2" visible="True" title="License Agreement"> <HelpKeywords> <HelpKeyword index="K" term="License Agreement" /> </HelpKeywords> </Topic> <Topic id="9bef5420-7560-47d9-98ce-0b5d5f46567a" visible="True" title="Code Snippets File"> <HelpKeywords> <HelpKeyword index="K" term="File Types, code snippets" /> </HelpKeywords> </Topic> <Topic id="2BE96AFB-6198-4796-A0CB-6B811549E14C" visible="True" title="Tutorial"> <HelpKeywords> <HelpKeyword index="K" term="Tutorial" /> </HelpKeywords> </Topic> <Topic id="53c8f54a-85fb-4857-8adc-0f137d6246a4" visible="True" noFile="true" isExpanded="true" title="Custom Node"> <Topic id="aba20266-8020-4e8c-96ad-f28e42c4db7b" visible="True" title="Custom Page"> <HelpKeywords> <HelpKeyword index="K" term="Custom Page" /> </HelpKeywords> </Topic> </Topic> </Topics>

The content layout file for the sample project is named ClassLibrary1.content. To re-use the content layout file from the sample project, copy and paste the ClassLibrary1.content file, renaming it as required. Then edit the values of the elements and attributes, while maintaining the overall structure of the original.

You don't have to use the '.content' file extension as we have in the sample, but we recommend that you do unless you have reasons to use a different one. The use of .content file extension here follows the naming conventions from the original concept and may help you become familiar with the topic more quickly and help you to understand other examples you may find on the web or elsewhere. And of course those who are familiar with the original Sandcastle feature will find it easier to get to grips with the GhostDoc implementation because we've kept to the naming conventions.

Alternatively, to create this file from scratch, add a new XML file to the project and save it with the file name of your choice. Then add the XML structure as shown in the example above.

Whichever method you use to create this file, note the following key points:

  • The ID must be unique; using a GUID is recommended.
  • The title attribute is required
  • You add one or more values to the term attribute of the HelpKeyword. This ensures that these items will appear in the list on the Index tab of the help file and that the user will be able to find this topic if they use any of these terms in the Search tab. Note that if you want to include multiple values for the term, they must be separated by a comma.

You'll see that individual Topic elements in the file use various other attributes, all of which I think are self-explanatory.

The first three Topics in this sample file are straightforward - Welcome, Code Snippets File and Tutorial. The final topic - Custom Node - is included to demonstrate that it's easy to add nested topics in the conceptual content of the help file. In this case, Custom Node has one child topic - Custom Page - but it is permissible to add more if you need them. You simply add further nested topics inside the Custom Node element.

Each Topic in the ClassLibrary1.content file, with the exception of the Custom Node topic, is related to a separate individual topic file which contains the content to be displayed on its help page. In the sample project, these individual topic files are saved in the Content folder of the project. As you'll find later when I deal with the ClassLibrary1.sln.GhostDoc.xml file, you can choose to store these files in another folder of your choice.

I'll deal with each of these individual topic files next.

Topic Files

You create a separate Topic File with the .aml file extension for each conceptual content topic you want to include in the help file. I'll begin with the Welcome.aml file which you can find in the Content folder of the sample project.


The generated output for the Welcome page in the sample file looks like this:


The Welcome.aml file that creates this page is structured as shown below:

<?xml version="1.0" encoding="utf-8"?> <topic id="90a1d911-0315-4865-a414-58189cca1ecb" revisionNumber="1"> <developerConceptualDocument xmlns="" xmlns:xlink=""> <mediaLink><image placement="center" xlink:href="GhostDoc"/></mediaLink> <introduction> <para>This is help file sample contains information on how use conceptual content to generate help file. You can find more information at <link xlink:href="2BE96AFB-6198-4796-A0CB-6B811549E14C" /> </para> </introduction> <relatedTopics> <link xlink:href="9bef5420-7560-47d9-98ce-0b5d5f46567a" /> </relatedTopics> </developerConceptualDocument> </topic>

The key points to note from this sample file are:

  • The topic id value must match the value of this topic's id in the .content file, otherwise the build will fail.
  • The main body of the topic must be placed inside the developerConceptualDocument tags. The 'Welcome' header (seen in blue at the top of the topic in the screenshot) is created and inserted automatically based on the title attribute in the .content file.
  • The xml namespaces shown above are required in all topic files.
  • To insert an image into the body of the topic, you use a mediaLink element which references a named image file, in this case an element with the id of 'GhostDoc'. I'll explain how this reference works when I deal with the MediaContent.xml file later in this tutorial.
  • The introduction element contains the main body of the text in the topic. You can include multiple paragraphs inside this section.
  • The introduction in this topic includes a link to another topic in the same help file. To do this, include a link inside the para and reference the id of the topic you want to link to. The easiest way to find the GUID is by looking in the Content Layout file (ClassLibrary1.content in the sample). The help compiler will automatically find the title of the linked topic and insert it here.
  • To provide the link that you can see in the Other Resources section, use the syntax shown in the example above. The procedure is the same as described in the previous bullet. You can of course add multiple links.

In the code snippets topic in the sample, the help file display looks like this:


The content of the CodeSnippetsFile.aml file that creates this page is shown below:

<?xml version="1.0" encoding="utf-8"?> <topic id="9bef5420-7560-47d9-98ce-0b5d5f46567a" revisionNumber="1"> <developerConceptualDocument xmlns="" xmlns:xlink=""> <introduction> <para>The code snippets file allows you to define code samples outside of conceptual topic files.</para> </introduction> <section> <title>Example Output</title> <content> <para>Define a class</para> <codeReference>ClassDefinition#Define</codeReference> </content> </section> <relatedTopics> <link xlink:href="90a1d911-0315-4865-a414-58189cca1ecb" /> </relatedTopics> </developerConceptualDocument> </topic>

Follow the guidelines below when creating your own code snippets files. Although several of them are the same as for the Welcome.aml file described above, there are some differences.

  • The topic id value must match the value of this topic in the .content file, otherwise the build will fail.
  • The main body of the topic must be placed inside the developerConceptualDocument tags. The 'Code Snippets File' header (seen in blue at the top of the topic in the screenshot) is created and inserted automatically.
  • The xml namespaces shown above are required in all topic files.
  • The introduction element contains the main body of the text in the topic. You can include multiple paragraphs inside this section.
  • The section element houses the code snippets display. In this example, there is a title and a content sub-element that is used to hold text (the string "Define a class").
  • The codeReference element references the id ("ClassDefinition#Define") of a code snippet which (in this sample project) is located in the ClassLibrary1.snippets file. I'll cover that snippet in more detail when I deal with the ClassLibrary1.snippets file later. Be aware though that the conceptual content compiler knows how to format the presentation of code snippets that are placed inside codeReference tags.
  • To include links in the Other Resources section, use the syntax shown in the example above inside the relatedTopics tags, inserting the GUID of the topic you want to link to. The help compiler will automatically find the title of the linked topic and insert it here.
Tutorial Topic

The Tutorial topic in the sample project looks like this:


You'll notice that on the first line of the main body of text on that page, the word 'Tutorial' is a hyperlink. You can insert hyperlinks to external URLs like this very easily. Here's the markup for the Tutorial Topic page:

<?xml version="1.0" encoding="utf-8"?> <topic id="2BE96AFB-6198-4796-A0CB-6B811549E14C" revisionNumber="1"> <developerConceptualDocument xmlns="" xmlns:xlink=""> Please see the following <token>tutorial</token> on SubMain web site and learn about custom help file content using Conceptual Content with GhostDoc. </developerConceptualDocument> </topic>

The text to be displayed, as with the other topics, is inside the body of the developerConceptualDocument element. In order to include a hyperlink, you use the <token> tag as shown above. The word 'tutorial' inside the token tag references the id of a token whose details are contained in the ClassLibrary1.tokens file. I'll be dealing with that file shortly, but for now it's enough to know that by referencing that token id, the required hyperlink can be invoked and an external page will be displayed.

Custom Page Topic

The Custom Page topic (shown below) simply displays the text content 'Custom Page'.


The CustomPage.aml file in the Contents folder looks like this:

<?xml version="1.0" encoding="utf-8"?> <topic id="aba20266-8020-4e8c-96ad-f28e42c4db7b" revisionNumber="1"> <developerConceptualDocument xmlns="" xmlns:xlink=""> Custom Page </developerConceptualDocument> </topic>

As with the other topics we've described, the main content is placed inside developerConceptualDocument tags. Although this simple example uses only two words, you can use any of the elements that are included in the other example topics - mediaLink, introduction, para, etc. plus more, such as lists, tables, warnings, and so on.

Custom Node Topic

The Custom Node Topic example in the sample file is slightly different from the other topics. When you navigate the nodes in the help file created in the sample project, you'll find that selecting the Custom Node topic doesn't cause a new page to be displayed. To demonstrate this, in the screenshot below, although Custom Node has been selected, you'll see that the previous topic - Welcome - is still displayed:


This is a useful feature if you want a parent node (in this case, Custom Node) that works as an empty header for one or more child nodes, such as the Custom Page in the example above. However, some users may find it counter-intuitive to have a node where there is no visual feedback when it is clicked. So if you do want to have content in the parent node, you can easily do so.

Here is the markup from the original example:

<Topic id="53c8f54a-85fb-4857-8adc-0f137d6246a4" visible="True" noFile="true" isExpanded="true" title="Custom Node"> <Topic id="aba20266-8020-4e8c-96ad-f28e42c4db7b" visible="True" title="Custom Page"> <HelpKeywords> <HelpKeyword index="K" term="Custom Page" /> </HelpKeywords> </Topic> </Topic>

Note that the noFile attribute is set to "true". This is the attribute that controls whether the compiler looks for a topic file in the Content folder to associate with this topic. In order to include content in this topic, the first step is to either change the value of noFile to "false", or simply delete that attribute because false is the default value.

Now that the help builder has been asked to find a topic file, the next step is to create it. The easiest way to do this is to copy one of topic files from the sample project, paste it into the Content folder of the solution and rename it to CustomNode.aml. I will use the Custom Page topic and edit that, but you can of course use any of the Topic files if you want to or build a new file from scratch.

Here is the original markup from the file I've copied:

<?xml version="1.0" encoding="utf-8"?> <topic id="aba20266-8020-4e8c-96ad-f28e42c4db7b" revisionNumber="1"> <developerConceptualDocument xmlns="" xmlns:xlink=""> Custom Page </developerConceptualDocument> </topic>

The two items that need to be edited are the topic id and the text content. So, first copy the topic id for the Custom Node topic from the ClassLibrary1.content file and paste it to replace the topic id in the file you are editing.

Then, inside the developerConceptualDocument tags, insert the content you want to display. For this example, I've used the introduction tag containing two paragraphs, but you can use any of the types of content shown in the sample files. I've also added two relatedTopics links, one to the Welcome page and one to the child topic of this page. The following markup creates the result you can see in the screenshot that immediately follows it:

<?xml version="1.0" encoding="utf-8"?> <topic id="53c8f54a-85fb-4857-8adc-0f137d6246a4" revisionNumber="1"> <developerConceptualDocument xmlns="" xmlns:xlink=""> <introduction> <para> This is the parent custom node. With the noFile attribute set to false, this topic content is now visible.</para> <para> You can choose not to have any content by setting noFile to true. </para> </introduction> <relatedTopics> <link xlink:href="90a1d911-0315-4865-a414-58189cca1ecb" /> <link xlink:href="aba20266-8020-4e8c-96ad-f28e42c4db7b" /> </relatedTopics> </developerConceptualDocument> </topic>


The ClassLibrary1.sln.GhostDoc.xml file

This key file is generated when you choose the Build Help File option in the Tools > GhostDoc Enterprise menu in Visual Studio.


It contains all the settings needed to generate the help file. For a standard help file (one without conceptual content) you won't need to edit this file because all the values are assigned based on your choices in the Build Help File dialog:


But when you want to create a help file that does include conceptual content, you do need to edit the ConceptualContent section of this file.

By default, when you create a new project, the automatically created .sln.GhostDoc.xml file will include a skeleton section as shown below:

<ConceptualContent> <ContentLayout /> <MediaContent /> </ConceptualContent>

Compare the above snippet with the same section in the ClassLibrary1 sample project:

<ConceptualContent> <ContentLayout file="ClassLibrary1.content" folder="Content\" /> <MediaContent file="MediaContent.xml" folder="Media\" /> <CodeSnippetsFile>ClassLibrary1.snippets</CodeSnippetsFile> <TokensFile>ClassLibrary1.tokens</TokensFile> <AdditionalContentFolder>Other\</AdditionalContentFolder> </ConceptualContent>

You can see that all those key resource files - ContentLayout, MediaContent, CodeSnippetsFile, and TokensFile - now reference specific files in the project. And where appropriate, the folder that contains child files is also named; in this case, the Content and Media folders.

(We have also included an AdditionalContentFolder in the example so you know it's available, but we haven't added any additional files in the sample.)

When you build your own conceptual content, you have to edit this sln.GhostDoc.xml file to reflect the names of the files and folders that you want to use. Our sample reflects the accepted naming conventions, but you can use other names if you wish.

This portion of the file pulls all the conceptual content together, so it's vitally important that you correctly name all the files and folders you want to use.

Looking now at that list of files and folders above, I've already covered the ClassLibrary1.content file and the files in the Content folder. All that remain to be described are the MediaContent.xml, ClassLibrary1.snippets and ClassLibrary1.tokens files.

Media Content file - MediaContent.xml

The MediaContent.xml file stores the information needed to locate and display media displayed on topic pages. This is a single image in the sample project, but you can include more in your own help files' conceptual content. Here is the MediaContent.xml file from the sample project:

<?xml version="1.0" encoding="utf-8"?> <stockSharedContentDefinitions> <item id="GhostDoc"> <image file="ghostdoc100x100.gif"> <altText>GhostDoc</altText> </image> </item> </stockSharedContentDefinitions>

The key points to note about this file are:

  • All the media content is placed inside a stockSharedContentDefinitions tag.
  • Each individual media item (in this example there is only one) is created as a separate element and given a descriptive id.
  • The source of the media (in this case a gif image file) is referenced by file name only, even though this file is stored in the Media sub-folder. The conceptual content builder will be able to find this file at compilation time because the required path is referenced in theClassLibrary1.sln.GhostDoc.xmlfile (See the preceding section for the relevant code snippet):
                               <MediaContent file="MediaContent.xml" folder="Media\" />
  • The altText value is optional but recommended as best practice for a better user experience.

Snippets file - ClassLibrary1.snippets

The .snippets file (in the sample, ClassLibrary1.snippets) is used to hold the individual code snippets that are displayed in the Code Snippets Topic files. In the sample project, there is just a single code snippets topic.

The output of the code snippets topic looks like this:


Two files are used in the creation of code snippets topics. I dealt with CodeSnippetsFile.aml earlier, in the Topic Files section.

The second file used for code snippets is the .snippets file that I'm covering in this section.

In the sample project it has the following content:

<?xml version="1.0" encoding="utf-8" ?> <!-- This is an example code snippets file --> <examples> <item id="ClassDefinition#Define"> <sampleCode language="CSharp"> public class CSharpClass() { // Members go here } </sampleCode> <sampleCode language="VisualBasic"> Public Class VBClass ' Members go here End Class </sampleCode> </item> </examples>

If you refer back to the earlier section that deals with the CodeSnippetsFile.aml, you'll see that the file has a <content> tag which contains para and codeReference elements:

<content> <para>Define a class</para> <codeReference>ClassDefinition#Define</codeReference> </content>

Notice that the value of the codeReference is "ClassDefinition#Define", which is the item id of the required snippet that's stored in the ClassLibrary1.snippets file.

The sampleCode tags hold the actual code you want to display. You can see in the two examples above that snippets are shown in both C# and VB. The language attribute on the sampleCode element dictates the language name that's displayed in the header of each snippet. You are not limited to these two languages and can include snippets from other popular languages, such as F#, JavaScript, etc. Just insert the language name in the language attribute of the sampleCode element.

Tokens File - ClassLibrary1.tokens

The .tokens file contains details of external links that can be included in topics. In the sample project, the Tutorial.aml file includes a link that will bring you to this tutorial on the SubMain web site.


The markup in the ClassLibrary1.tokens file is:

<?xml version="1.0" encoding="utf-8"?> <content xml:space="preserve" xmlns:ddue="" xmlns:xlink=""> <item id="tutorial"> <ddue:externalLink xmlns:ddue=""> <ddue:linkText>Tutorial</ddue:linkText> <ddue:linkUri></ddue:linkUri> <ddue:linkTarget>_blank</ddue:linkTarget> </ddue:externalLink> </item> </content>

Note the following guidelines:

  • You should place all the content inside a <content> tag and include the xml namespaces shown above.
  • Each individual item must be placed inside an item tag and assigned an id - in this example, it's "tutorial". This id is referenced in line 7 of the Tutorial.aml file that I described earlier.
                        Please see the following <token>tutorial</token> on SubMain web site and learn about custom help file content using Conceptual Content with GhostDoc.
  • The linkText element contains the string that will be displayed as the text of the hyperlink in the Tutorial.aml file.
  • The linkUri identifies the URI of the external resource that will be navigated to.
  • The linkTarget element in this example has been set to _blank and in the case of chm help files will make the linked page open in a new window inside the help file


This tutorial and the sample project are designed to bring you up to speed on the core features of conceptual content when used with GhostDoc Enterprise Edition. The original Sandcastle project and Microsoft's MAML allow for more types of content to be displayed and you may want to read further once you've mastered the basics covered in this sample here. The original MAML help file created by Microsoft can be downloaded here. Also see the Sandcastle MAML Guide link (#3) under Additional Resources below.

In many projects, including conceptual content in your help files will improve the users' experience and may reduce the number of clarification requests you receive at your help desk. It doesn't take a huge amount of work or time and once you are familiar with how the .xml and .aml files link together you can very quickly add value to the GhostDoc generated help files.

If you don't have GhostDoc Enterprise installed, you can download the free 14 day evaluation copy here.

Additional Resources

  1. Download GhostDoc Conceptual Content Sample Project
  2. Download MAML Reference Help File
  3. Sandcastle MAML Guide
  4. Conceptual Content - How to Include Bulleted and Ordered Lists
  5. Conceptual Content - How to include Tables