Главная » XSLT » Преобразование документов из формата Visio VDX в формат SVG

0

Задача

Требуется преобразовать файл в формате Microsoft Visio XML (VDX) в более переносимый формат SVG.

Решение

Показанное ниже решение предложил Джон Брин. Основные элементы Visio отображаются на элементы SVG, как показано в таблице 13.1.

Таблица 13.1. Отображение элементов Visio на элементы SVG

В этом разделе мы рассмотрим только главную таблицу стилей и отдельные части включаемых таблиц. Полностью исходный код вместе с примерами можно найти по адресу http://sourceforge.net/projects/vdxtosvg/.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v="urn:schemas-microsoft-com:office:visio" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:math="java.lang.Math" xmlns:jDouble="java.lang.Double" xmlns:saxon="http://icl.com/saxon" exclude-result-prefixes="v math saxon jDouble" xmlns="http://www.w3.org/2000/svg" version="1.0">

<xsl:output method="xml" version="1.0" omit-xml-declaration="no" media-type="image/svg+xml" encoding="iso-8 85 9-1" indent="yes"

cdata-section-elements="style" doctype-public="-//W3C//DTD SVG 1.0//EN"

doctype-system="http://www.w3.org/TR/2001/REC-SVG-20010 904/DTD/svg10.dtd"

/>

Таблица 13.1. Отображение элементов Visio на элементы SVG (окончание)

Параметр pageNumber задает номер страницы, извлекаемой из VDX-файла, а параметр userScale – коэффициент масштабирования для перевода из единиц Visio в единицы пользователя:

<xsl:param name="pageNumber" select="1"/> <xsl:param name="userScale" select="100"/>

<!– = = Переменные (т.е. константы) = = = = = = = = = –> <!– Таблица отображения цветов –> <xsl:variable name="Colors"

select="//v:Colors[position( )=1]/v:ColorEntry"/>

<!– Обрабатываемая страница –> <xsl:variable name="Page"

select="/v:VisioDocument/v:Pages/v:Page[number($pageNumber)]"/>

<!– Главные шаблоны –> <xsl:variable name="Masters"

select="//v:Masters[position( )=1]/v:Master"/>

<!– viewBox Master –> <xsl:variable name="viewBoxMaster"

select="$Masters[@NameU=’viewBox’]"/>

<!– Отношение высоты шрифта к ширине (поправочный коэффициент) –> <xsl:variable name="fontRatio" select="2"/>

<!– Число Pi (в SVG используются градусы, в Visio радианы) –> <xsl:variable name="pi" select="3.1415 92 65 35 8 97 932 38 4 62 64 3 38 327"/>

Таблица стилей разбита на несколько компонентов, которые включаются ко­мандой include. Часть из них будет рассмотрена ниже. Используются расшире­ния на языке JavaScript. Впрочем, если имеющийся у вас процессор XSLT не под­держивает JavaScript, код все равно будет работать, хотя форматирование будет не таким красивым.

<!– Включаемые файлы –> <xsl:include href="visio-style.xsl"/> <xsl:include href="visio-text.xsl"/> <xsl:include href="visio-masters.xsl"/> <xsl:include href="visio-nurbs.xsl"/>

<!– Сценарии –>

<xsl:template name="required-scripts">

<script xlink:href="wordwrap.js" type="text/ecmascript"/> </xsl:template>

<xsl:template match="/v:VisioDocument"> <xsl:apply-templates select="$Page"/> </xsl:template>

Страница Visio отображается на графику в формате SVG. Извлеченная из до­кумента Visio информация определяет, как оптимально расположить графику в области просмотра:

<!– = = = = = Страница = = = = = = = = = = = = =–> <xsl:template match="v:Page"> <xsl:message>

<xsl:value-of select="@NameU"/>

</xsl:message> <svg id="{@NameU}"> <xsl:attribute name="xml:space">

<xsl:value-of select="’preserve’"/> </xsl:attribute> <xsl:choose>

<!– Использовать viewBox с именем ‘default’, если таковой имеется — >

<xsl:when test="//v:Shape[@Master=$viewBoxMaster/@ID and @NameU=’default’][1]">

<xsl:for-each

select="//v:Shape[@Master=$viewBoxMaster/@ID

and @NameU=’default’]"> <xsl:attribute name="viewBox"> <xsl:value-of select="concat(

v:XForm/v:PinX*$userScale, ‘ ‘, -v:XForm/v:PinY*$userScale, ‘ ‘, v:XForm/v:Width*$userScale, ‘ ‘, v:XForm/v:Height*$userScale)"/>

</xsl:attribute> </xsl:for-each> </xsl:when>

<!– Иначе paспoлoжить в центpе листа –> <xsl:otherwise>

<xsl:attribute name="viewBox"> <xsl:value-of select="concat(‘0 ‘,

-v:PageSheet/v:PageProps/v:PageHeight

*$userScale, ‘ ‘, v:PageSheet/v:PageProps/v:PageWidth

*$userScale, ‘ ‘, v:PageSheet/v:PageProps/v:PageHeight *$userScale)"/>

</xsl:attribute> </xsl:otherwise> </xsl:choose>

<xsl:call-template name="required-scripts"/> <xsl:call-template name="predefined-pattern-fgnds"/> <xsl:call-template name="predefined-markers"/>

Отсюда начинается собственно преобразование. Для начала обработаем эле­менты Visio StyleSheet и преобразуем их в правила Cascading Style Sheet. За­тем преобразуем все формы в эквивалентное представление на SVG:

<xsl:apply-templates select="../../v:StyleSheets"/> <xsl:apply-templates select="v:Shapes/v:Shape"/>

</svg> </xsl:template>

<!– = = = = = StyleSheets = = = = = = = = = = = = –> <xsl:template match="v:StyleSheets"> <defs>

<xsl:for-each select="v:StyleSheet"> <!– Стиль линии –>

<style id="ss-line-{@ID}" type="text/css">

<xsl:text>*.ss-line-</xsl:text><xsl:value-of select="@ID"/> <xsl:text> { </xsl:text>

<xsl:call-template name="recursive-line-style">

<xsl:with-param name="ss" select="."/> </xsl:call-template> <xsl:text> }</xsl:text> </style>

<!– Стиль заливки –>

<style id="ss-fill-{@ID}" type="text/css">

<xsl:text>*.ss-fill-</xsl:text><xsl:value-of select="@ID"/> <xsl:text> { </xsl:text>

<xsl:call-template name="recursive-fill-style">

<xsl:with-param name="ss" select="."/> </xsl:call-template> <xsl:text> }</xsl:text> </style>

<!– Стиль текста –>

<style id="ss-text-{@ID}" type="text/css">

<xsl:text>*.ss-text-</xsl:text><xsl:value-of select="@ID"/> <xsl:text> { </xsl:text>

<xsl:call-template name="recursive-text-style">

<xsl:with-param name="ss" select="."/> </xsl:call-template> <xsl:text> } </xsl:text> </style> </xsl:for-each> </defs> </xsl:template>

<!– Рекурсивно обрабатываем наследование StyleSheet –> <xsl:template name="recursive-line-style"> <xsl:param name="ss"/> <xsl:if test="$ss/@LineStyle">

<xsl:call-template name="recursive-line-style"> <xsl:with-param name="ss"

select="$ss/../v:StyleSheet[@ID=$ss/@LineStyle]"/> </xsl:call-template> </xsl:if>

<xsl:apply-templates select="$ss/v:Line" mode="style"/> </xsl:template>

<xsl:template name="recursive-fill-style"> <xsl:param name="ss"/> <xsl:if test="$ss/@FillStyle">

<xsl:call-template name="recursive-fill-style"> <xsl:with-param name="ss"

select="$ss/../v:StyleSheet[@ID=$ss/@FillStyle]"/> </xsl:call-template> </xsl:if>

<xsl:apply-templates select="$ss/v:Fill" mode="style"/> </xsl:template>

<xsl:template name="recursive-text-style"> <xsl:param name="ss"/> <xsl:if test="$ss/@TextStyle">

<xsl:call-template name="recursive-text-style"> <xsl:with-param name="ss"

select="$ss/../v:StyleSheet[@ID=$ss/@TextStyle]"/> </xsl:call-template> </xsl:if>

<xsl:apply-templates select="$ss/v:Char|$ss/v:Para" mode="style"/> </xsl:template>

<!– Этот шаблон возвращает строку, описывающую стиль линии –> <xsl:template match="v:Line" mode="style"> <xsl:for-each select="v:LineWeight"> <xsl:text>stroke-width:</xsl:text>

<xsl:value-of select=". * $userScale"/><xsl:text>;</xsl:text> </xsl:for-each>

<xsl:for-each select="v:LineColor"> <xsl:choose>

<xsl:when test="../v:LinePattern > 0"> <xsl:text>stroke:</xsl:text> <xsl:call-template name="lookup-color">

<xsl:with-param name="c_el" select="."/> </xsl:call-template> </xsl:when>

<xsl:when test="../v:LinePattern = 0"> <xsl:text>stroke:none</xsl:text>

</xsl:when> </xsl:choose> <xsl:text>;</xsl:text> </xsl:for-each>

<xsl:for-each select="v:EndArrow"> <xsl:choose>

<xsl:when test=". = 0">

<xsl:value-of select="string(‘marker-end:none;’)"/> </xsl:when> <xsl:otherwise>

<xsl:value-of select="concat(‘marker-end:url(#EndArrow-‘, .,

‘-‘, ../v:EndArrowSize, ‘);’)"/>

</xsl:otherwise> </xsl:choose> </xsl:for-each>

<xsl:apply-templates select="v:LinePattern[. &gt; 1]" mode="style"/> </xsl:template>

<!– Этот шаблон возвращает строку, описывающую стиль заливки –> <xsl:template match="v:Fill" mode="style"> <xsl:for-each select="v:FillForegnd"> <xsl:choose>

<xsl:when test="../v:FillPattern = 1"> <xsl:text>fill:</xsl:text> <xsl:call-template name="lookup-color">

<xsl:with-param name="c_el" select="."/> </xsl:call-template> </xsl:when>

<xsl:when test="../v:FillPattern = 0">

<xsl:text>fill:none</xsl:text> </xsl:when> <xsl:otherwise>

<xsl:text>fill:url(#</xsl:text> <xsl:value-of select="generate-id(../..)"/> <xsl:text>-pat)</xsl:text> </xsl:otherwise> </xsl:choose> <xsl:text>;</xsl:text> </xsl:for-each> </xsl:template>

<!– Этот шаблон возвращает строку, описывающую стиль текста –> <xsl:template match="v:Char|v:Para" mode="style"> <xsl:for-each select="v:Color">

<!– Не думаю, что Visio обрабатывает залитые символы –> <xsl:text>stroke:none</xsl:text> <xsl:text>;fill:</xsl:text> <xsl:call-template name="lookup-color">

<xsl:with-param name="c_el" select="."/> </xsl:call-template> <xsl:text>;</xsl:text> </xsl:for-each>

<xsl:for-each select="v:Size">

<xsl:text>font-size:</xsl:text>

<xsl:value-of select=". * $userScale"/><xsl:text>;</xsl:text> </xsl:for-each>

<xsl:for-each select="v:HorzAlign"> <xsl:text>text-anchor:</xsl:text> <xsl:choose>

<xsl:when test="(. = 0) or (. = 3)">

<xsl:text>start</xsl:text> </xsl:when>

<xsl:when test=". = 1">

<xsl:text>middle</xsl:text> </xsl:when>

<xsl:when test=". = 2">

<xsl:text>end</xsl:text> </xsl:when> </xsl:choose> <xsl:text>;</xsl:text> </xsl:for-each> </xsl:template>

<!– Все остальные элементы StyleSheet игнорируем –> <xsl:template match="*[parent::v:StyleSheet]" priority="-100"/>

В следующем фрагменте формы отображаются на эквивалентные конструк­ции SVG. Обратите внимание, как можно ассоциировать формы с главными шаб­лонами в документе Visio. Можно считать, что главный шаблон – это образец, от которого нарисованная на странице форма наследует атрибуты и поведение.

По умолчанию каждая форма Visio транслируется в элемент <g>, так как она может содержать графику и текст. Напомним, что в SVG элемент <g> описывает группу графических элементов, имеющих общие стилистические характеристики.

SvgElement – это свойство Visio, которое пользователь может присоединить к форме для задания специальной обработки данным транслятором. Например, в качестве svgElement можно указать любой другой контейнерный элемент SVG, скажем defs. Таким способом можно запретить рисование некоторых форм, на­пример, путей для элементов animateMotion. То есть сослаться на путь в SVG- файле можно, а отображаться он не будет.

Одно из основных назначений элемента animateMotion – обозначить спе­циальные формы, которые транслируются в элементы, не имеющие аналогов в Visio, например, animate, animateMotion и viewBox. Эти элементы обраба­тываются таблицей стилей visio-master.xsl, которую мы рассмотрим ниже.

<!– = = = = Форма = = = = = = = = = = = = = = = –> <xsl:template match="v:Shape">

<xsl:variable name="master"

select="/v:VisioDocument//v:Masters[1]/

v:Master[@ID=current( )/@Master]"/>

<xsl:variable name="svgElement"> <xsl:choose>

<!— Проверить наличие специального свойства svgElement у формы … —> <xsl:when test="./v:Prop/v:Label[.=’svgElement’]"> <xsl:value-of

select="./v:Prop/v:Label[.=’svgElement’]/../v:Value"/> </xsl:when>

<!– … и у главного шаблона –> <xsl:when test="@Master and

$master//v:Prop/v:Label[.=’svgElement’]"> <xsl:value-of

select="$master//v:Prop/v:Label[.=’svgElement’]/../v:Value"/> </xsl:when>

<!— Простой случай: форма отображается на группу svg – элемент g –> <xsl:otherwise>

<xsl:value-of select="’g’"/> </xsl:otherwise> </xsl:choose> </xsl:variable>

<xsl:choose>

<xsl:when test="@Master and string($svgElement)

and contains($specialMasters, $svgElement)"> <xsl:call-template name="choose-special-master">

<xsl:with-param name="master" select="$master"/> <xsl:with-param name="masterElement" select="$svgElement"/> </xsl:call-template> </xsl:when>

<xsl:when test="($svgElement = ‘defs’) or ($svgElement = ‘g’) or ($svgElement = ‘symbol’)">

<xsl:choose>

<xsl:when test="v:Hyperlink">

<!– Погрузить форму в элемент ‘a’ –>

<!– Это минимальная реализация. Не поддерживаются –> <!– множественные ссылки, подадрес и т.д. –> <a xlink:title="{v:Hyperlink/v:Description}" xlink:href="{v:Hyperlink/v:Address}"> <xsl:if test="v:Hyperlink/v:NewWindow"> <xsl:attribute name="show">

<xsl:value-of select="new"/> </xsl:attribute> </xsl:if>

<xsl:element name="{$svgElement}">

<xsl:call-template name="userShape"/> </xsl:element> </a> </xsl:when> <xsl:otherwise>

<xsl:element name="{$svgElement}">

<xsl:call-template name="userShape"/> </xsl:element> </xsl:otherwise> </xsl:choose> </xsl:when> </xsl:choose> </xsl:template>

Далее обычные формы, созданные пользователем, отображаются на элементы SVG, как описано в таблице 13.1.

<!– Обработка обычных ‘пользовательских’ форм –> <xsl:template name="userShape"> <xsl:variable name="master"

select="/v:VisioDocument/v:Masters /v:Master[(@ID=current( )/@Master)

and (current( )/@Type != ‘Group’)] /v:Shapes/v:Shape | /v:VisioDocument/v:Masters /v:Master[@ID=current( ) /ancestor::v:Shape[@Master]/@Master] //v:Shape[@ID=current( )/@MasterShape] | ."/>

<xsl:call-template name="setIdAttribute"/>

<xsl:attribute name="class">

<xsl:for-each select="($master[@LineStyle])[last( )]"> <xsl:text> ss-line-</xsl:text> <xsl:value-of select="@LineStyle"/> </xsl:for-each>

<xsl:for-each select="($master[@FillStyle])[last( )]"> <xsl:text> ss-fill-</xsl:text> <xsl:value-of select="@FillStyle"/> </xsl:for-each> </xsl:attribute> <xsl:attribute name="style">

<xsl:for-each select="$master">

<xsl:apply-templates select="./v:Line" mode="style"/> <xsl:apply-templates select="./v:Fill" mode="style"/> </xsl:for-each> </xsl:attribute>

<xsl:for-each select="v:XForm">

<xsl:call-template name="transformAttribute"> </xsl:call-template> </xsl:for-each>

<!— Это нужно для создания специального образца —> <xsl:apply-templates select="v:Fill" mode="Shape"/> <xsl:for-each select="v:Geom">

<xsl:apply-templates select="v:Ellipse"/> <xsl:if test="v:MoveTo or v:LineTo">

<xsl:call-template name="pathElement"/> </xsl:if> </xsl:for-each>

<xsl:for-each select="($master/v:Text)[last( )]">

<xsl:apply-templates select="."/> </xsl:for-each>

<xsl:apply-templates select="v:Shapes/v:Shape"/>

<!— Добавить элементы, соответствующие свойствам —> <xsl:for-each select="v:Prop"> <xsl:choose>

<xsl:when test="starts-with(v:Label, ‘svg-element’)"> <!– Криво – в будущем, возможно, будет убрано –> <xsl:value-of disable-output-escaping="yes" select="v:Value" </xsl:when> </xsl:choose> </xsl:for-each> </xsl:template>

<!– Здесь у трансляции есть ограничения. Предполагается, что оси параллельны осям x и y, а левый нижний угол охватывающего прямоугольника находится в начале координат (похоже, именно так Visio рисует по умолчанию). –>

<ellipse id="ellipse-{generate-id(ancestor::v:Shape[1])}" cx="{v:X*$userScale}" cy="{-v:Y*$userScale}" rx="{v:X*$userScale}" ry="{v:Y*$userScale}"/> </xsl:template>

<!– = = = = Вспомогательные шаблоны = = = = = = = = = –>

<!– Поиск значения цвета в элементе Colors –> <xsl:template name="lookup-color"> <xsl:param name="c_el"/> <xsl:choose>

<xsl:when test="starts-with($c_el, ‘#’)">

<xsl:value-of select="$c_el"/> </xsl:when> <xsl:otherwise>

<xsl:value-of select="$Colors[@IX=string($c_el)]/@RGB"/> </xsl:otherwise> </xsl:choose> </xsl:template>

Если у элемента Visio есть имя, берем его в качестве идентификатора формы; в противном случае вызываем generate-id():

<xsl:template name="setIdAttribute"> <xsl:attribute name="id"> <xsl:choose>

<xsl:when test="@NameU">

<xsl:value-of select="@NameU"/> </xsl:when> <xsl:otherwise>

<xsl:value-of select="generate-id(.)"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template>

<!– Транслировать элемент XForm в атрибут transform –> <xsl:template name="transformAttribute"> <xsl:attribute name="transform"> <xsl:text>translate(</xsl:text>

<xsl:value-of select="concat((v:PinX – v:LocPinX)*$userScale,

‘,’, -(v:PinY – v:LocPinY)*$userScale)"/>

<xsl:if test="v:Angle != 0">

<xsl:text>) rotate(</xsl:text>

<xsl:value-of select="-v:Angle*18 0 div $pi"/> <xsl:value-of select="concat(‘,’, v:LocPinX*$userScale,

-v:LocPinY*$userScale)"/>

</xsl:if>

<xsl:text>)</xsl:text> </xsl:attribute> </xsl:template>

Элементы Vision Geom транслируются в пути. По большей части, отображе­ние прямолинейно. Исключение составляет обработка неоднородных рациональ­ных B-сплайнов (Non-Uniform Rational B-Splines – NURBS), которая делегирует­ся набору специальных шаблонов в файле visio-nurbs.xsl (имеется в полном дистрибутиве).

<!– Транслировать элемент Geom element в элемент path —> <xsl:template name="pathElement"> <xsl:variable name="pathID"> <xsl:text>path-</xsl:text> <xsl:choose>

<xsl:when test="ancestor::v:Shape[1]/@NameU">

<xsl:value-of select="ancestor::v:Shape[1]/@NameU"/> </xsl:when> <xsl:otherwise>

<xsl:value-of select="generate-id(ancestor::v:Shape[1])"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <path id="{$pathID}">

<xsl:attribute name="d">

<xsl:for-each select="v:*"> <xsl:choose>

<xsl:when test="name( ) = ‘MoveTo’">

<xsl:value-of select="concat(‘M’, v:X*$userScale,

-v:Y*$userScale, ‘ ‘)"/>

</xsl:when>

<xsl:when test="name( ) = ‘LineTo’">

<xsl:value-of select="concat(‘L’, v:X*$userScale,

-v:Y*$userScale, ‘ ‘)"/>

</xsl:when>

<xsl:when test="name( ) = ‘EllipticalArcTo’"> <!– Если тригонометрические функции недоступны, то дуга будет представлена двумя отрезками прямых –> <xsl:choose>

<xsl:when test="function-available(‘math:atan2′)">

<xsl:call-template name="ellipticalArcPath"/> </xsl:when> <xsl:otherwise>

<xsl:value-of select="concat(‘L’, v:A*$userScale, ‘,’, -v:B*$userScale, ‘ L’, v:X*$userScale, ‘,’, -v:Y*$userScale, ‘ ‘)"/>

</xsl:otherwise> </xsl:choose> </xsl:when>

<xsl:when test="(name( ) = ‘NoFill’) or (name( ) = ‘NoLine’) or (name( ) = ‘NoShow’) or (name( ) = ‘NoSnap’)"> <!— Игнорируются —> </xsl:when>

<xsl:when test="name( ) = ‘NURBSTo’">

<xsl:call-template name="NURBSPath"/> </xsl:when> <xsl:otherwise> <xsl:message>

<xsl:text>Предупреждение: обнаружена неподдерживаемая команда path:</xsl:text> <xsl:value-of select="name( )"/> <xsl:text>; replacing with LineTo</xsl:text> </xsl:message>

<xsl:value-of select="concat(‘L’, v:X*$userScale,

‘,’, -v:Y*$userScale, ‘ ‘)"/>

</xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:attribute> <xsl:if test="v:NoFill = 1">

<xsl:attribute name="fill"><xsl:text>none</xsl:text></xsl:attribute> </xsl:if> </path> </xsl:template>

<!— Этот шаблон вычисляет строку path для дуги эллипса —>

<xsl:template name="ellipticalArcPath">

<!– Нарисовать дугу, зная углы между текущей точкой и точками (X,Y) и (A,B) –>

<!– TODO: найти более удачный способ убедиться в том,

<!– что предшествующий брат — элемент, относящийся к рисованию –>

<xsl:variable name="lastX"

select="preceding-sibling::*[1]/v:X"/> <xsl:variable name="lastY"

select="preceding-sibling::*[1]/v:Y"/> <xsl:variable name="angle"

select="math:atan2(v:Y – $lastY, v:X – $lastX)

- math:atan2(v:B – $lastY, v:A – $lastX)"/> <xsl:variable name="sweep"> <xsl:choose> <xsl:when test="$angle &gt; 0

and math:abs($angle) &lt; 180"> <xsl:value-of select=’0’/> </xsl:when>

<xsl:when test="$angle &lt; 0

and math:abs($angle) &gt; 180"> <xsl:value-of select=’0’/> </xsl:when> <xsl:otherwise>

<xsl:value-of select=’1’/> </xsl:otherwise> </xsl:choose> </xsl:variable>

<xsl:value-of select="concat(‘A’,

(preceding-sibling::*[1]/v:X – v:X)*$userScale, ‘,’, (preceding-sibling::*[1]/v:Y – v:Y)*$userScale, ‘ ‘, v:C, ‘ 0,’, $sweep, ‘ ‘, v:X*$userScale, ‘,’,

-v:Y*$userScaie, ‘ ‘)"/>

</xsl:template> </xsl:stylesheet>

Обсуждение

В последней версии Visio поддерживается вывод в формате SVG. Тем не менее этот рецепт остается полезным, если у вас установлена старая версия Visio или преобразование, выполняемое в текущей версии, вас не устраивает. Понятно, что SVG – недостаточно развитый формат, чтобы точно представить все конструкции Visio, но аппроксимация довольно близкая. Простые диаграммы Visio можно транс­лировать в SVG почти без искажений. В более сложных случаях, возможно, придет­ся подправить результат в SVG-редакторе. В замечаниях к версии, включенных в состав полного дистрибутива Visio, все отсутствующие возможности перечислены. На рис. 13.1 показан пример SVG-файла, сгенерированного из диаграммы Visio; видно, что он отображается практически без изъянов.

Рис. 13.1. Простые SVG-формы и текст, полученные преобразованием файла Visio

Урок, который можно извлечь из этого примера, отнюдь не ограничивается деталями форматов Visio VDX , SVG и специальными приемами, которые приме­нил автор. Интересно, что это сложное преобразование было первым опытом ав­тора по работе с XSLT. И этот факт многое говорит о выразительности парадигмы преобразований, принятой в XSLT.

См. также

Исходный код и ряд демонстраций можно найти на сайте Source Forge по ад­ресу http://sourceforge.net/projects/vdxtosvg/.

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии