跳转到内容

XQuery/序列图

来自维基教科书,开放的书籍,开放的世界

即使使用绘图工具,序列图也很难绘制。当序列发生变化时,它们更难编辑。一种替代方法是定义一个 XML 词汇表来定义消息排序,并使用 XQuery 将此描述渲染为 XHTML。这种文本方法还允许在每个步骤中显示解释,并生成序列 XML 定义的替代渲染,例如打印版本。

此演示器使用简化的元模型,仅包含参与者之间的消息和参与者执行的动作。

(文章正在重新设计 - CW)

3层架构

[编辑 | 编辑源代码]

以下是一个在 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>

显示

更多示例图表

[编辑 | 编辑源代码]
  1. 一个 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 中的优势之一是,图表可以在打印时以不同的方式显示,以便可以将每个步骤及其描述一起显示。

完全展开的描述

华夏公益教科书