はじめに
それvisioで欲しいんだよね。
最近、blockdiag+SphinxのコラボでDFDやシーケンス図の自動生成に精をだしていた矢先、
- 「visio出力してほしい」
- 「編集したい」
という声が上がってしまいました。
そんなこんなで、visioを自動出力しようかと考えたのですが、
- visioマクロでの生成はイケてない。そもそもVisioがないと動かないし。
- POIのVisio生成は、仕様が難しいうえに、一部対応しきれていないという情報もあり
- IronPythonで実装するのも、C#で実装するのもVisioと変わらないし。
- 自由度の高いフリーソフトも見つからず…。
などの理由で悩んでいました。
visioファイルはXML形式
そんななか、実はvisioでよく利用されるファイル形式vdxがただのXML形式のファイルであることを知り、その構成について手探りで調べたメモになります。
簡単な構成でXMLを作成してみる
<VisioDocument>
<StyleSheets/>
<Masters>
</Masters>
<Pages>
<Page ID="0">
<PageSheet>
<PageProps>
<!-- ページのレイアウト -->
<PageWidth>10</PageWidth>
<PageHeight>10</PageHeight>
</PageProps>
</PageSheet>
<Shapes>
<Shape ID="1" >
<XForm>
<!-- 位置 -->
<PinX>1</PinX>
<PinY>1</PinY>
<!-- オブジェクトの大きさ -->
<Width>2.5</Width>
<Height>1</Height>
</XForm>
<Fill>
<!-- 背景色 -->
<FillForegnd F="RGB(255,255,255)"/>
</Fill>
<!-- 罫線の詳細定義 -->
<Line>
<!-- 太さ -->
<LineWeight>0.0138889</LineWeight>
<!-- 色 -->
<LineColor F="RGB(32,32,140)"/>
<!-- 普通の線 -->
<LinePattern>1</LinePattern>
</Line>
<!-- 文字定義 -->
<Char IX="0">
<Font F="FONTTOID("Arial")">0</Font>
<Color F="RGB(140,32,32)"/>
<Style>0</Style>
<Size>0.138889</Size>
</Char>
<!-- オブジェクトの線 -->
<Geom IX="0">
<!-- 線をつくる点の開始位置 -->
<MoveTo IX="1">
<X F="Width*0" />
<Y F="Height*1" />
</MoveTo>
<!-- 線をつくる点(IX="1"と線としてつながる) -->
<LineTo IX="2">
<X F="Width*0" />
<Y F="Height*0" />
</LineTo>
<!-- 線をつくる点(IX="2"と線としてつながる) -->
<LineTo IX="3">
<X F="Width*1" />
<Y F="Height*0" />
</LineTo>
<!-- 線をつくる点(IX="3"と線としてつながる) -->
<LineTo IX="4">
<X F="Width*1" />
<Y F="Height*1" />
</LineTo>
<!-- 線をつくる点(IX="4"と線としてつながる) -->
<LineTo IX="5">
<X F="Width*0" />
<Y F="Height*1" />
</LineTo>
</Geom>
<Text>Sample</Text>
<!-- 線などを結ぶためのコネクタ -->
<Connection IX="0">
<X F="Width*1"/>
<Y F="Height*0.5"/>
</Connection>
</Shape>
</Shapes>
</Page>
</Pages>
</VisioDocument>
Masterタグを利用してみる
上記のような記載をおこなうと、オブジェクトを1つ作る毎に冗長なコードが必要になります。
したがって、visioファイルの容量も大きくなります。
そこでよく利用するオブジェクトをカプセル化するイメージで定義し、インスタンスを生成するように実行することができます。
それがMasterタグになります。
<VisioDocument>
<StyleSheets/>
<Masters>
<Master ID='0' NameU='Normal Object' Name='ただの四角' Prompt='' >
<!-- Normalな四角 -->
<Shapes>
<Shape ID='5' Type='Shape'>
<!-- オブジェクトの大きさ -->
<XForm><Width>2</Width><Height>0.75</Height></XForm>
<!-- 背景色 -->
<Fill><FillForegnd F="RGB(255,255,255)"/></Fill>
<Line><LineWeight>0.0138889</LineWeight><LineColor F="RGB(32,32,140)"/><LinePattern>1</LinePattern></Line>
<Char IX="0"><Font F="FONTTOID("Arial")">0</Font><Color F="RGB(0,0,0)"/><Style>0</Style><Size>0.138889</Size></Char>
<!-- オブジェクトの線 -->
<Geom IX="0"><MoveTo IX="1"><X F="Width*0" /><Y F="Height*1" /></MoveTo><LineTo IX="2"><X F="Width*0" /><Y F="Height*0" /></LineTo><LineTo IX="3"><X F="Width*1" /><Y F="Height*0" /></LineTo><LineTo IX="4"><X F="Width*1" /><Y F="Height*1" /></LineTo><LineTo IX="5"><X F="Width*0" /><Y F="Height*1" /></LineTo></Geom>
<!-- 接続点の定義 -->
<Connection IX='0'><X F='Width*1'/><Y F='Height*0.5'/></Connection>
<Connection IX='1'><X F='Width*0.5'/><Y Unit='MM'/></Connection>
<Connection IX='2'><X F='Width*0'/><Y F='Height*0.5'/></Connection>
<Connection IX='3'><X F='Width*0.5'/><Y Unit='MM' F='Height*1'/></Connection>
</Shape>
</Shapes>
</Master>
</Masters>
<Pages>
<Page ID="0">
<PageSheet>
<PageProps>
<!-- ページのレイアウト -->
<PageWidth>10</PageWidth>
<PageHeight>10</PageHeight>
</PageProps>
</PageSheet>
<Shapes>
<Shape ID="1" Master='0'>
<XForm><PinX F='2+3*0'/><PinY F='1*1'/></XForm>
<Text>BL1</Text>
</Shape>
<Shape ID="2" Master='0'>
<XForm><PinX F='2+3*1'/><PinY F='1*2'/></XForm>
<Text>BL2</Text>
</Shape>
</Shapes>
</Page>
</Pages>
</VisioDocument>
Masterタグはオーバーライド可能
また上記例では、行いませんでしたがMasterタグはShapeタグで同じものを定義すればオーバーライドできます。
必要なオブジェクトはMaster化して増やしてく
あとは、必要なオブジェクトをMaster化して増やせば、Masterは多少冗長になりますが、簡単なVisioの図は自動生成できるようになっていきます。
オブジェクト定義一つ一つは、元々Visioに搭載されているサンプルから取得して、あとは必要な箇所を切り取って利用します。
以下は、その一例になります。
<?xml version='1.0' encoding='utf-8' ?>
<VisioDocument xml:space='preserve' xmlns:vx='http://schemas.microsoft.com/visio/2006/extension' xmlns='http://schemas.microsoft.com/visio/2003/core'>
<!-- オブジェクト定義 -->
<Masters>
<Master ID='0' NameU='Normal Object' Name='ただの四角' Prompt='' >
<!-- Normalな四角 -->
<Shapes>
<Shape ID='5' Type='Shape'>
<!-- オブジェクトの大きさ -->
<XForm><Width>2</Width><Height>0.75</Height></XForm>
<Fill><FillForegnd F="RGB(255,255,255)"/></Fill>
<Line><LineWeight>0.0138889</LineWeight><LineColor F="RGB(32,32,140)"/><LinePattern>1</LinePattern></Line>
<Char IX="0"><Font F="FONTTOID("Arial")">0</Font><Color F="RGB(0,0,0)"/><Style>0</Style><Size>0.138889</Size></Char>
<!-- 罫線 -->
<Geom IX="0"><MoveTo IX="1"><X F="Width*0" /><Y F="Height*1" /></MoveTo><LineTo IX="2"><X F="Width*0" /><Y F="Height*0" /></LineTo><LineTo IX="3"><X F="Width*1" /><Y F="Height*0" /></LineTo><LineTo IX="4"><X F="Width*1" /><Y F="Height*1" /></LineTo><LineTo IX="5"><X F="Width*0" /><Y F="Height*1" /></LineTo></Geom>
<Connection IX='0'><X F='Width*1'/><Y F='Height*0.5'/></Connection>
<Connection IX='1'><X F='Width*0.5'/><Y Unit='MM'/></Connection>
<Connection IX='2'><X F='Width*0'/><Y F='Height*0.5'/></Connection>
<Connection IX='3'><X F='Width*0.5'/><Y Unit='MM' F='Height*1'/></Connection>
</Shape>
</Shapes>
</Master>
<!-- ドラム缶 -->
<Master ID='1' NameU='Data store' Name='データ保管'>
<Shapes>
<Shape ID='5' Type='Shape'>
<!-- オブジェクトの大きさ -->
<XForm><Width>2</Width><Height>0.75</Height></XForm>
<TextXForm><TxtPinX Unit='PT' F='Controls.Row_2'>0.3937007874015748</TxtPinX><TxtPinY F='Controls.Row_2.Y'>-0.09444444444444444</TxtPinY><TxtWidth Unit='PT' F='MAX(TEXTWIDTH(TheText),8*Char.Size)'>0.8888888888888888</TxtWidth><TxtHeight F='TEXTHEIGHT(TheText,TxtWidth)'>0.1888888888888889</TxtHeight><TxtLocPinX Unit='PT' F='TxtWidth*0.5'>0.4444444444444444</TxtLocPinX><TxtLocPinY F='TxtHeight*0.5'>0.09444444444444444</TxtLocPinY><TxtAngle>0</TxtAngle></TextXForm>
<TextBlock><LeftMargin Unit='PT' F='Inh'>0.02777777777777778</LeftMargin><RightMargin Unit='PT' F='Inh'>0.02777777777777778</RightMargin><TopMargin Unit='PT' F='Inh'>0.02777777777777778</TopMargin><BottomMargin Unit='PT' F='Inh'>0.02777777777777778</BottomMargin><VerticalAlign F='Inh'>1</VerticalAlign><TextBkgnd F='Inh'>0</TextBkgnd><DefaultTabStop F='Inh'>0.5</DefaultTabStop><TextDirection F='Inh'>0</TextDirection><TextBkgndTrans F='Inh'>0</TextBkgndTrans></TextBlock>
<Event><TheData F='No Formula'>0</TheData><TheText F='No Formula'>0</TheText><EventDblClick F='OPENTEXTWIN()'>0</EventDblClick><EventXFMod F='No Formula'>0</EventXFMod><EventDrop F='No Formula'>0</EventDrop></Event>
<vx:Event xmlns:vx='http://schemas.microsoft.com/visio/2006/extension'><vx:EventMultiDrop F='No Formula'>0</vx:EventMultiDrop></vx:Event>
<Help><HelpTopic>Vis_D21.chm!#48063</HelpTopic><Copyright V='null'/></Help>
<Misc><NoObjHandles F='Inh'>0</NoObjHandles><NonPrinting F='Inh'>0</NonPrinting><NoCtlHandles F='Inh'>0</NoCtlHandles><NoAlignBox F='Inh'>0</NoAlignBox><UpdateAlignBox F='Inh'>0</UpdateAlignBox><HideText F='Inh'>0</HideText><DynFeedback F='Inh'>0</DynFeedback><GlueType F='Inh'>0</GlueType><WalkPreference F='Inh'>0</WalkPreference><BegTrigger F='No Formula'>0</BegTrigger><EndTrigger F='No Formula'>0</EndTrigger><ObjType>1</ObjType><Comment F='Inh'/><IsDropSource F='Inh'>0</IsDropSource><NoLiveDynamics F='Inh'>0</NoLiveDynamics><LocalizeMerge F='Inh'>0</LocalizeMerge><Calendar F='Inh'>0</Calendar><LangID F='Inh'>1041</LangID><ShapeKeywords F='Inh'/><DropOnPageScale F='Inh'>1</DropOnPageScale></Misc>
<Protection><LockWidth F='Inh'>0</LockWidth><LockHeight F='Inh'>0</LockHeight><LockMoveX F='Inh'>0</LockMoveX><LockMoveY F='Inh'>0</LockMoveY><LockAspect F='Inh'>0</LockAspect><LockDelete F='Inh'>0</LockDelete><LockBegin F='Inh'>0</LockBegin><LockEnd F='Inh'>0</LockEnd><LockRotate F='Inh'>0</LockRotate><LockCrop F='Inh'>0</LockCrop><LockVtxEdit F='Inh'>0</LockVtxEdit><LockTextEdit F='Inh'>0</LockTextEdit><LockFormat F='Inh'>0</LockFormat><LockGroup F='Inh'>0</LockGroup><LockCalcWH F='Inh'>0</LockCalcWH><LockSelect F='Inh'>0</LockSelect><LockCustProp F='Inh'>0</LockCustProp></Protection>
<vx:Protection xmlns:vx='http://schemas.microsoft.com/visio/2006/extension'><vx:LockFromGroupFormat F='Inh'>0</vx:LockFromGroupFormat><vx:LockThemeColors F='Inh'>0</vx:LockThemeColors><vx:LockThemeEffects>1</vx:LockThemeEffects></vx:Protection>
<User NameU='CH' ID='1'><Value F='IF(TEXTWIDTH(TheText)-LeftMargin-RightMargin>0.1PT,0,5)'>5</Value><Prompt F='No Formula'/></User>
<User NameU='visVersion' ID='3'><Value>12</Value><Prompt F='No Formula'/></User>
<Control NameU='Row_1' ID='1'><X F='Width*0.5'>0.3937007874015748</X><Y Unit='MM' F='Height-7.499999986MM'>0.4921259848031497</Y><XDyn F='Controls.Row_1'>0.3937007874015748</XDyn><YDyn Unit='MM' F='Controls.Row_1.Y'>0.4921259848031497</YDyn><XCon F='IF(OR(Height=0,Width=0),6,1)'>1</XCon><YCon>4</YCon><CanGlue>1</CanGlue><Prompt>奥行の変更</Prompt></Control>
<!-- 背景色 -->
<Fill><FillForegnd F="RGB(30,144,255)"/></Fill>
<Line>
<!-- 罫線の太さ -->
<LineWeight>0.0138889</LineWeight>
<!-- 罫線の色 -->
<LineColor F="RGB(32,32,140)"/>
<!-- 罫線の普通の線 -->
<LinePattern>1</LinePattern>
</Line>
<!-- custom 文字の配置 -->
<Control NameU='Row_2' ID='2'><X Unit='PT' F='Width*0.5'/><Y Unit='PT' F='Height*0.375'/></Control>
<!-- custom 文字定義 -->
<Char IX="0"><Font F="FONTTOID("Arial")">0</Font><Color F="RGB(140,32,32)"/><Style>0</Style><Size>0.138889</Size></Char>
<Scratch IX='0'><X F='No Formula'>0</X><Y Unit='MM' F='MAX(Height-ABS(MAX(Height*0.25,Controls.Row_1.Y)),0)'>0.29527559</Y><A Unit='BOOL' F='IF(Controls.Row_1.Y<Height*0,SETF(GetRef(Controls.Row_1.Y),Height*0),IF(Controls.Row_1.Y>Height*1,SETF(GetRef(Controls.Row_1.Y),Height*1),FALSE))'>0</A><B F='No Formula'>0</B><C F='No Formula'>0</C><D F='No Formula'>0</D></Scratch>
<Connection IX='0'><X F='Width*1'/><Y F='Height*0.5'/><DirX F='No Formula'>0</DirX><DirY F='No Formula'>0</DirY><Type F='No Formula'>0</Type><AutoGen F='No Formula'>0</AutoGen><Prompt F='No Formula'/></Connection>
<Connection IX='1'><X F='Width*0.5'/><Y Unit='MM'/><DirX F='No Formula'>0</DirX><DirY F='No Formula'>0</DirY><Type F='No Formula'>0</Type><AutoGen F='No Formula'>0</AutoGen><Prompt F='No Formula'/></Connection>
<Connection IX='2'><X F='Width*0'/><Y F='Height*0.5'/><DirX F='No Formula'>0</DirX><DirY F='No Formula'>0</DirY><Type F='No Formula'>0</Type><AutoGen F='No Formula'>0</AutoGen><Prompt F='No Formula'/></Connection>
<Connection IX='3'><X F='Width*0.5'/><Y Unit='MM' F='Height*1-0.5*Scratch.Y1'/><DirX F='No Formula'>0</DirX><DirY F='No Formula'>0</DirY><Type F='No Formula'>0</Type><AutoGen F='No Formula'>0</AutoGen><Prompt F='No Formula'/></Connection>
<Geom IX='0'><NoFill>0</NoFill><NoLine>0</NoLine><NoShow>0</NoShow><NoSnap F='No Formula'>0</NoSnap><MoveTo IX='1'><X F='Width*0'>0</X><Y Unit='MM' F='Height-0.5*Scratch.Y1'>0.6397637798031497</Y></MoveTo><EllipticalArcTo IX='2'><X F='Width'>0.7874015748031497</X><Y Unit='MM' F='Height-0.5*Scratch.Y1'>0.6397637798031497</Y><A Unit='DL' F='Width*0.5'>0.3937007874015748</A><B Unit='DL' F='Height*1'>0.7874015748031497</B><C Unit='DA'>0</C><D F='Width/Scratch.Y1'>2.666666671644445</D></EllipticalArcTo><EllipticalArcTo IX='3'><X F='Geometry1.X1'>0</X><Y Unit='MM' F='Geometry1.Y1'>0.6397637798031497</Y><A Unit='DL' F='Width*0.5'>0.3937007874015748</A><B Unit='MM' F='Height-Scratch.Y1'>0.4921259848031497</B><C Unit='DA'>0</C><D F='Width/Scratch.Y1'>2.666666671644445</D></EllipticalArcTo></Geom>
<Geom IX='1'><NoFill>0</NoFill><NoLine>0</NoLine><NoShow>0</NoShow><NoSnap F='No Formula'>0</NoSnap><MoveTo IX='1'><X F='Width*0'>0</X><Y Unit='MM' F='Height-(0.5*Scratch.Y1)'>0.6397637798031497</Y></MoveTo><LineTo IX='2'><X F='Width*0'>0</X><Y Unit='MM' F='0.5*Scratch.Y1'>0.147637795</Y></LineTo><EllipticalArcTo IX='3'><X F='Width*1'>0.7874015748031497</X><Y Unit='MM' F='0.5*Scratch.Y1'>0.147637795</Y><A Unit='DL' F='Width*0.5'>0.3937007874015748</A><B Unit='MM'>0</B><C Unit='DA'>0</C><D F='Width/Scratch.Y1'>2.666666671644445</D></EllipticalArcTo><LineTo IX='4'><X F='Width*1'>0.7874015748031497</X><Y Unit='MM' F='Height-(0.5*Scratch.Y1)'>0.6397637798031497</Y></LineTo><EllipticalArcTo IX='5'><X F='Geometry2.X1'>0</X><Y Unit='MM' F='Geometry2.Y1'>0.6397637798031497</Y><A Unit='DL' F='Width*0.5'>0.3937007874015748</A><B Unit='MM' F='Height-(Scratch.Y1)'>0.4921259848031497</B><C Unit='DA'>0</C><D F='Width/Scratch.Y1'>2.666666671644445</D></EllipticalArcTo></Geom>
<Text><cp IX='0'/></Text>
</Shape>
</Shapes>
</Master>
<Master ID='11' NameU='Dynamic connector' Name='動的コネクタ'>
<Shapes>
<Shape ID='5' Type='Shape'>
<!-- オブジェクト情報をXForm1Dより -->
<XForm><PinX F="(BeginX+EndX)/2"/><PinY F="(BeginY+EndY)/2"/><Width F='GUARD(EndX-BeginX)'/><Height F='GUARD(EndY-BeginY)'/></XForm>
<XForm1D><BeginX>1.181102362204724</BeginX><BeginY>2.362204724409449</BeginY><EndX>2.362204724409449</EndX><EndY>1.181102362204724</EndY></XForm1D>
<TextXForm><TxtPinX F='SETATREF(Controls.TextPosition)'>0</TxtPinX><TxtPinY F='SETATREF(Controls.TextPosition.Y)'>-1.181102362204724</TxtPinY><TxtWidth F='MAX(TEXTWIDTH(TheText),5*Char.Size)'>0.5555555555555556</TxtWidth><TxtHeight F='TEXTHEIGHT(TheText,TxtWidth)'>0.2444444444444444</TxtHeight><TxtLocPinX F='TxtWidth*0.5'>0.2777777777777778</TxtLocPinX><TxtLocPinY F='TxtHeight*0.5'>0.1222222222222222</TxtLocPinY><TxtAngle>0</TxtAngle></TextXForm>
<Protection><LockWidth>0</LockWidth><LockHeight>1</LockHeight><LockMoveX>0</LockMoveX><LockMoveY>0</LockMoveY><LockAspect F='Inh'>0</LockAspect><LockDelete>0</LockDelete><LockBegin F='Inh'>0</LockBegin><LockEnd F='Inh'>0</LockEnd><LockRotate>0</LockRotate><LockCrop F='Inh'>0</LockCrop><LockVtxEdit>0</LockVtxEdit><LockTextEdit>0</LockTextEdit><LockFormat F='Inh'>0</LockFormat><LockGroup F='Inh'>0</LockGroup><LockCalcWH>1</LockCalcWH><LockSelect F='Inh'>0</LockSelect><LockCustProp F='Inh'>0</LockCustProp></Protection>
<vx:Protection xmlns:vx='http://schemas.microsoft.com/visio/2006/extension'><vx:LockFromGroupFormat F='Inh'>0</vx:LockFromGroupFormat><vx:LockThemeColors>0</vx:LockThemeColors><vx:LockThemeEffects>0</vx:LockThemeEffects></vx:Protection>
<Help><HelpTopic>Vis_SE.chm!#20000</HelpTopic><Copyright>Copyright 2001 Microsoft Corporation. All rights reserved.</Copyright></Help>
<Misc><NoObjHandles F='Inh'>0</NoObjHandles><NonPrinting F='Inh'>0</NonPrinting><NoCtlHandles F='Inh'>0</NoCtlHandles><NoAlignBox>1</NoAlignBox><UpdateAlignBox F='Inh'>0</UpdateAlignBox><HideText F='Inh'>0</HideText><DynFeedback>2</DynFeedback><GlueType>2</GlueType><WalkPreference F='Inh'>0</WalkPreference><BegTrigger F='No Formula'>0</BegTrigger><EndTrigger F='No Formula'>0</EndTrigger><ObjType>2</ObjType><Comment F='Inh'/><IsDropSource F='Inh'>0</IsDropSource><NoLiveDynamics>1</NoLiveDynamics><LocalizeMerge F='Inh'>0</LocalizeMerge><Calendar F='Inh'>0</Calendar><LangID F='Inh'>1041</LangID><ShapeKeywords F='Inh'/><DropOnPageScale F='Inh'>1</DropOnPageScale></Misc>
<Layout><ShapePermeableX F='Inh'>0</ShapePermeableX><ShapePermeableY F='Inh'>0</ShapePermeableY><ShapePermeablePlace F='Inh'>0</ShapePermeablePlace><ShapeFixedCode F='Inh'>0</ShapeFixedCode><ShapePlowCode F='Inh'>0</ShapePlowCode><ShapeRouteStyle F='Inh'>0</ShapeRouteStyle><ConFixedCode F='Inh'>0</ConFixedCode><ConLineJumpCode F='Inh'>0</ConLineJumpCode><ConLineJumpStyle F='Inh'>0</ConLineJumpStyle><ConLineJumpDirX F='Inh'>0</ConLineJumpDirX><ConLineJumpDirY F='Inh'>0</ConLineJumpDirY><ShapePlaceFlip F='Inh'>0</ShapePlaceFlip><ConLineRouteExt F='Inh'>0</ConLineRouteExt><ShapeSplit F='Inh'>0</ShapeSplit><ShapeSplittable>1</ShapeSplittable></Layout>
<vx:Layout xmlns:vx='http://schemas.microsoft.com/visio/2006/extension'><vx:ShapePlaceStyle F='Inh'>0</vx:ShapePlaceStyle></vx:Layout>
<LayerMem><LayerMember>0</LayerMember></LayerMem>
<Event><TheData F='No Formula'>0</TheData><TheText F='No Formula'>0</TheText><EventDblClick F='No Formula'>0</EventDblClick><EventXFMod F='No Formula'>0</EventXFMod><EventDrop F='No Formula'>0</EventDrop></Event>
<vx:Event xmlns:vx='http://schemas.microsoft.com/visio/2006/extension'><vx:EventMultiDrop F='No Formula'>0</vx:EventMultiDrop></vx:Event>
<Control NameU='TextPosition' ID='1'><X>0</X><Y>-1.181102362204724</Y><XDyn F='Controls.TextPosition'>0</XDyn><YDyn F='Controls.TextPosition.Y'>-1.181102362204724</YDyn><XCon F='IF(OR(STRSAME(SHAPETEXT(TheText),""),HideText),5,0)'>5</XCon><YCon>0</YCon><CanGlue>0</CanGlue><Prompt>Reposition Text</Prompt></Control>
<Char IX='0'><Font F='Inh'>7</Font><Color F='Inh'>0</Color><Style F='Inh'>0</Style><Case F='Inh'>0</Case><Pos F='Inh'>0</Pos><FontScale F='Inh'>1</FontScale><Size F='Inh'>0.1111111111111111</Size><DblUnderline F='Inh'>0</DblUnderline><Overline F='Inh'>0</Overline><Strikethru F='Inh'>0</Strikethru><Highlight F='Inh'>0</Highlight><DoubleStrikethrough F='Inh'>0</DoubleStrikethrough><RTLText F='Inh'>0</RTLText><UseVertical F='Inh'>0</UseVertical><Letterspace F='Inh'>0</Letterspace><ColorTrans F='Inh'>0</ColorTrans><AsianFont F='Inh'>7</AsianFont><ComplexScriptFont F='Inh'>0</ComplexScriptFont><LocalizeFont F='Inh'>0</LocalizeFont><ComplexScriptSize F='Inh'>-1</ComplexScriptSize><LangID F='Inh'>1041</LangID></Char>
<!-- 線の折れぐらいをカスタム定義 -->
<Geom IX='0'><MoveTo IX='1'><X F="Width*0"/><Y F="Height*0"/></MoveTo><LineTo IX='2'><X F="Width*0.25"/><Y F="Height*0"/></LineTo><LineTo IX='3'><X F="Width*0.25"/><Y F="Height*1"/></LineTo><LineTo IX='4'><X F="Width*1"/><Y F="Height*1"/></LineTo></Geom>
<!-- 背景を透過させる -->
<Fill><FillForegnd F='Inh'>1</FillForegnd><FillBkgnd F='Inh'>0</FillBkgnd><FillPattern F='Inh'>1</FillPattern><ShdwForegnd F='Inh'>0</ShdwForegnd><ShdwBkgnd F='Inh'>1</ShdwBkgnd><ShdwPattern F='Inh'>0</ShdwPattern><FillForegndTrans>1</FillForegndTrans><FillBkgndTrans>1</FillBkgndTrans><ShdwForegndTrans F='Inh'>0</ShdwForegndTrans><ShdwBkgndTrans F='Inh'>0</ShdwBkgndTrans><ShapeShdwType F='Inh'>0</ShapeShdwType><ShapeShdwOffsetX F='Inh'>0</ShapeShdwOffsetX><ShapeShdwOffsetY F='Inh'>0</ShapeShdwOffsetY><ShapeShdwObliqueAngle F='Inh'>0</ShapeShdwObliqueAngle><ShapeShdwScaleFactor F='Inh'>1</ShapeShdwScaleFactor></Fill>
</Shape>
</Shapes>
</Master>
</Masters>
<Pages>
<Page ID="0">
<PageSheet>
<PageProps>
<!-- 1+3*3 -->
<PageWidth>10</PageWidth>
<PageHeight>10</PageHeight>
</PageProps>
</PageSheet>
<Shapes>
<!-- Object -->
<Shape ID="1" Master='0'>
<XForm><PinX F='2+3*0'/><PinY F='1'/></XForm>
<Text>BL</Text>
</Shape>
<Shape ID="2" Master='1'>
<XForm><PinX F='2+3*1'/><PinY F='2'/></XForm>
<Text>DataBase</Text>
</Shape>
<Shape ID="3" Master='1'>
<XForm><PinX F='2+3*1'/><PinY F='1'/></XForm>
<Text>DataBase</Text>
</Shape>
<Shape ID="4" Master='0'>
<XForm><PinX F='2+3*2'/><PinY F='1'/></XForm>
<Text>BL2</Text>
</Shape>
<!-- Edge -->
<Shape ID='10' Master='11'>
<XForm1D>
<BeginX F="PAR(PNT(Sheet.1!Connections.X1,Sheet.1!Connections.Y1))"/>
<BeginY F="PAR(PNT(Sheet.1!Connections.X1,Sheet.1!Connections.Y1))"/>
<EndX F="PAR(PNT(Sheet.2!Connections.X3,Sheet.2!Connections.Y1))"/>
<EndY F="PAR(PNT(Sheet.2!Connections.X3,Sheet.2!Connections.Y1))"/>
</XForm1D>
</Shape>
<Shape ID='11' Master='11'>
<XForm1D>
<BeginX F="PAR(PNT(Sheet.1!Connections.X1,Sheet.1!Connections.Y1))"/>
<BeginY F="PAR(PNT(Sheet.1!Connections.X1,Sheet.1!Connections.Y1))"/>
<EndX F="PAR(PNT(Sheet.3!Connections.X3,Sheet.3!Connections.Y1))"/>
<EndY F="PAR(PNT(Sheet.3!Connections.X3,Sheet.3!Connections.Y1))"/>
</XForm1D>
</Shape>
<Shape ID='12' Master='11'>
<XForm1D>
<BeginX F="PAR(PNT(Sheet.2!Connections.X1,Sheet.2!Connections.Y1))"/>
<BeginY F="PAR(PNT(Sheet.2!Connections.X1,Sheet.2!Connections.Y1))"/>
<EndX F="PAR(PNT(Sheet.4!Connections.X3,Sheet.4!Connections.Y1))"/>
<EndY F="PAR(PNT(Sheet.4!Connections.X3,Sheet.4!Connections.Y1))"/>
</XForm1D>
</Shape>
<Shape ID='13' Master='11'>
<XForm1D>
<BeginX F="PAR(PNT(Sheet.3!Connections.X1,Sheet.3!Connections.Y1))"/>
<BeginY F="PAR(PNT(Sheet.3!Connections.X1,Sheet.3!Connections.Y1))"/>
<EndX F="PAR(PNT(Sheet.4!Connections.X3,Sheet.4!Connections.Y1))"/>
<EndY F="PAR(PNT(Sheet.4!Connections.X3,Sheet.4!Connections.Y1))"/>
</XForm1D>
</Shape>
</Shapes>
</Page>
</Pages>
</VisioDocument>
おわりに...
割りとXMLをparseすることはできそうですが、一方でこれを毎度生成するのはツライなーっと感じました。
なので、元気がでたらblockdiagのparser等々を利用して、同じAPIでblockdiagのファイル形式からvisio出力できるようにしたいと夢見ています。