XQuery/序列图
外观
< XQuery
即使使用绘图工具,序列图也很难绘制。当序列发生变化时,它们更难编辑。一种替代方法是定义一个 XML 词汇表来定义消息排序,并使用 XQuery 将此描述渲染为 XHTML。这种文本方法还允许在每个步骤中显示解释,并生成序列 XML 定义的替代渲染,例如打印版本。
此演示器使用简化的元模型,仅包含参与者之间的消息和参与者执行的动作。
(文章正在重新设计 - CW)
以下是一个在 3 层架构中交互的示例描述:(非常需要重写)
<SequenceDiagram id="3tier">
<name>3-tier architecture</name>
<description>An overview of the 3-tier Architecture</description>
<cast>
<actor>
<name>user</name>
<label>The User</label>
<color>pink</color>
<location>client</location>
<description>The user of the site</description>
</actor>
<actor>
<name>browser</name>
<label>Presentation Layer</label>
<color>lightgreen</color>
<location>client</location>
<description>A browser such as Firefox, Opera or Internet Explorer</description>
</actor>
<actor>
<name>server</name>
<label>Application Layer</label>
<color>lightblue</color>
<location>server</location>
<description>Scripts in languages such as PHP or Java invoked via a web server</description>
</actor>
<actor>
<name>database</name>
<label>Persistance Layer</label>
<color>grey</color>
<location>server</location>
<description>A database server such as Oracle or MySQL</description>
</actor>
</cast>
<communication>
<connection>
<actor>user</actor>
<actor>browser</actor>
<method/>
<prep>on</prep>
</connection>
<connection>
<actor>browser</actor>
<actor>server</actor>
<method>HTTP</method>
<prep>to</prep>
</connection>
<connection>
<actor>server</actor>
<actor>database</actor>
<method>SQL</method>
<prep>to</prep>
</connection>
</communication>
<trace>
<message>
<from>user</from>
<to>browser</to>
<action>click</action>
<object>link</object>
</message>
<message>
<from>browser</from>
<to>server</to>
<action>request</action>
<object>URL</object>
<url>http://www.cems.uwe.ac.uk/~cjwallac/apps/poll2/tally.php?pollid=2</url>
</message>
<do>
<at>server</at>
<action>decode input</action>
<object/>
</do>
<do>
<at>server</at>
<action>create SQL request</action>
<object/>
</do>
<message>
<from>server</from>
<to>database</to>
<action>request</action>
<object>SQL statement</object>
</message>
<message>
<from>database</from>
<to>server</to>
<action>respond</action>
<object>tables</object>
</message>
<do>
<at>server</at>
<action>create page with data in table</action>
<object/>
</do>
<message>
<from>server</from>
<to>browser</to>
<action>respond</action>
<object>HTML page</object>
</message>
<message>
<from>user</from>
<to>browser</to>
<action>read</action>
<object>page</object>
</message>
</trace>
</SequenceDiagram>
'displayDiagram' 脚本将此模型渲染为 XHTML 表格
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
declare variable $homesym :=' || ';
declare variable $leftsym := ' >> ';
declare variable $rightsym := ' << ';
declare function local:makeText($event){
concat($event/action,' ',string-join($event/object,' + '))
};
let $id:= request:get-parameter('id','')
let $sd :=//SequenceDiagram[@id=$id]
let $trace := $sd/trace
let $actors := $sd/cast/actor
let $nactors := count($sd/cast/actor)
let $width := 100 div $nactors
return
<html>
<head><title>Sequence Diagram {string($sd/@id)}</title>
</head>
<body>
<h1>{string($sd/name)} </h1>
<div class="description">
{$sd/description/node() }
</div>
<table border='1'>
<tr>
{for $a in $actors
return
<th width='{$width}%' bgcolor='{$a/color}'>{string($a/label)}</th>
}
</tr>
{ if ($actors/description)
then
<tr>
{for $a in $actors
return <th width='{$width}%' bgcolor='{$a/color}'>{string($a/description)} </th>
}
</tr>
else ()
}
{for $event in $trace/*
return
<tr>
{if (name($event)='do')
then
let $p := index-of($actors/name,$event/at )
let $text:= local:makeText($event)
return
( for $i in (1 to $p - 1) return <td/>,
<td align='center' bgcolor='{$actors[name=$event/at]/color}'>
{
if ($event/url)
then <a href='{$event/url}' target='demo'>{$text}</a>
else $text
}
</td>,
for $i in ($p + 1to $nactors)
return <td/>
)
else if (name($event)='message')
then
let $pfrom := index-of($actors/name,$event/from )
let $pto := index-of($actors/name,$event/to)
let $pfirst := min (($pfrom,$pto))
let $plast := max(($pfrom,$pto))
let $ltor := $pfrom = $pfirst
let $text:= local:makeText($event)
let $connection := $sd//connection[actor = $event/from and actor= $event/to]
let $text := if ($ltor)
then concat($connection/method,$leftsym,$text,$leftsym)
else concat($rightsym,$text,$rightsym, $connection/method)
return
(
for $i in (1 to $pfirst - 1)
return <td/>,
<td align='center' colspan='{$plast - $pfirst + 1 }' bgcolor ='{$actors[name=$event/from]/color}' >
{$text}
{ if ($event/url)
then <a href='{$event/url}' target='demo'>Link </a>
else ()
}
</td>,
for $i in ($plast + 1 to $nactors)
return <td/>
)
else ()
}
</tr>
}
</table>
</body>
</html>
- 一个 GoogleEarth 应用程序
与显示完整的交互不同,图表可以通过仅显示前 n 步以及最后一步的解释文本来简单地进行动画处理。添加一些控件可以让用户在序列中向前和向后迈进。
3层 GoogleEarth 用于计算下一步的函数
declare function local:next-step($step,$action, $max) {
if ($action = "start")
then 0
else if ($action = "back")
then max (($step -1,0))
else if ($action = "forward")
then min(($max,$step+1))
else if ($action="end")
then $max
else $step
};
并调用该函数
let $step := local:next-step(
number(request:request-parameter("step",0)),
request:request-parameter("action", "start"),
count($trace/*))
提供控件并维护交互状态的表单
<h2>
<form>
<input type="hidden" name="id" value="{$id}"/>
<input type="hidden" name="step" value="{$step}"/>
<input type="submit" name="action" value="start"/>
<input type="submit" name="action" value="back"/>
<input type="submit" name="action" value="forward"/>
<input type="submit" name="action" value="end"/>
</form>
</h2>
将显示的事件限制为指定数量的步骤
for $event in $trace/*[position()<=$step]
并显示最后一步的解释
<div class="description">
{if ($step=0)
then $sd/description/node()
else $trace/*[position()=$step]/description/node()
}
</div>
将整个图表存储在 XML 中的优势之一是,图表可以在打印时以不同的方式显示,以便可以将每个步骤及其描述一起显示。