![]() |
Форум visio.getbb.ru |
О форумах
Библиотека | Частые вопросы | Литература | Склад материалов Visio Navigator | Blog | Полезные ссылки | О сайте История Visio | Продукты Visio |
Для русскоязычных пользователей Visio. Начинающих и профессионалов. Где взять, как сделать, что купить и т.д. |
Геннадий Туманов
Так как Visio, начиная с 2002 версии позволяет сохранять документ в формате XML (.vdx) интересно было попробовать использовать его в качестве XML источника данных. Попробовал, вот что получилось.
Исходный файл d1.vdx содержит всего три прямоугольника с Custom Properties p1, p2 и p3. Ставилась задача – выбрать эти Custom Properties. Вспомогательный инструмент – MSXML. Программа написана в VB6.
Проверены два способа: работа с DOM и XSLT-преобразование.
Работа с DOM никаких неожиданностей не принесла. Вот такой текст
Sub GetCustProp()
'Выборка данных из Visio файла с помощью MSXML
Dim xmlVis As MSXML2.DOMDocument 'Исходный документ
Dim NL As MSXML2.IXMLDOMNodeList
Dim NL1 As MSXML2.IXMLDOMNodeList
Dim NL2 As MSXML2.IXMLDOMNodeList
Set xmlVis = New MSXML2.DOMDocument
xmlVis.validateOnParse = False
xmlVis.async = False
s = fPath & "d1.vdx"
xmlVis.Load (s)
Set NL = xmlVis.getElementsByTagName("*/Shape")
For i = 0 To NL.length - 1
Set NL1 = NL.Item(i).selectNodes("@ID")
Debug.Print "ID шейпа = " & NL1.Item(0).Text
Set NL1 = NL.Item(i).selectNodes("Prop")
s = ""
For j = 0 To NL1.length - 1
Set NL2 = NL1.Item(j).selectNodes("Label")
s = s & NL2.Item(0).Text
Set NL2 = NL1.Item(j).selectNodes("Value")
s = s & " = " & NL2.Item(0).Text & "; "
Next
Debug.Print s
Next
Set xmlVis = Nothing
End Sub
дает вот такой вывод
ID шейпа = 1
p1 = Первый; p2 = wetwer; p3 = fgdfgsdfgsdf;
ID шейпа = 2
p1 = Второй; p2 = wert wer wer ; p3 = gh fg hfgh fg h;
ID шейпа = 3
p1 = Третий; p2 = kkkkkk; p3 = uyyyyyyyyi iiii;
Все, что требуется, – ориентироваться в XML модели Visio.
Этот вариант дался немного потяжелее. Текст программы
Sub CopyCustPropToFile()
'Конвертирование Visio файла с помощью MSXML. XLT-преобразование
Dim xmlSource As MSXML2.DOMDocument
Dim xmlTr As MSXML2.DOMDocument
Set xmlSource = New MSXML2.DOMDocument
xmlSource.validateOnParse = False
xmlSource.async = False
s = fPath & "d1.vdx"
'Из входного файла приходится вырезать xmlns
s1 = fPath & "d1.vdx"
s2 = fPath & "temp.vdx"
Open s1 For Input As #1
Open s2 For Output As #2
Input #1, s3
Print #2, s3
Input #1, s3
s3 = Replace(s3, " xmlns='http://schemas.microsoft.com/visio/2003/core'", "")
Print #2, s3
Do While Not EOF(1)
Input #1, s3
Print #2, s3
Loop
Close #1
Close #2
'На вход загружается почищенная копия
s = fPath & "temp.vdx"
xmlSource.Load (s)
'Загрузка трансформатора
Set xmlTr = New MSXML2.DOMDocument
xmlTr.validateOnParse = False
s = fPath & "Автоконвертор.xslt"
xmlTr.Load (s)
'Вот собственно преобразование
s = xmlSource.transformNode(xmlTr)
'Трансформатор по умолчанию создает выходной файл в кодировке "UTF-16"
'Это можно исправить непосредственно в трансформаторе или (грубо) вручную функцией Replace
s = Replace(s, "UTF-16", "Windows-1251")
s1 = fPath & "d2.htm"
Open s1 For Output As #1
Print #1, s
Close #1
Set xmlSource = Nothing
Set xmlTr = Nothing
End Sub
Текст конвертора (файл Автоконвертор.xslt)
<?xml version="1.0" encoding="ISO-8859-5"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:template match="/">
<html>
<head />
<body>
<xsl:for-each select="VisioDocument">
<xsl:for-each select="DocumentSheet">
<xsl:for-each select="@NameU">
<xsl:value-of select="." />
</xsl:for-each>
</xsl:for-each>
<br />
<xsl:for-each select="Pages/Page">
<xsl:for-each select="@NameU">Страница = <xsl:value-of select="." />
</xsl:for-each>
<br />
<table border="1">
<xsl:for-each select="Shapes">
<xsl:for-each select="Shape">
<tr>
<xsl:for-each select="Prop">
<td>
<xsl:for-each select="Label">
<xsl:value-of select="." />
</xsl:for-each> =
<xsl:for-each select="Value">
<xsl:value-of select="." />
</xsl:for-each>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</xsl:for-each>
</table>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
На выходе получается html файл d2.htm примерно такого вида
TheDoc
Страница = Page-1
p1 = Первый p2 = wetwer p3 = fgdfgsdfgsdf
p1 = Второй p2 = wert wer wer p3 = gh fg hfgh fg h
p1 = Третий p2 = kkkkkk p3 = uyyyyyyyyi iiii
Все неприятности возникли почему-то из-за ссылки на пространство имен. Visio вставляет в файл атрибут xmlns='http://schemas.microsoft.com/visio/2003/core'. Но MSXML с такой ссылкой работать отказывается (еще надо бы выяснить, почему). Удаляться через RemoveNamedItem такой атрибут отказывается (другие атрибуты удаляются).
Причина скорее всего в том, что привязка к пространству имен в MSXML очень глубокая. Однажды захватив эту ссылку, он уже распространяет ее на весь документ. При попытке удаления атрибута со ссылкой атрибут на самом деле удаляется, но для сохранения привязки MSXML тут же вставляет аналогичный атрибут в другом месте.
Аналогичная история происходит при попытке создать новый документ и поэлементно перенести в него компоненты из первого. Ссылка xmlns размножается и присваивается каждому переносимому компоненту.
Радикальный способ – удалить ссылку непосредственно во входном файле. Это работает. Если весь входной файл переписать во временный, вычистив из второй строки ссылку xmlns, и подать полученную копию на вход конвертора, у MSXML претензий не возникает. Так и сделано в приведенном примере.