Сообщений 8    Оценка 1110        Оценить  
Система Orphus

Sandcastle

Новый генератор документации для .NET

Автор: Никита Зимин
Деловые программы

Источник: RSDN Magazine #4-2006
Опубликовано: 23.11.2006
Исправлено: 10.12.2016
Версия текста: 1.0
Печальная кончина NDoc
Что такое Sandcastle?
Процесс
Подготовка
Создание топиков
Sandcastle.config
Шаблоны справочника
Сборка .CHM-файла
Выводы
Источники информации

Печальная кончина NDoc

В конце июля 2006 года, Кевин Даунс (Kevin Downs), основной (и единственный) разработчик NDoc — средства генерации документации для .NET — распространил заявление о том, что он прекращает свою работу над ним и вообще больше не будет участвовать в каких бы то ни было open-source проектах:

«… Разработка и выпуск NDoc 1.3 потребовали огромного объема работы, и по всем признакам, этот вклад был оценен по достоинству. К несчастью, несмотря на почти повсеместное использование NDoc, сообщество разработчиков на .Net не оказало проекту никакой поддержки, ни финансовой, ни своим вкладом в разработку. С тех пор, как версия 1.3 была выпущена, проекту было перечислено всего лишь 12 пожертвований. Фактически, если бы не подарок Олега Ткаченко, в виде подписки на MSDN, я бы даже не имел копии VS 2005, с которой мог бы продолжать работу! …»

Можно по-разному относится к такой ситуации, но это — тема для совсем другой статьи.

Итак, с января 2005 года проект NDoc почти не развивался. На форумах разработчиков довольно часто появляется вопрос «где найти NDoc для .Net 2.0?». И если версию NDoc, хоть как-то генерирующую документацию под .Net 2.0, еще можно найти, по-видимому, не существует версии NDoc, в полной мере поддерживающей все новые возможности нового фреймворка (в частности, generics).

В своем письме Кевин упоминает проект «Sandcastle», над которым работает одна из команд Microsoft, и который преследует (примерно) те же цели, что и NDoc. По убеждению Кевина, «после того, как ‘Sandcastle’ будет выпущен, он станет стандартом де-факто … Это случится в независимости от технических соображений, даже если Sandcastle будет предлагать меньше возможностей …».

Похоже, имеет смысл разобраться, что же это за «убийца NDoc» и чем он может быть нам полезен.

Что такое Sandcastle?

В блоге команды разработки Sandcastle первая запись появилась 27 июля 2006 года.

В качестве цели заявляется: «предоставить разработчикам библиотек классов по всему миру средство простого создания точной и информативной документации общепринятого вида» (вставка от отдела маркетинга?). Свойства Sandcastle:

По словам одного из разработчиков Sandcastle, первая версия Sandcastle состояла из двух компонентов — cDoc, вытягивающего метаданные из сборок в единый файл, и pDoc, создающего на основе этого файла топики для каждого пространства имен/типа/метода, а также создающего файлы содержания, предметного указателя и файлы проектов для последующей сборки через компилятор HTML Help. После выпуска Visual Studio 2005, было принято решение переписать Sandcastle, для повышения производительности и масштабируемости. Июльская CTP-версия Sandcastle 2.0 позволила сократить время компиляции .NET Framework с 10 часов до 30 минут!

Интересный документирующий комментарий в шаблоне презентации Sandcastle:

      /// <summary>To enable people and business throughout
      /// the world to realize their full potential.</summary>
      public
      class Microsoft
{

Процесс

ПРЕДУПРЕЖДЕНИЕ

Если вам требуется быстро получить результат и вы не хотите влезать во все тонкости, то все дальнейшее изложение можно смело опустить. Возьмите готовый инструмент, например такой как Sandcastle Help File Builder.

Вы пишете свой код (на C#, VB.NET или другом языке), используя или не используя документирующие XML-комментарии. В результате компиляции получается сборка и (опционально) сопутствующий ей XML-файл с информацией из XML-комментариев. Либо, у вас есть сторонняя сборка, к которой может быть приложен XML-файл. В любом случае, задача состоит в получении справочника по этой сборке.


Важное отличие этого процесса от процесса NDoc: в Sandcastle основой всегда является сборка, на основе мета-информации сборки строится весь справочник, файл XML-комментариев является необязательным; в NDoc основным источником являются XML-комментарии, мета-информация из сборки используется только для тех объектов, которые упоминаются в файле XML-комментариев.

Подготовка

Действие начинается с работы утилиты MrefBuilder, которая, используя CCI (Common Compiler Infrastructure library — Microsoft.Cci.dll — тот же механизм, что используется в FxCop для получения мета-информации), получает информацию из сборки и выдает ее в выходной файл — Reflection.xml. Этот файл имеет следующую структуру:

<reflection>
  <assemblies>
    <assembly name="Foo" ... >
      ...
    </assembly>
  </assemblies>
  <apis>
    ...
    <api id="N:FooNamespace">
      ...
    </api>
    <api id="T:FooNamespace.FooClass">
      ...
    </api>
    <api id="M:FooNamespace.FooClass.FooMethod">
      ...
    </api>
    ...
  </apis>
</reflection>

Для каждого объекта исходной сборки — пространства имен, класса, свойства, метода и т. п. — здесь есть свой тэг <api> с подробным описанием. В готовом справочнике, каждому тэгу <api> будет соответствовать свой HTML-файл описания.

Формат вызова MrefBuilder:

MrefBuilder <сборки> [/out:<выходной_файл>] [/config:<файл_конфигурации>] [/dep:<сборка_зависимости>] [/internal:+]

где /dep указывает сборки, от которых зависят наши сборки, флаг /internal:+ показывает что нужно генерировать документацию для не-public классов/методов.

Пример использования MrefBuilder:

MrefBuilder MyAssembly.dll /out:Reflection.org

Следующий шаг — дополнение файла Reflection.xml серией «искусственных» тэгов <api>. Для этого используются XSLT-преобразования, которые выполняются утилитой XslTransform. Судя по списку файлов в папке ProductionTransforms, нам уже доступны следующие способы дополнения файла Reflection.xml:

XSLT-преобразование Описание
AddOverloads.xsl Добавляет элементы <api id="Overload:..."> для методов с одним названием и разным набором параметров
AddMemberLists.xsl
AddRoot.xsl Добавляет корневой элемент <api>, для страницы со списком всех пространств имен (по-видимому, для Sandcastle November CTP этот шаг уже не нужен — элемент <api id="R:Project"> создается автоматически)
AddGuidFilenames.xsl Добавляет элемент <file name="..."/> в каждый элемент <api>, в качестве имен файлов задаются глобально уникальные идентификаторы
AddFriendlyFilenames.xsl Добавляет элемент <file name="..."/> с «дружественными» именами файлов: в качестве имен файлов задаются имена, содержащие названия объектов, например для класса — "T_FooNamespace_FooClass"
AddXamlAttachedMembers.xsl

Формат вызова XslTransform:

XslTransform <XML-файл> [/xsl:<XSLT-шаблон>[,...]] [/arg:<имя>=<значение>[,...]] [/out:<выходной_файл>]

Пример обработки файла Reflection.org, полученного от MrefBuilder (для простоты, опущено указание путей):

XslTransform Reflection.org /xsl:AddOverloads.xsl /out:Reflection.st2
XslTransform Reflection.st2 /xsl:AddGuidFilenames.xsl /out:Reflection.xml

Наконец, готовый Reflection.xml сформирован. На его основе, также при помощи XSLT, создается файл со списком топиков — Manifest.xml, имеющий вид:

<topics>
  ...
  <topic id="N:FooNamespace" />
  <topic id="T:FooNamespace.FooClass" />
  <topic id="Overload:FooNamespace.FooClass.FooMethod" />
  <topic id="M:FooNamespace.FooClass.FooMethod" />
  ...
</topics>

Пример преобразования для получения Manifest.xml:

XslTransform Reflection.xml /xsl:ReflectionToManifest.xsl /out:Manifest.xml

Создание топиков

Теперь, когда вся подготовительная работа проделана, публика разогрета, на сцену выходит суперзвезда этого шоу — BuildAssembler.

Результат работы BuildAssembler — логически группированные HTML-файлы топиков документации, пригодные к использованию компиляторами HTML Help 1.3 либо HTML Help 2.0.

Вызов BuildAssembler выглядит так:

BuildAssembler /config:Sandcastle.config manifest.xml

Для каждого топика, указанного в файле Manifest.xml, BuildAssembler выполняет одну и ту же последовательность действий, описанную в файле Sandcastle.config. Типичный набор таких действий выглядит так:

Каждое действие описывается в Sandcastle.config в виде вызова определенного компонента с параметрами.

Sandcastle.config

Итак, центральная часть процесса обработки топиков — это файл Sandcastle.config. Стоит рассмотреть его повнимательнее. Пожалуй, это наиболее интересная часть Sandcastle, и наименее документированная. Мне не удалось найти справочника по используемым компонентам, по-видимому, его вообще (пока) нет в открытом доступе, и все что нам остается — запастись терпением и ждать, либо взять Reflector и влезть с ногами в сборки Sandcastle.

Структура Sandcaste.config:

<configuration>
  <dduetools>
    <builder>
      <components>
        <component type="тип" assembly="путь к сборке">
          <!-- настройки компонента -->
          ...
        </component>
        <!-- тэги вызова других компонентов -->
        ...
      </components>
    </builder>
  </dduetools>
</configuration>

Во время обработки, каждый топик представляет из себя XML-документ в памяти (экземпляр класса XmlDocument). Компоненты, перечисленные в Sandcastle.config — это классы, которые инстанциируются и выполняются один за другим над каждым топиком.

В целом, работа BuildAssembler проходит в несколько фаз:

  1. Загрузка и разбор файлов Manifest.xml и Sandcastle.config
  2. Инстанциирование компонентов
  3. Для каждого топика, описанного в Manifest.xml — выполнение компонентов

Все компоненты являются наследниками абстрактного класса BuildComponent:

        public
        abstract
        class BuildComponent {
    protected BuildComponent(XPathNavigator configuration) {}
    publicabstractvoid Apply(XmlDocument topic, string id);
    protectedvoid WriteMessage(LogLevel level, string message) {}
}

При инстанциировании компонента, в его конструктор передается соответствующая этому компоненту секция файла Sandcastle.config. Это позволяет компоненту «прочитать» свои настройки. Для выполнения компонента вызывается метод Apply, в который передается текущий топик (в виде XmlDocument) и идентификатор этого топика.

Одни компоненты изменяют документ, другие управляют потоком выполнения, третьи позволяют загрузить информацию в XML-документ из файла или сохранить текущее состояние документа в файл.

Вот некоторые из «стандартных» компонентов, содержащихся в сборке BuildComponents.dll:

Тип компонента Описание
CopyFromFileComponent Загрузка содержимого XML-файла в указанный элемент документа
CopyFromIndexComponent Загрузка некоторой части одного или нескольких XML-файлов в документ
ResolveReferenceLinksComponent Расставляет ссылки на другие страницы внутри документа, а также ссылки на внешние источники
SharedContentComponent Заменяет элементы <include> и <includeAttribute> содержимым внешних XML-файлов
SyntaxComponent Описывает синтаксис объекта на различных языках — C#, VB (объявление), VB (использование) управляемый C++, J#, JScript, XAML (использование)
TransformComponent Выполняет XSLT-преобразование над текущим содержанием
SaveComponent Сохраняет текущий XML-документ в указанный файл
ForEachComponent Выполняет набор компонентов над каждым узлом из набора, заданного XPath-выражением
IfThenComponent Выполняет или не выполняет вложенные компоненты в зависимости от условия
SwitchComponent Вычисляет XPath-выражение, находит ветку, подходящую под результат вычисления и выполняет компоненты этой ветки
DisplayComponent Выдает дамп текущего содержимого документа
ValidateComponent Валидирует текущий документ по XML-схеме (.xsd-файлу)

Шаблоны справочника

Помимо логики создания топиков, описанной файлом Sandcastle.config, облик справочника определяется еще целым рядом файлов — это шаблоны страниц, стилевые файлы CSS, скрипты, изображения и т. п. Все эти файлы, плюс собственно Sandcastle.config составляют шаблон справочника.

Перед вызовом BuildAssembler, файлы шаблона копируются в рабочую папку, в которой и выполняется сборка справочника.

В составе Sandcastle, в папке Presentation есть два готовых шаблона:

Сборка .CHM-файла

Используя Reflection.xml с помощью XSLT-преобразования мы можем получить все файлы, необходимые для сборки .CHM: .HHC-файл содержания, .HHK-файл предметного указателя и .HHP-файл проекта справки. Впрочем, файл проекта можно подготовить и вручную — его не требуется изменять при каждой пересборке справки.

Пример получения этих файлов (для простоты, опущено указание путей):

XslTransform Reflection.xml /xsl:ReflectionToChmContents.xsl /out:test.hhc
XslTransform Reflection.xml /xsl:ReflectionToChmIndex.xsl /out:test.hhk
XslTransform Reflection.xml /xsl:ReflectionToChmProject.xsl /out:test.hhp

Остается лишь выполнить сборку справочника, используя утилиту hhc.exe из HTML Help Workshop 1.3:

"C:\Program Files\HTML Help Workshop\hhc.exe" Foo.hhp

Неприятная особенность: hhc.exe написан таким образом, что он возвращает код возврата «1» в случае удачного завершения, и «0» — в случае ошибки. Это отличается от обычной практики, когда после нормального завершения возвращается «0». Поэтому hhc.exe неудобно использовать с такими средствами сборки как NAnt или MSBuild. К счастью, есть простое решение этой проблемы — использовать «инвертирующий» .BAT-файл:

        @echo off
rem запустить компилятор help файлов
%1 "%2"rem обработка ошибок, коды возврата: 0 - ошибка, 1 - успешное завершение, 2 и выше - ошибка
if errorlevel 2 goto error
if errorlevel 1 goto success
if errorlevel 0 goto error0
:success
exit 0
:error
exit %ERRORLEVEL%
:error0
exit 1

Пример использования:

hhc_wrapper.bat <hhc_exe_path> <hhp_path>

Выводы

Источники информации


Эта статья опубликована в журнале RSDN Magazine #4-2006. Информацию о журнале можно найти здесь
    Сообщений 8    Оценка 1110        Оценить