HTML file names - HashedMemberName

Topics: DocSites, Features
Jul 23, 2008 at 3:17 PM
Hi

There is one extra file naming schema in the Sandcastle Help Builder - HashedMemberName, that generates nice short names such as on MSDN. This is however not available in DocProject. Do you have any plans to add into a project? It would be very useful to have it as names based on topics are sometimes too long and difficult and GUID is useless as well.

Cheers
Jimmy
Coordinator
Jul 23, 2008 at 4:00 PM
Hi Jimmy,

I haven't considered it but if it's worth the effort then I'll add a work item to the Issue Tracker and look into it for the 1.12.0 Release.

So what kind of hash do you expect to be used for file names?  I'd have to imagine that a SHA1 or MD5 hash is going to be just as useless as a GUID name.  And anything less than the "friendly" topic name that Sandcastle generates may cause clashes, it would seem.

- Dave
Jul 24, 2008 at 7:47 AM
Hi Dave

That was a quick response indeed. As for hash names, for "AccuRevWrapper Dispose Method" I have file 15395F10.htm. I've checked in Sandcastle Help Builder for definition and there is what I found in help:

"Use the hashed member name without parameters as the filename. No character replacements are made for this option and the GetHashCode method is used to generate the hash value and it is formatted as a hex value. This is useful for extremely long type names that cause the filename to exceed the maximum length when the full path is included. Duplicate names will have an incrementing value appended to the name prior to creating the hash value as needed."

So it looks it's even simpler than SHA1 or MD5. Result is not friendly in readability meaning, but generates short file names that looks better than long ones based on type name.
Coordinator
Jul 24, 2008 at 4:20 PM
Hi,

Seems reasonable but since Microsoft may already have an internal implementation you should report this to the Sandcastle team as a feature request.  Then I can include support in DocProject using their built-in transformation.  I'll also consider adding my own implementation for the next release but I'd rather not if Microsoft already has one :)

For the time being, you can roll your own solution if you want by modifying Sandcastle's ProductionTransforms\AddFriendlyFilenames.xsl transformation (and then choose Friendly file names in your projects) or by using your project's Build Process Component or a custom Build Engine Provider.  Basically, I think you'll need to do the following to do this programmatically in a build process component: 

  1. Open your project's BuildProcess.cs|vb file.
  2. In the BuildStarting method replace the Execute XslTransform build step that applies the doc model and naming transformations with a dynamic build step that applies the doc model and a custom naming convention.
    1. To find the correct Execute XslTransform step (there are more than one) you need to loop through the context.Steps property and look for a step with that name.
    2. For each step with that name:
      1. Cast it to ExternalProcessBuildStep<SandcastleBuildEngine>.  (This will require that you add an assembly reference to DaveSexton.DocProject.Sandcastle.dll, which can be found in DocProject's installation bin folder.)
      2. Check Arguments.Contains for a string like /out:"reflection.xml", I think with the quotes.  This would indicate that it's the doc model transformation.
      3. Remove this step from the Steps collection.  (Do a normal build first though so that you can see how this build step looks with the chosen project options.  The build trace will show all of the arguments being passed to the XslTransform.exe program.)
      4. Insert a new dynamic build step that executes Sandcastle's XslTransform.exe tool with the appropriate doc model args, but without the file name transformation.
      5. Finally, in the new dynamic build step, programmatically apply your naming convention to the reflection.xml file.  You may be able to use DocProject's Reflection File API to do the dirty work.  IIRC, I think your goal should be to add a file attribute to each api element.
      6. Break from the outer loop.
When I get home tonight I'll confirm whether this works and post the code here.

- Dave
Coordinator
Jul 29, 2008 at 11:38 PM
Hi Jimmy,

Sorry for the delay - I've been having major hardware problems with my home desktop computer, which is where I have DocProject's source and development tools, but I think the issue is finally resolved :)

For now, the best approach seems to be using a custom XSL transformation in place of the AddFriendlyFilenames.xsl transformation that ships with Sandcastle.  Here's what I did to get it working in a test project:

  1. Close all open instances of Visual Studio.
  2. Open the DocProject configuration file (commonly found at, C:\Program Files\Dave Sexton\DocProject\bin\DaveSexton.DocProject.dll.config).  You can use notepad.
  3. Search for and replace AddFriendlyFilenames with AddHashedFilenames.  There should be 3 matches to replace (one for each of the registered presentation styles).
  4. Create a new AddHashedFilenames.xsl file in Sandcastle's ProductionTransforms folder (commonly found at, C:\Program Files\Sandcastle\ProductionTransforms).  Example content for the file is included below.

After you complete those steps you can start VS again and open your solution.  Your changes to DocProject's configuration file will be loaded.

In your DocProjects and DocSites make sure to set the Build Use friendly HTML file names project option to True in the DocProject Properties window before building help so that the new XSL transformation will be used.

Example AddHashedFilenames.xsl

The following example content simply uses Int32.GetHashCode to generate a hash for each topic identifier.  The hash is then formatted as a hexidecimal string and used as the file name for the topic.  A typical result will look something like this: a2887bf4

Note that I didn't put much thought into this algorithm so it's possible that there may be clashes with topic file names.  If you experience that please let me know.  (Also, the constructor/overload stuff is based on Sandcastle's "friendly" algorithm.  Frankly I doubt that it's even necessary here.)

I'll also consider shipping this transformation in DocProject and changing the Use friendly HTML file names option to a drop-down list option named, File name format, with three choices: GUID, Topic ID, Hash.

<?xml version="1.0"?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 xmlns:ddue="urn:ddue-extensions"
 version="1.1">

 <msxsl:script language="C#" implements-prefix="ddue">
  <msxsl:using namespace="System" />
  <![CDATA[
    public static string getFileName(string id)
    {
     string fileName = id.GetHashCode().ToString("x");

     if (id.IndexOf(".#ctor") != -1)
     {
      fileName = "c_" + fileName;
     }
     else if (fileName.IndexOf(".#cctor") != -1)
     {
      fileName = "cc_" + fileName;
     }
     else if (fileName.IndexOf("Overload") != -1)
     {
      fileName = "o_" + fileName;
     }

     return fileName;
    }
  ]]>
 </msxsl:script>

 <xsl:output indent="yes" encoding="UTF-8" />
 
 <xsl:template match="/">
  <reflection>
   <xsl:apply-templates select="/*/assemblies" />
   <xsl:apply-templates select="/*/apis" />
  </reflection>
 </xsl:template>

 <xsl:template match="assemblies">
  <xsl:copy-of select="." />
 </xsl:template>

 <xsl:template match="apis">
  <apis>
   <xsl:apply-templates select="api" />
  </apis>
 </xsl:template>

 <xsl:template match="api">
  <api id="{@id}">
   <xsl:copy-of select="*" />
   <file name="{ddue:getFileName(@id)}" />
  </api>
 </xsl:template>

</xsl:stylesheet>

Coordinator
Jul 29, 2008 at 11:49 PM
Work item:
http://www.codeplex.com/DocProject/WorkItem/View.aspx?WorkItemId=17585