我们现在需要将istar的数据源文件转换为对应的图形显示,生成对应的svg(scalable vector graphics)显示,这一步可以当然也直接交给javascript处理,也可以使用xml转换语言xsl来尝试一下:
xsl完整文件如下:
不注释了。。stomach began to hurt...
xsl完整文件如下:
1<?xml version="1.0" encoding="UTF-8"?>
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns="http://www.w3.org/2000/svg">
3 <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
4 <xsl:template match="/">
5 <!--在打开svg的时候,自动创建link的显示-->
6 <svg onload="drawRelationships(evt)" width="100%" height="100%" version="1.1" id="istarSVG" preserveAspectRatio="xMidYMid meet" zoomAndPan="magnify">
7 <script language="JavaScript" xlink:href="./istar.js"/>
8 <!--指定javascript文件-->
9 <defs>
10 <!--自定义右键菜单-->
11 <menu id="NewMenu">
12 <header>XML to IStar Tool Menu</header>
13 <item enabled="no">XML to IStar Tool Menu</item>
14 <separator/>
15 <item action="ViewSource">View Source</item>
16 <item action="SaveSnapshotAs">Save Diagram As</item>
17 <separator/>
18 <item action="About">About SVG Viewer</item>
19 </menu>
20 <!--定义滤镜效果-->
21 <filter id="DropShadowFilter" filterUnits="objectBoundingBox" x="-50%" y="-50%" width="200%" height="200%">
22 <feGaussianBlur in="SourceAlpha" stdDeviation="2" result="BlurAlpha"/>
23 <feOffset in="BlurAlpha" dx="4" dy="4" result="OffsetBlurAlpha"/>
24 <feMerge>
25 <feMergeNode in="OffsetBlurAlpha"/>
26 <feMergeNode in="SourceGraphic"/>
27 </feMerge>
28 </filter>
29 <!--定义istar需要的四种link的箭头-->
30 <g stroke="black" fill="none">
31 <!--箭头实在独立的viewbox中的,其坐标系即相对于线条方向而定-->
32 <marker id = "DependencyMarker" viewBox = "0 0 40 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
33 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
34 orient = "auto" preserveAspectRatio="xMidYMid meet">
35 <path d="M0,40 l0,-40 c15,10 15,30 0,40"/>
36 </marker>
37 <marker id = "MeanMarker" viewBox = "0 0 60 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
38 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
39 orient = "auto" preserveAspectRatio="xMidYMid meet">
40 <path d="M0,0 v40 l60,-20 l-60,-20"/>
41 </marker>
42 <marker id = "DecompositionMarker" viewBox = "0 0 40 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
43 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
44 orient = "auto" preserveAspectRatio="xMidYMid meet">
45 <path d="M0,0 v40"/>
46 </marker>
47 <marker id = "ContributionMarker" viewBox = "0 0 40 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
48 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
49 orient = "auto" preserveAspectRatio="xMidYMid meet">
50 <path d="M0,0 l40,20 l-40,20"/>
51 </marker>
52 </g>
53 </defs>
54 <!--定义背景框,主要是为了接收拖动时的处理函数-->
55 <g id="background" onmousemove="mouseMove()" onmouseup="mouseUp()" style="pointer-events: none;">
56 <rect id="border" x="0" y="0" width="100%" height="100%" style="fill: none; stroke-width: 1px; stroke: #000000; shape-rendering: optimizeSpeed;" transform="scale(1,1)"/>
57 </g>
58 <g fill="none" stroke="black" stroke-width="2">
59 <xsl:apply-templates select="*"/>
60 </g>
61 <g id="controls" transform="scale(1,1)translate(0,0)">
62 <rect x="260" y="10" rx="10" ry="10" width="100" height="100" style="fill:yellow;opacity:0.4;stroke:black;stroke-width:2;filter:url(#DropShadowFilter);"/>
63 <image id="panUp" x="280" y="36" onclick="pan(0,-1)" width="19" height="13" xlink:href="./images/up.gif"/>
64 <image id="panRight" x="300" y="50" onclick="pan(1,0)" width="13" height="19" xlink:href="./images/right.gif"/>
65 <image id="panDown" x="280" y="70" onclick="pan(0,1)" width="19" height="13" xlink:href="./images/down.gif"/>
66 <image id="panLeft" x="264" y="50" onclick="pan(-1,0)" width="13" height="19" xlink:href="./images/left.gif"/>
67 <image id="zoomIn" x="314" y="36" onclick="zoom(1.2)" width="19" height="19" xlink:href="./images/zoomIn.gif"/>
68 <image id="zoomOut" x="336" y="36" onclick="zoom(0.8)" width="19" height="19" xlink:href="./images/zoomOut.gif"/>
69 <image id="reset" x="323" y="62" onclick="reset()" width="21" height="21" xlink:href="./images/reset.gif"/>
70 </g>
71 </svg>
72 </xsl:template>
73 <xsl:template name="recursion">
74 <xsl:param name="actorindex"/>
75 <xsl:param name="Ypos1"/>
76 <xsl:choose>
77 <xsl:when test="$actorindex = 5">
78 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
79 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
80 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)
81 +count(/istar/actor[2]/goal)
82 + count(/istar/actor[2]/softgoal) + count(/istar/actor[2]/task)
83 + count(/istar/actor[2]/resource) + count(/istar/actor[2]/belief)
84 +count(/istar/actor[3]/goal)
85 + count(/istar/actor[3]/softgoal) + count(/istar/actor[3]/task)
86 + count(/istar/actor[3]/resource) + count(/istar/actor[3]/belief)
87 +count(/istar/actor[4]/goal)
88 + count(/istar/actor[4]/softgoal) + count(/istar/actor[4]/task)
89 + count(/istar/actor[4]/resource) + count(/istar/actor[4]/belief)"/>
90 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
91 <xsl:value-of select="$Ypos2"/>
92 </xsl:when>
93 <xsl:when test="$actorindex = 4">
94 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
95 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
96 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)
97 +count(/istar/actor[2]/goal)
98 + count(/istar/actor[2]/softgoal) + count(/istar/actor[2]/task)
99 + count(/istar/actor[2]/resource) + count(/istar/actor[2]/belief)
100 +count(/istar/actor[3]/goal)
101 + count(/istar/actor[3]/softgoal) + count(/istar/actor[3]/task)
102 + count(/istar/actor[3]/resource) + count(/istar/actor[3]/belief)"/>
103 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
104 <xsl:value-of select="$Ypos2"/>
105 </xsl:when>
106 <xsl:when test="$actorindex = 3">
107 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
108 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
109 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)
110 +count(/istar/actor[2]/goal)
111 + count(/istar/actor[2]/softgoal) + count(/istar/actor[2]/task)
112 + count(/istar/actor[2]/resource) + count(/istar/actor[2]/belief)"/>
113 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
114 <xsl:value-of select="$Ypos2"/>
115 </xsl:when>
116 <xsl:when test="$actorindex = 2">
117 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
118 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
119 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)"/>
120 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
121 <xsl:value-of select="$Ypos2"/>
122 </xsl:when>
123 <xsl:when test="$actorindex = 1">
124 <xsl:value-of select="$Ypos1"/>
125 </xsl:when>
126 </xsl:choose>
127 </xsl:template>
128 <xsl:template match="/istar/actor">
129 <xsl:param name="prenum" select="0"/>
130 <xsl:param name="actorindex" select="position()"/>
131 <xsl:param name="Ypos1" select="150 * position()"/>
132 <xsl:variable name="Ypos">
133 <xsl:call-template name="recursion">
134 <xsl:with-param name="Ypos1" select="150 * position()"/>
135 <xsl:with-param name="actorindex" select="position()"/>
136 </xsl:call-template>
137 </xsl:variable>
138 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="50" y="{$Ypos - 90}" height="100" width="100">
139 <circle r="50" cx="100" cy="{$Ypos - 90}"/>
140 <path d="M 10 {$Ypos - 90 } L 190 {$Ypos - 90 }" stroke="none">
141 <xsl:attribute name="id"><xsl:value-of select="concat('actor_', @ID)"/></xsl:attribute>
142 </path>
143 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
144 <textPath xlink:href="#{concat('actor_', @ID)}" startOffset="50%" dy="10">
145 <xsl:value-of select="name"/>
146 </textPath>
147 </text>
148 <xsl:for-each select="./*">
149 <xsl:apply-templates select=".">
150 <xsl:with-param name="xOffset" select="((position() - 2) mod 3) * 200 + 240"/>
151 <xsl:with-param name="yOffset" select="format-number(((position()) div 3), '#') * 150 + $Ypos - 150 "/>
152 </xsl:apply-templates>
153 </xsl:for-each>
154 </g>
155 </xsl:template>
156 <xsl:template match="/istar/actor/goal">
157 <xsl:param name="xOffset"/>
158 <xsl:param name="yOffset"/>
159 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
160 <rect x="{$xOffset}" y="{$yOffset}" rx="30" ry="50" width="120" height="80"/>
161 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
162 <xsl:attribute name="id"><xsl:value-of select="concat('innergoal_', @ID)"/></xsl:attribute>
163 </path>
164 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
165 <textPath xlink:href="#{concat('innergoal_', @ID)}" startOffset="50%" dy="10">
166 <xsl:value-of select="name"/>
167 </textPath>
168 </text>
169 </g>
170 </xsl:template>
171 <xsl:template match="istar/actor/softgoal">
172 <xsl:param name="xOffset"/>
173 <xsl:param name="yOffset"/>
174 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
175 <path d="M{$xOffset},{$yOffset+40} c0,-20 15,-40 30,-40 c15,10 45,10 60,0 c15,0 30,20 30,40
176 c0,20 -15,40 -30,40 c-15,-10 -45,-10 -60,0 c-15,0 -30,-20 -30,-40"/>
177 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
178 <xsl:attribute name="id"><xsl:value-of select="concat('innersoftgoal_', @ID)"/></xsl:attribute>
179 </path>
180 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
181 <textPath xlink:href="#{concat('innersoftgoal_', @ID)}" startOffset="50%" dy="10">
182 <xsl:value-of select="name"/>
183 </textPath>
184 </text>
185 </g>
186 </xsl:template>
187 <xsl:template match="istar/actor/task">
188 <xsl:param name="xOffset"/>
189 <xsl:param name="yOffset"/>
190 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
191 <path d="M{$xOffset},{$yOffset+40} l30,-40 h60 l30,40 l-30,40 h-60 l-30,-40"/>
192 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
193 <xsl:attribute name="id"><xsl:value-of select="concat('innertask_', @ID)"/></xsl:attribute>
194 </path>
195 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
196 <textPath xlink:href="#{concat('innertask_', @ID)}" startOffset="50%" dy="10">
197 <xsl:value-of select="name"/>
198 </textPath>
199 </text>
200 </g>
201 </xsl:template>
202 <xsl:template match="istar/actor/resource">
203 <xsl:param name="xOffset"/>
204 <xsl:param name="yOffset"/>
205 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
206 <rect x="{$xOffset}" y="{$yOffset}" width="120" height="80"/>
207 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
208 <xsl:attribute name="id"><xsl:value-of select="concat('innerresource_', @ID)"/></xsl:attribute>
209 </path>
210 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
211 <textPath xlink:href="#{concat('innerresource_', @ID)}" startOffset="50%" dy="10">
212 <xsl:value-of select="name"/>
213 </textPath>
214 </text>
215 </g>
216 </xsl:template>
217 <xsl:template match="istar/actor/belief">
218 <xsl:param name="xOffset"/>
219 <xsl:param name="yOffset"/>
220 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
221 <ellipse cx="{$xOffset+60}" cy="{$yOffset+40}" rx="60" ry="40"/>
222 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
223 <xsl:attribute name="id"><xsl:value-of select="concat('innergoal_', @ID)"/></xsl:attribute>
224 </path>
225 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
226 <textPath xlink:href="#{concat('innergoal_', @ID)}" startOffset="50%" dy="10">
227 <xsl:value-of select="name"/>
228 </textPath>
229 </text>
230 </g>
231 </xsl:template>
232 <xsl:template match="istar/actor/Mean-ends-link">
233 <g from="{from/@ID}" to="{to/@ID}">
234 <path marker-mid = "url(#MeanMarker)" d="M0,0 l80,75 l80,75"/>
235 </g>
236 </xsl:template>
237 <xsl:template match="istar/actor/Contribution-link">
238 <g from="{from/@ID}" to="{to/@ID}">
239 <path marker-end = "url(#ContributionMarker)" d="M0,0 l80,75 l80,75"/>
240 </g>
241 </xsl:template>
242 <xsl:template match="istar/actor/Decomposition-link">
243 <g from="{from/@ID}" to="{to/@ID}">
244 <path marker-mid = "url(#DecompositionMarker)" d="M0,0 l80,75 l80,75"/>
245 </g>
246 </xsl:template>
247 <xsl:template match="istar/goal">
248 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
249 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
250 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
251 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
252 <rect x="{$xOffset}" y="{$yOffset}" rx="30" ry="50" width="120" height="80"/>
253 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
254 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
255 </path>
256 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
257 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
258 <xsl:value-of select="name"/>
259 </textPath>
260 </text>
261 </g>
262 </xsl:template>
263 <xsl:template match="istar/softgoal">
264 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
265 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
266 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
267
268 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
269 <path d="M{$xOffset},{$yOffset+40} c0,-20 15,-40 30,-40 c15,10 45,10 60,0 c15,0 30,20 30,40
270 c0,20 -15,40 -30,40 c-15,-10 -45,-10 -60,0 c-15,0 -30,-20 -30,-40"/>
271 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
272 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
273 </path>
274 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
275 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
276 <xsl:value-of select="name"/>
277 </textPath>
278 </text>
279 </g>
280 </xsl:template>
281 <xsl:template match="istar/task">
282 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
283 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
284 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
285 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
286 <path d="M{$xOffset},{$yOffset+40} l30,-40 h60 l30,40 l-30,40 h-60 l-30,-40"/>
287 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
288 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
289 </path>
290 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
291 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
292 <xsl:value-of select="name"/>
293 </textPath>
294 </text>
295 </g>
296 </xsl:template>
297 <xsl:template match="istar/resource">
298 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
299 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
300 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
301 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
302 <rect x="{$xOffset}" y="{$yOffset}" width="120" height="80"/>
303 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
304 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
305 </path>
306 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
307 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
308 <xsl:value-of select="name"/>
309 </textPath>
310 </text>
311 </g>
312 </xsl:template>
313 <xsl:template match="istar/belief">
314 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
315 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
316 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
317 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
318 <ellipse cx="{$xOffset+60}" cy="{$yOffset+40}" rx="60" ry="40"/>
319 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
320 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
321 </path>
322 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
323 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
324 <xsl:value-of select="name"/>
325 </textPath>
326 </text>
327 </g>
328 </xsl:template>
329 <xsl:template match="istar/Dependency-link">
330 <g from="{depender/@ID}" to="{dependee/@ID}">
331 <path marker-mid = "url(#DependencyMarker)" d="M0,0 l80,75 l80,75"/>
332 </g>
333 </xsl:template>
334 <xsl:template match="//name">
335 </xsl:template>
336</xsl:stylesheet>
337
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns="http://www.w3.org/2000/svg">
3 <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
4 <xsl:template match="/">
5 <!--在打开svg的时候,自动创建link的显示-->
6 <svg onload="drawRelationships(evt)" width="100%" height="100%" version="1.1" id="istarSVG" preserveAspectRatio="xMidYMid meet" zoomAndPan="magnify">
7 <script language="JavaScript" xlink:href="./istar.js"/>
8 <!--指定javascript文件-->
9 <defs>
10 <!--自定义右键菜单-->
11 <menu id="NewMenu">
12 <header>XML to IStar Tool Menu</header>
13 <item enabled="no">XML to IStar Tool Menu</item>
14 <separator/>
15 <item action="ViewSource">View Source</item>
16 <item action="SaveSnapshotAs">Save Diagram As</item>
17 <separator/>
18 <item action="About">About SVG Viewer</item>
19 </menu>
20 <!--定义滤镜效果-->
21 <filter id="DropShadowFilter" filterUnits="objectBoundingBox" x="-50%" y="-50%" width="200%" height="200%">
22 <feGaussianBlur in="SourceAlpha" stdDeviation="2" result="BlurAlpha"/>
23 <feOffset in="BlurAlpha" dx="4" dy="4" result="OffsetBlurAlpha"/>
24 <feMerge>
25 <feMergeNode in="OffsetBlurAlpha"/>
26 <feMergeNode in="SourceGraphic"/>
27 </feMerge>
28 </filter>
29 <!--定义istar需要的四种link的箭头-->
30 <g stroke="black" fill="none">
31 <!--箭头实在独立的viewbox中的,其坐标系即相对于线条方向而定-->
32 <marker id = "DependencyMarker" viewBox = "0 0 40 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
33 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
34 orient = "auto" preserveAspectRatio="xMidYMid meet">
35 <path d="M0,40 l0,-40 c15,10 15,30 0,40"/>
36 </marker>
37 <marker id = "MeanMarker" viewBox = "0 0 60 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
38 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
39 orient = "auto" preserveAspectRatio="xMidYMid meet">
40 <path d="M0,0 v40 l60,-20 l-60,-20"/>
41 </marker>
42 <marker id = "DecompositionMarker" viewBox = "0 0 40 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
43 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
44 orient = "auto" preserveAspectRatio="xMidYMid meet">
45 <path d="M0,0 v40"/>
46 </marker>
47 <marker id = "ContributionMarker" viewBox = "0 0 40 40" refX = "35" refY = "20" markerUnits = "strokeWidth" markerWidth = "30"
48 markerHeight ="10" stroke = "blue" stroke-width = "3" fill = "none"
49 orient = "auto" preserveAspectRatio="xMidYMid meet">
50 <path d="M0,0 l40,20 l-40,20"/>
51 </marker>
52 </g>
53 </defs>
54 <!--定义背景框,主要是为了接收拖动时的处理函数-->
55 <g id="background" onmousemove="mouseMove()" onmouseup="mouseUp()" style="pointer-events: none;">
56 <rect id="border" x="0" y="0" width="100%" height="100%" style="fill: none; stroke-width: 1px; stroke: #000000; shape-rendering: optimizeSpeed;" transform="scale(1,1)"/>
57 </g>
58 <g fill="none" stroke="black" stroke-width="2">
59 <xsl:apply-templates select="*"/>
60 </g>
61 <g id="controls" transform="scale(1,1)translate(0,0)">
62 <rect x="260" y="10" rx="10" ry="10" width="100" height="100" style="fill:yellow;opacity:0.4;stroke:black;stroke-width:2;filter:url(#DropShadowFilter);"/>
63 <image id="panUp" x="280" y="36" onclick="pan(0,-1)" width="19" height="13" xlink:href="./images/up.gif"/>
64 <image id="panRight" x="300" y="50" onclick="pan(1,0)" width="13" height="19" xlink:href="./images/right.gif"/>
65 <image id="panDown" x="280" y="70" onclick="pan(0,1)" width="19" height="13" xlink:href="./images/down.gif"/>
66 <image id="panLeft" x="264" y="50" onclick="pan(-1,0)" width="13" height="19" xlink:href="./images/left.gif"/>
67 <image id="zoomIn" x="314" y="36" onclick="zoom(1.2)" width="19" height="19" xlink:href="./images/zoomIn.gif"/>
68 <image id="zoomOut" x="336" y="36" onclick="zoom(0.8)" width="19" height="19" xlink:href="./images/zoomOut.gif"/>
69 <image id="reset" x="323" y="62" onclick="reset()" width="21" height="21" xlink:href="./images/reset.gif"/>
70 </g>
71 </svg>
72 </xsl:template>
73 <xsl:template name="recursion">
74 <xsl:param name="actorindex"/>
75 <xsl:param name="Ypos1"/>
76 <xsl:choose>
77 <xsl:when test="$actorindex = 5">
78 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
79 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
80 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)
81 +count(/istar/actor[2]/goal)
82 + count(/istar/actor[2]/softgoal) + count(/istar/actor[2]/task)
83 + count(/istar/actor[2]/resource) + count(/istar/actor[2]/belief)
84 +count(/istar/actor[3]/goal)
85 + count(/istar/actor[3]/softgoal) + count(/istar/actor[3]/task)
86 + count(/istar/actor[3]/resource) + count(/istar/actor[3]/belief)
87 +count(/istar/actor[4]/goal)
88 + count(/istar/actor[4]/softgoal) + count(/istar/actor[4]/task)
89 + count(/istar/actor[4]/resource) + count(/istar/actor[4]/belief)"/>
90 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
91 <xsl:value-of select="$Ypos2"/>
92 </xsl:when>
93 <xsl:when test="$actorindex = 4">
94 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
95 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
96 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)
97 +count(/istar/actor[2]/goal)
98 + count(/istar/actor[2]/softgoal) + count(/istar/actor[2]/task)
99 + count(/istar/actor[2]/resource) + count(/istar/actor[2]/belief)
100 +count(/istar/actor[3]/goal)
101 + count(/istar/actor[3]/softgoal) + count(/istar/actor[3]/task)
102 + count(/istar/actor[3]/resource) + count(/istar/actor[3]/belief)"/>
103 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
104 <xsl:value-of select="$Ypos2"/>
105 </xsl:when>
106 <xsl:when test="$actorindex = 3">
107 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
108 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
109 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)
110 +count(/istar/actor[2]/goal)
111 + count(/istar/actor[2]/softgoal) + count(/istar/actor[2]/task)
112 + count(/istar/actor[2]/resource) + count(/istar/actor[2]/belief)"/>
113 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
114 <xsl:value-of select="$Ypos2"/>
115 </xsl:when>
116 <xsl:when test="$actorindex = 2">
117 <xsl:variable name="prenum" select="count(/istar/actor[1]/goal)
118 + count(/istar/actor[1]/softgoal) + count(/istar/actor[1]/task)
119 + count(/istar/actor[1]/resource) + count(/istar/actor[1]/belief)"/>
120 <xsl:variable name="Ypos2" select="$Ypos1 + format-number((($prenum) div 3), '#') * 150"/>
121 <xsl:value-of select="$Ypos2"/>
122 </xsl:when>
123 <xsl:when test="$actorindex = 1">
124 <xsl:value-of select="$Ypos1"/>
125 </xsl:when>
126 </xsl:choose>
127 </xsl:template>
128 <xsl:template match="/istar/actor">
129 <xsl:param name="prenum" select="0"/>
130 <xsl:param name="actorindex" select="position()"/>
131 <xsl:param name="Ypos1" select="150 * position()"/>
132 <xsl:variable name="Ypos">
133 <xsl:call-template name="recursion">
134 <xsl:with-param name="Ypos1" select="150 * position()"/>
135 <xsl:with-param name="actorindex" select="position()"/>
136 </xsl:call-template>
137 </xsl:variable>
138 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="50" y="{$Ypos - 90}" height="100" width="100">
139 <circle r="50" cx="100" cy="{$Ypos - 90}"/>
140 <path d="M 10 {$Ypos - 90 } L 190 {$Ypos - 90 }" stroke="none">
141 <xsl:attribute name="id"><xsl:value-of select="concat('actor_', @ID)"/></xsl:attribute>
142 </path>
143 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
144 <textPath xlink:href="#{concat('actor_', @ID)}" startOffset="50%" dy="10">
145 <xsl:value-of select="name"/>
146 </textPath>
147 </text>
148 <xsl:for-each select="./*">
149 <xsl:apply-templates select=".">
150 <xsl:with-param name="xOffset" select="((position() - 2) mod 3) * 200 + 240"/>
151 <xsl:with-param name="yOffset" select="format-number(((position()) div 3), '#') * 150 + $Ypos - 150 "/>
152 </xsl:apply-templates>
153 </xsl:for-each>
154 </g>
155 </xsl:template>
156 <xsl:template match="/istar/actor/goal">
157 <xsl:param name="xOffset"/>
158 <xsl:param name="yOffset"/>
159 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
160 <rect x="{$xOffset}" y="{$yOffset}" rx="30" ry="50" width="120" height="80"/>
161 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
162 <xsl:attribute name="id"><xsl:value-of select="concat('innergoal_', @ID)"/></xsl:attribute>
163 </path>
164 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
165 <textPath xlink:href="#{concat('innergoal_', @ID)}" startOffset="50%" dy="10">
166 <xsl:value-of select="name"/>
167 </textPath>
168 </text>
169 </g>
170 </xsl:template>
171 <xsl:template match="istar/actor/softgoal">
172 <xsl:param name="xOffset"/>
173 <xsl:param name="yOffset"/>
174 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
175 <path d="M{$xOffset},{$yOffset+40} c0,-20 15,-40 30,-40 c15,10 45,10 60,0 c15,0 30,20 30,40
176 c0,20 -15,40 -30,40 c-15,-10 -45,-10 -60,0 c-15,0 -30,-20 -30,-40"/>
177 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
178 <xsl:attribute name="id"><xsl:value-of select="concat('innersoftgoal_', @ID)"/></xsl:attribute>
179 </path>
180 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
181 <textPath xlink:href="#{concat('innersoftgoal_', @ID)}" startOffset="50%" dy="10">
182 <xsl:value-of select="name"/>
183 </textPath>
184 </text>
185 </g>
186 </xsl:template>
187 <xsl:template match="istar/actor/task">
188 <xsl:param name="xOffset"/>
189 <xsl:param name="yOffset"/>
190 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
191 <path d="M{$xOffset},{$yOffset+40} l30,-40 h60 l30,40 l-30,40 h-60 l-30,-40"/>
192 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
193 <xsl:attribute name="id"><xsl:value-of select="concat('innertask_', @ID)"/></xsl:attribute>
194 </path>
195 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
196 <textPath xlink:href="#{concat('innertask_', @ID)}" startOffset="50%" dy="10">
197 <xsl:value-of select="name"/>
198 </textPath>
199 </text>
200 </g>
201 </xsl:template>
202 <xsl:template match="istar/actor/resource">
203 <xsl:param name="xOffset"/>
204 <xsl:param name="yOffset"/>
205 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
206 <rect x="{$xOffset}" y="{$yOffset}" width="120" height="80"/>
207 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
208 <xsl:attribute name="id"><xsl:value-of select="concat('innerresource_', @ID)"/></xsl:attribute>
209 </path>
210 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
211 <textPath xlink:href="#{concat('innerresource_', @ID)}" startOffset="50%" dy="10">
212 <xsl:value-of select="name"/>
213 </textPath>
214 </text>
215 </g>
216 </xsl:template>
217 <xsl:template match="istar/actor/belief">
218 <xsl:param name="xOffset"/>
219 <xsl:param name="yOffset"/>
220 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
221 <ellipse cx="{$xOffset+60}" cy="{$yOffset+40}" rx="60" ry="40"/>
222 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
223 <xsl:attribute name="id"><xsl:value-of select="concat('innergoal_', @ID)"/></xsl:attribute>
224 </path>
225 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
226 <textPath xlink:href="#{concat('innergoal_', @ID)}" startOffset="50%" dy="10">
227 <xsl:value-of select="name"/>
228 </textPath>
229 </text>
230 </g>
231 </xsl:template>
232 <xsl:template match="istar/actor/Mean-ends-link">
233 <g from="{from/@ID}" to="{to/@ID}">
234 <path marker-mid = "url(#MeanMarker)" d="M0,0 l80,75 l80,75"/>
235 </g>
236 </xsl:template>
237 <xsl:template match="istar/actor/Contribution-link">
238 <g from="{from/@ID}" to="{to/@ID}">
239 <path marker-end = "url(#ContributionMarker)" d="M0,0 l80,75 l80,75"/>
240 </g>
241 </xsl:template>
242 <xsl:template match="istar/actor/Decomposition-link">
243 <g from="{from/@ID}" to="{to/@ID}">
244 <path marker-mid = "url(#DecompositionMarker)" d="M0,0 l80,75 l80,75"/>
245 </g>
246 </xsl:template>
247 <xsl:template match="istar/goal">
248 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
249 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
250 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
251 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
252 <rect x="{$xOffset}" y="{$yOffset}" rx="30" ry="50" width="120" height="80"/>
253 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
254 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
255 </path>
256 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
257 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
258 <xsl:value-of select="name"/>
259 </textPath>
260 </text>
261 </g>
262 </xsl:template>
263 <xsl:template match="istar/softgoal">
264 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
265 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
266 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
267
268 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
269 <path d="M{$xOffset},{$yOffset+40} c0,-20 15,-40 30,-40 c15,10 45,10 60,0 c15,0 30,20 30,40
270 c0,20 -15,40 -30,40 c-15,-10 -45,-10 -60,0 c-15,0 -30,-20 -30,-40"/>
271 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
272 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
273 </path>
274 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
275 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
276 <xsl:value-of select="name"/>
277 </textPath>
278 </text>
279 </g>
280 </xsl:template>
281 <xsl:template match="istar/task">
282 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
283 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
284 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
285 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
286 <path d="M{$xOffset},{$yOffset+40} l30,-40 h60 l30,40 l-30,40 h-60 l-30,-40"/>
287 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
288 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
289 </path>
290 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
291 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
292 <xsl:value-of select="name"/>
293 </textPath>
294 </text>
295 </g>
296 </xsl:template>
297 <xsl:template match="istar/resource">
298 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
299 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
300 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
301 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
302 <rect x="{$xOffset}" y="{$yOffset}" width="120" height="80"/>
303 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
304 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
305 </path>
306 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
307 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
308 <xsl:value-of select="name"/>
309 </textPath>
310 </text>
311 </g>
312 </xsl:template>
313 <xsl:template match="istar/belief">
314 <xsl:param name="precount" select="position() - count(/istar/actor)"/>
315 <xsl:param name="xOffset" select="(($precount + 1) mod 2) * 200 + 940"/>
316 <xsl:param name="yOffset" select="format-number(( ($precount + 1) div 2 ), '#') * 250 - 200"/>
317 <g id="{@ID}" onmousedown="mouseDown()" style="pointer-events:all;opacity:1.0;z-index:1;" transform="translate(0,0)" x="{$xOffset}" y="{$yOffset+40}" height="80" width="120">
318 <ellipse cx="{$xOffset+60}" cy="{$yOffset+40}" rx="60" ry="40"/>
319 <path d="M {$xOffset + 10 - 40} {$yOffset+40} L {$xOffset + 190 -40 } {$yOffset+40}" stroke="none">
320 <xsl:attribute name="id"><xsl:value-of select="concat('outgoal', @ID)"/></xsl:attribute>
321 </path>
322 <text text-anchor="middle" font-family="Verdana" font-size="10" fill="blue" stroke-width="0" startOffset="0">
323 <textPath xlink:href="#{concat('outgoal', @ID)}" startOffset="50%" dy="10">
324 <xsl:value-of select="name"/>
325 </textPath>
326 </text>
327 </g>
328 </xsl:template>
329 <xsl:template match="istar/Dependency-link">
330 <g from="{depender/@ID}" to="{dependee/@ID}">
331 <path marker-mid = "url(#DependencyMarker)" d="M0,0 l80,75 l80,75"/>
332 </g>
333 </xsl:template>
334 <xsl:template match="//name">
335 </xsl:template>
336</xsl:stylesheet>
337
不注释了。。stomach began to hurt...