This commit is contained in:
Andy Bunce 2013-01-20 23:37:18 +00:00
parent 3aa4cb7757
commit 63c8f5d0a9
10 changed files with 147 additions and 105 deletions

18
src/graphxq/dotml.xqm Normal file
View File

@ -0,0 +1,18 @@
(:~
: dotml module
: @see http://www.martin-loetzsch.de/DOTML/
:)
module namespace dotml="http://www.martin-loetzsch.de/DOTML";
declare default function namespace 'http://www.martin-loetzsch.de/DOTML';
import module namespace xslt="http://basex.org/modules/xslt";
(:~
: @return graphviz dot string
:)
declare function generate($dotml) as xs:string
{
xslt:transform($dotml, fn:resolve-uri( "dotml/dotml2dot.xsl"))
};

View File

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<!-- <!--
File dotml2dot.xsl File dotml2dot.xsl
Copyright 2002 - 2006 Martin Loetzsch Copyright 2002 - 2006 Martin Loetzsch
Translates dotml documents into the native dot syntax. Translates dotml documents into the native dot syntax.
--> -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:output method="text"/>
<xsl:variable xml:space="preserve" name="graph-attributes">bgcolor fontcolor fontname fontsize label margin nodesep rankdir ranksep ratio size</xsl:variable> <xsl:variable xml:space="preserve" name="graph-attributes">bgcolor fontcolor fontname fontsize label margin nodesep rankdir ranksep ratio size</xsl:variable>
<xsl:variable xml:space="preserve" name="cluster-attributes">bgcolor color fillcolor fontcolor fontname fontsize label labeljust labelloc style</xsl:variable> <xsl:variable xml:space="preserve" name="cluster-attributes">bgcolor color fillcolor fontcolor fontname fontsize label labeljust labelloc style</xsl:variable>
<xsl:variable xml:space="preserve" name="node-attributes">color fillcolor fixedsize fontcolor fontname fontsize height shape style URL width</xsl:variable> <xsl:variable xml:space="preserve" name="node-attributes">color fillcolor fixedsize fontcolor fontname fontsize height shape style URL width</xsl:variable>
@ -16,12 +15,11 @@ Translates dotml documents into the native dot syntax.
<xsl:apply-templates/> <xsl:apply-templates/>
</xsl:template> </xsl:template>
<xsl:template match="text()"/> <xsl:template match="text()"/>
<xsl:template match="dotml:graph">digraph g {compound="true";<xsl:call-template name="copy-attributes"> <xsl:template match="dotml:graph"><dummy>digraph g {compound="true";<xsl:call-template name="copy-attributes">
<xsl:with-param name="separator" select="';'"/> <xsl:with-param name="separator" select="';'"/>
<xsl:with-param name="attributes" select="$graph-attributes"/> <xsl:with-param name="attributes" select="$graph-attributes"/>
</xsl:call-template> </xsl:call-template>
<xsl:apply-templates/>} <xsl:apply-templates/>}</dummy>
&lt;dot-filename&gt;<xsl:value-of select="@file-name"/>&lt;/dot-filename&gt;
</xsl:template> </xsl:template>
<xsl:template match="dotml:sub-graph">subgraph sub_graph_<xsl:value-of select="count(preceding::dotml:sub-graph)"/>{rank="<xsl:value-of select="@rank"/>";<xsl:apply-templates/>}</xsl:template> <xsl:template match="dotml:sub-graph">subgraph sub_graph_<xsl:value-of select="count(preceding::dotml:sub-graph)"/>{rank="<xsl:value-of select="@rank"/>";<xsl:apply-templates/>}</xsl:template>
<xsl:template match="dotml:cluster">subgraph cluster_<xsl:value-of select="@id"/>{<xsl:call-template name="copy-attributes"> <xsl:template match="dotml:cluster">subgraph cluster_<xsl:value-of select="@id"/>{<xsl:call-template name="copy-attributes">

View File

@ -38,7 +38,8 @@ declare function dot( $dot as xs:string*, $params as xs:string*) as node()*{
else $gr:empty else $gr:empty
}; };
declare %private function dot1( $dot as xs:string) as node(){ declare %private function dot1( $dot as xs:string) as element(svg:svg)
{
let $fname:=$gr:tmpdir || random:uuid() let $fname:=$gr:tmpdir || random:uuid()
let $junk:=file:write-text($fname,$dot) let $junk:=file:write-text($fname,$dot)
let $r:=proc:execute($gr:dotpath , ("-Tsvg",$fname)) let $r:=proc:execute($gr:dotpath , ("-Tsvg",$fname))
@ -77,6 +78,7 @@ declare %private function dot1( $dot as xs:string) as node(){
</svg> </svg>
}; };
(:~ (:~
:Layout one ore more graphs given in the GXL language and render them as SVG. :Layout one ore more graphs given in the GXL language and render them as SVG.
: gxl2dot Test.gxl > Test.dot : gxl2dot Test.gxl > Test.dot

View File

@ -1,5 +1,5 @@
(:~ (:~
: restxq interface for graphviz : RESTXQ interface for graphviz
: @author andy bunce : @author andy bunce
: @since sept 2012 : @since sept 2012
:) :)
@ -8,13 +8,19 @@ module namespace grxq = 'apb.graphviz.web';
declare default function namespace 'apb.graphviz.web'; declare default function namespace 'apb.graphviz.web';
import module namespace gr = 'apb.graphviz' at "graphviz.xqm"; import module namespace gr = 'apb.graphviz' at "graphviz.xqm";
import module namespace dotml = 'http://www.martin-loetzsch.de/DOTML' at "dotml.xqm";
import module namespace dotui = 'apb.graphxq.dotui' at "dotui.xqm"; import module namespace dotui = 'apb.graphxq.dotui' at "dotui.xqm";
import module namespace txq = 'apb.txq' at "lib/txq.xqm"; import module namespace txq = 'apb.txq' at "lib/txq.xqm";
import module namespace request = "http://exquery.org/ns/request"; import module namespace request = "http://exquery.org/ns/request";
declare namespace svg= "http://www.w3.org/2000/svg";
declare namespace rest = 'http://exquery.org/ns/restxq'; declare namespace rest = 'http://exquery.org/ns/restxq';
declare variable $grxq:layout:=fn:resolve-uri("views/layout.xml"); declare variable $grxq:layout:=fn:resolve-uri("views/layout.xml");
(:~
: Home page for app
:)
declare declare
%rest:GET %rest:path("graphxq") %rest:GET %rest:path("graphxq")
%output:method("html") %output:version("5.0") %output:method("html") %output:version("5.0")
@ -23,14 +29,14 @@ declare
function graphxq($dot,$url) { function graphxq($dot,$url) {
let $edot:=if($url) then "" else fn:encode-for-uri($dot) let $edot:=if($url) then "" else fn:encode-for-uri($dot)
let $dot2:=getdot($dot,$url) let $dot2:=getdot($dot,$url)
let $svg:=get-svg($dot) let $svg:=dot2svg($dot)
let $map:=map{"dot":=$dot,"url":=$url,"svg":=$svg,"edot":=$edot} let $map:=map{"dot":=$dot,"url":=$url,"svg":=$svg,"edot":=$edot}
let $page:=render("views/page1.xml",$map) let $page:=render("views/page1.xml",$map)
return $page return $page
}; };
(:~ (:~
: return svg for dot, with download option : GET or POST return svg for dot, with download option
:) :)
declare declare
%rest:path("graphxq/svg") %rest:path("graphxq/svg")
@ -39,18 +45,18 @@ declare
%rest:form-param("dl","{$dl}") %rest:form-param("dl","{$dl}")
%output:media-type("image/svg+xml") %output:media-type("image/svg+xml")
function graphxq-svg($dot,$url,$dl) { function graphxq-svg($dot,$url,$dl) {
let $dot2:=getdot($dot,$url) let $dot2:=getdot($dot,$url)
let $svg:=get-svg($dot2) let $svg:=dot2svg($dot2)
let $resp:=<rest:response> let $resp:=<rest:response>
<http:response> <http:response>
<http:header name="Access-Control-Allow-Origin" value="*"/> <http:header name="Access-Control-Allow-Origin" value="*"/>
{if($dl) {if($dl)
then <http:header name="Content-Disposition" value='attachment;filename="graphxq.svg"'/> then <http:header name="Content-Disposition" value='attachment;filename="graphxq.svg"'/>
else ()} else ()}
</http:response> </http:response>
</rest:response> </rest:response>
return ($resp,$svg) return ($resp,$svg)
}; };
(:~ (:~
@ -64,25 +70,34 @@ declare
function dotform($src){ function dotform($src){
let $dot:= getdot("digraph {{a -> b}}",$src) let $dot:= getdot("digraph {{a -> b}}",$src)
let $svgwidget:=fn:doc("views/widget.svg") let $svgwidget:=fn:doc("views/widget.svg")
let $map:=map{"list-shapes":=dotui:shapes(""), let $map:=map{"list-shapes":=dotui:shapes(""),
"list-colors":=dotui:colors(""), "list-colors":=dotui:colors(""),
"svgwidget":=$svgwidget, "svgwidget":=$svgwidget,
"dot":=$dot} "dot":=$dot}
return render("views/dotform.xml",$map) return render("views/dotform.xml",$map)
}; };
declare declare
%rest:GET %rest:path("graphxq/dotml") %rest:GET %rest:path("graphxq/dotml")
%output:method("html") %output:version("5.0") %output:method("html") %output:version("5.0")
function dotmlform(){ function dotmlform(){
render("views/dotmlform.xml",map{}) render("views/dotmlform.xml",map{})
}; };
(:~ static about page :)
declare declare
%rest:GET %rest:path("graphxq/about") %rest:GET %rest:path("graphxq/about")
%output:method("html") %output:version("5.0") %output:method("html") %output:version("5.0")
function about(){ function about(){
render("views/about.xml",map{}) render("views/about.xml",map{})
};
(:~ static api page :)
declare
%rest:GET %rest:path("graphxq/api")
%output:method("html") %output:version("5.0")
function api(){
render("views/api.xml",map{})
}; };
declare declare
@ -93,44 +108,72 @@ function search($q ) {
let $map:=map{"q":=$q} let $map:=map{"q":=$q}
return render("views/search.xml",$map) return render("views/search.xml",$map)
}; };
declare declare
%rest:GET %rest:path("graphxq/library") %rest:GET %rest:path("graphxq/library")
%output:method("html") %output:version("5.0") %output:method("html") %output:version("5.0")
function library( ) { function library( ) {
let $map:=map{ } let $map:=map{ }
return render("views/library.xml",$map) return render("views/library.xml",$map)
}; };
(:~
: @return svg from dotml
:)
declare
%rest:POST %rest:path("graphxq/api/dotml")
%rest:form-param("dotml","{$dotml}")
function api-dotml($dotml ) as node()
{
let $dotml:=fn:parse-xml($dotml)
let $x:=dotml:generate($dotml)
(: let $svg:=dot2svg($x) :)
return $x
};
(:~ use dot or url :) (:~ if url is defined then treat as url and fetch else use dot :)
declare %private function getdot($dot,$url) as xs:string{ declare %private function getdot($dot as xs:string,$url) as xs:string{
if($url) then if($url) then
try{fn:unparsed-text(fn:resolve-uri($url))} catch * { "digraph {{ failed to load remote }}" } try{fn:unparsed-text(fn:resolve-uri($url))} catch * { "digraph {{ failed to load remote }}" }
else else
$dot $dot
}; };
(:~ post process svg :) (:~ if url is defined then treat as url and fetch else use dotml :)
declare %private function get-svg($dot as xs:string) as node(){ declare %private function getdotml($dotml as xs:string,$url) as xs:string{
if($url) then
try{fn:unparsed-text(fn:resolve-uri($url))} catch * { "digraph {{ failed to load remote }}" }
else
$dotml
};
(:~ Generate svg from dot :)
declare %private function dot2svg($dot as xs:string) as node(){
let $svgx:=gr:dot($dot,()) let $svgx:=gr:dot($dot,())
return gr:autosize($svgx) return gr:autosize($svgx)
}; };
declare function render($template,$locals){ (:~
: Render html page
: @param template path to page template
: @params locals map of page variables
:)
declare function render($template as xs:string,$locals){
let $sidebar:=<div> let $sidebar:=<div>
<a href="/graphxq/viewbox/viewBox.svg">viewbox work</a> <a href="/graphxq/viewbox/viewBox.svg">viewbox work</a>
<ul> <ul>
<div>Samples:</div> <div>Samples:</div>
<li> <a href="dot?src=samples/dot/process.gv">process</a></li> <li> <a href="dot?src=samples/dot/process.gv">process</a></li>
<li><a href="/restxq/graphxq/dot?src=samples/dot/unix.gv">unix</a></li> <li><a href="dot?src=samples/dot/unix.gv">unix</a></li>
<li> <a href="/restxq/graphxq/dot?src=samples/dot/root.gv">root (slow)</a></li> <li><a href="dot?src=samples/dot/root.gv">root (slow)</a></li>
</ul> <li><a href="dotml?src=samples/dotml/sample1.xml">dotml sample</a></li>
</ul>
</div> </div>
let $default:=map{"sidebar":=$sidebar , let $default:=map{"sidebar":=$sidebar ,
"usermenu":=<div>users</div>, "usermenu":=<div>users</div>,
"title":=request:path(), "title":=request:path(),
"messages":=()} "messages":=()}
let $locals:=map:new(($default,$locals)) let $locals:=map:new(($default,$locals))
return txq:render(fn:resolve-uri($template),$locals,$grxq:layout) return txq:render(fn:resolve-uri($template),$locals,$grxq:layout)
}; };

View File

@ -1,4 +1,4 @@
<graph file-name="graphs/example_xabsl_option1" ranksep="0.3" nodesep="0.2"> <graph xmlns="http://www.martin-loetzsch.de/DOTML" ranksep="0.3" nodesep="0.2">
<cluster id="option" label="option handle-ball-at-left-and-right-border" fontname="Arial" fontcolor="#005A9C" fontsize="11" fillcolor="#F4F4F4" style="filled"> <cluster id="option" label="option handle-ball-at-left-and-right-border" fontname="Arial" fontcolor="#005A9C" fontsize="11" fillcolor="#F4F4F4" style="filled">
<sub-graph rank="same"> <sub-graph rank="same">
<node label="go\nto\nball" fontcolor="#005A9C" fontsize="11" style="filled" fillcolor="#FFFFFF" fontname="Arial" id="state_go_to_ball" shape="Mcircle"/> <node label="go\nto\nball" fontcolor="#005A9C" fontsize="11" style="filled" fillcolor="#FFFFFF" fontname="Arial" id="state_go_to_ball" shape="Mcircle"/>

View File

@ -1,46 +0,0 @@
(:~
: A(nother) templating Engine for XQuery (BaseX 7.5+(or -) specific)
:
: @author andy bunce
: @since sept 2012
:)
module namespace txq = 'apb.txq';
declare default function namespace 'apb.txq';
import module namespace xquery = "http://basex.org/modules/xquery";
(:~
: template function
: @return updated doc from map
:)
declare function render($map as map(*),$layout as xs:string,$file as xs:string)
{
let $content:=render($map,$file)
let $map:=map:new(($map,map{"body":=$content}))
return render($map,$layout)
};
(:~
: template function
: @return updated doc from map
:)
declare function render($layout as xs:string,$map as map(*))
{
let $map:=map:new(($map,map{"partial":=partial(?,?,?,$map,$layout)}))
return xquery:invoke($layout,$map)
};
(:~
: partial template function: evaluate part for each value in sequence
: @return updated doc from map
:)
declare function partial($part as xs:string,$name,$seq,$map,$base)
{
for $s in $seq
let $map:=map:new(($map,map{$name:=$s}))
return render($map,fn:resolve-uri($part,$base))
};

View File

@ -42,7 +42,7 @@
<li class="tweet-btn"><iframe title="Twitter Tweet Button" <li class="tweet-btn"><iframe title="Twitter Tweet Button"
style="width: 106px; height: 20px;" style="width: 106px; height: 20px;"
class="twitter-share-button twitter-count-horizontal" class="twitter-share-button twitter-count-horizontal"
src="http://platform.twitter.com/widgets/tweet_button.html?count=horizontal&amp;id=twitter-widget-0&amp;lang=en&amp;original_referer=https%3A%2F%2Fgithub.com%2Fapb2006%2Fxqwebdoc%2F&amp;size=m&amp;text=xqwebdoc #xquery&amp;url=https%3A%2F%2Fgithub.com%2Fapb2006%2Fxqwebdoc&amp;via=apb1704" src="http://platform.twitter.com/widgets/tweet_button.html?count=horizontal&amp;id=twitter-widget-0&amp;lang=en&amp;original_referer=https%3A%2F%2Fgithub.com%2Fapb2006%2Fgraphxq&amp;size=m&amp;text=graphxq #xquery&amp;url=https%3A%2F%2Fgithub.com%2Fapb2006%2Fxqwebdoc&amp;via=apb1704"
allowtransparency="true" scrolling="no" frameborder="0"></iframe></li> allowtransparency="true" scrolling="no" frameborder="0"></iframe></li>
</ul> </ul>
</div> </div>

View File

@ -0,0 +1,7 @@
<div>
<h1>About GraphXQ API</h1>
<p>
POST or GET <div>restxq/svg?dot=..</div>
</p>
</div>

View File

@ -1,8 +1,17 @@
<div class="row-fluid" style="heigth:20em"> <div class="row-fluid" style="height:20em">
<div class="span5"> <div class="span5">
<form method="post" action="." style="background-color:#EEEEEE;padding:8px;"> <form method="post" action="api/dotml" style="background-color:#EEEEEE;padding:8px;">
<textarea name="dot" rows="2" cols="80"></textarea> <textarea name="dotml" rows="12" cols="80">
&lt;graph file-name=&quot;graphs/decorate&quot;&gt;
&lt;node id=&quot;a&quot;/&gt;
&lt;node id=&quot;b&quot;/&gt;
&lt;node id=&quot;c&quot;/&gt;
&lt;edge from=&quot;a&quot; to=&quot;c&quot; decorate=&quot;false&quot; label=&quot;decorate=&#39;false&#39;&quot;/&gt;
&lt;edge from=&quot;b&quot; to=&quot;c&quot; decorate=&quot;true&quot; label=&quot;decorate=&#39;true&#39;&quot;/&gt;
&lt;/graph&gt;
</textarea>
<button type="submit">Redraw</button> <button type="submit">Redraw</button>
</form > </form >

View File

@ -5,7 +5,7 @@
<base href="/restxq/graphxq/" /> <base href="/restxq/graphxq/" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="xquery documentation" /> <meta name="description" content="graphviz tool" />
<meta name="author" content="andy bunce" /> <meta name="author" content="andy bunce" />
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.2/css/bootstrap.css" rel="stylesheet" <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.2/css/bootstrap.css" rel="stylesheet"
type="text/css" /> type="text/css" />
@ -63,11 +63,22 @@
</li> </li>
</ul> </ul>
</li> </li>
<li class="nav"> <li >
<a href="library">Library</a> <a href="library">Library</a>
</li> </li>
<li class="nav"> <li class="dropdown">
<a href="about">About</a> <a href="#" class="dropdown-toggle" data-toggle="dropdown">
About
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li>
<a href="about"><i class="icon-edit"></i> About</a>
</li>
<li>
<a href="api"><i class="icon-align-center"></i> API</a>
</li>
</ul>
</li> </li>
</ul> </ul>
<form class="pull-right navbar-search" action="search"> <form class="pull-right navbar-search" action="search">