Главная страница Обратная связь Карта сайта


  

Демо-версия
сайт и интерфейс

Документация
все о системе

  

Служба поддержки
+7 (3412) 511419

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

Печальная кончина 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:

  • документация в стиле MSDN; в частности, Sandcastle используется внутри Microsoft для создания документации на .Net Framework
  • создание документации с авторскими комментариями или без них
  • поддержка generics и других возможностей .Net Framework 2.0
  • Sandcastle имеет два основных компонента: MrefBuilder и BuildAssembler. MrefBuilder генерирует XML-файл для BuildAssembler, используя reflection. BuildAssembler генерирует файлы, выполняет преобразования и т. д.

По словам одного из разработчиков 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. Типичный набор таких действий выглядит так:

  • загрузить «скелет» документа
  • загрузить из Reflection.xml данные по описываемому объекту, а также по «родительскому» объекту (например, для класса также загружаются данные по пространству имен) и «дочерним» объектам (например, для класса — по его полям, свойствам и методам)
  • загрузить XML-комментарии
  • проставить перекрестные ссылки
  • выполнить ряд XSLT-преобразований
  • сохранить готовый документ

Каждое действие описывается в 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) {}
    public abstract void Apply(XmlDocument topic, string id);
    protected void 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 есть два готовых шаблона:

  • vs2005 — стандартный шаблон, с помощью которого оформлена справка по Visual Studio 2005, входящая в состав MSDN Library
  • Prototype — прототип/пример шаблона пользователя

Сборка .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>

Выводы

  • Sandcastle стоит того чтобы потратить на него время, с его помощью можно получить отличную документацию на библиотеку классов, как с документирующими комментариями, так и без них
  • Полученную документацию можно выкладывать на сайт в виде HTML-документов, можно получать документацию в формате HTML Help 1.x либо 2.x
  • Процесс создания документации с помощью Sandcastle — открытый, допускающий настройку и расширение на каждом этапе
  • Процесс подготовки документации всюду использует формат XML, многие задачи обработки документов решаются XSLT-преобразованиями
  • Есть возможность подправить облик генерируемых страниц или даже сделать полностью свой шаблон справочника
  • Есть возможность получать документацию не только в формате HTML, но и XML. Можно написать XSLT-преобразования, позволяющие получать документацию и в других форматах, например, LaTeX или XSL-FO
  • Вполне можно ожидать, что после релиза Sandcastle станет де-факто стандартом на генератор документации для платформы .NET

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

Никита Зимин,
ведущий разработчик компании «Деловые программы»

Вернуться к списку статей

Rambler's Top100 CMS List: Обзор систем управления сайтами и программ для создания сайтов
© 2005–2012 ООО «Компания «Деловые программы»