rdf2dot.xsl 12.2 KB
<?xml version='1.0'?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
               version="1.0"
               xmlns:web="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
               xmlns:util="http://www.w3.org/2000/01/rdf-schema#"
               xmlns:g="http://www.w3.org/2001/02pd/gv#"
               >

<xsl:variable name="RCSId"
              select='"$Id: rdf2dot.xsl,v 1.19 2005/11/12 00:18:34 connolly Exp $"'/>

<xsl:param name="Debug" select='0'/>

<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
This transformation groks a limited subset of RDF:
  -- just one level of nesting (no Description/typedNodes
     as values of properties)
  -- properties are sorted by subject, collected
     in a Description element for that subject
  -- rdf:ID is not used; only rdf:about
  -- only absolute URIs are used

Arbitrary RDF can be converted to this form using
          cwm --rdf foo.rdf --bySubject --base=bogus: > foo-limited.rdf

see <a href="http://www.w3.org/2000/10/swap/">Semantic Web Area for Play</a>
for details about cwm.
</pre>

<address>Dan Connolly <br class=""/>
$Id: rdf2dot.xsl,v 1.19 2005/11/12 00:18:34 connolly Exp $</address>

<p>Norman Walsh updated this stylesheet on 16 Jan 2002 so that edges
between nodes in different clusters are generated outside of any
cluster. This prevents nodes from automatically inheriting cluster
semantics. I also switched to keys() as a comment suggested.</p>

</div>

<xsl:output method="text"/>

<xsl:param name="GVns" select='"http://www.w3.org/2001/02pd/gv#"'/>

<xsl:key name="about" match="*" use="@web:about"/>

<xsl:template match="/web:RDF">
  <xsl:text>/* transformed by by </xsl:text>
  <xsl:value-of select='substring($RCSId, 2, string-length($RCSId)-2)'/>
  <xsl:text> */&#xA;</xsl:text>

  <xsl:for-each select="*/g:digraph/@web:resource">
    <xsl:variable name="it" select="key('about', current())"/>

    <xsl:text>digraph </xsl:text>
    <xsl:call-template name="eachGraph">
      <xsl:with-param name="it" select='$it'/>
      <xsl:with-param name="first" select="1"/>
    </xsl:call-template>
  </xsl:for-each>
</xsl:template>

<xsl:template name="eachGraph">
  <xsl:param name="it"/>
  <xsl:param name="cluster"/>
  <xsl:param name="crossGraphLinking" select="0"/>
  <xsl:param name="first" select="0"/>

  <xsl:if test="$crossGraphLinking = 0">
    <xsl:value-of select='concat($cluster, generate-id($it))'/>
    <xsl:text> {&#xA;</xsl:text>

    <!-- graph attributes see Graphviz spec table 3 -->
    <xsl:for-each select='$it/g:center
                          |$it/g:clusterrank
                          |$it/g:color
                          |$it/g:compound
                          |$it/g:concentrate
                          |$it/g:fontcolor
                          |$it/g:fontname
                          |$it/g:fontsize
                          |$it/g:label
                          |$it/g:layerseq
                          |$it/g:margin
                          |$it/g:mclimit
                          |$it/g:nodesep
                          |$it/g:nslimit
                          |$it/g:ordering
                          |$it/g:orientation
                          |$it/g:page
                          |$it/g:rank
                          |$it/g:rankdir
                          |$it/g:ranksep
                          |$it/g:ratio
                          |$it/g:size
                          |$it/g:style
			  '>
      <!--@@ ...others-->
      <xsl:value-of select='local-name()'/>
      <xsl:text>="</xsl:text>
      <xsl:value-of select='.'/> <!-- @@quoting? -->
      <xsl:text>";&#xA;</xsl:text>
    </xsl:for-each>
    <xsl:if test="$first != 0">
      <xsl:call-template name="eachGraph">
        <xsl:with-param name="it" select='$it'/>
        <xsl:with-param name="crossGraphLinking" select="1"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:if>

  <!-- explicit nodes -->
  <xsl:for-each select="$it/g:hasNode/@web:resource">
    <xsl:variable name="nodeURI" select='current()'/>
    <xsl:variable name="nodeElt" select='key("about", $nodeURI)'/>
    <xsl:if test='$nodeElt'>
      <xsl:call-template name="eachNode">
        <xsl:with-param name="graphElt" select='$it'/>
        <xsl:with-param name="nodeElt" select='$nodeElt'/>
        <xsl:with-param name="nodeURI" select='$nodeURI'/>
        <xsl:with-param name="crossGraphLinking" select="$crossGraphLinking"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:for-each>

  <xsl:for-each select="$it/g:subgraph/@web:resource">
    <xsl:variable name="it2" select="key('about', current())"/>
    <xsl:if test="$crossGraphLinking = 0">
      <xsl:text>subgraph </xsl:text>
    </xsl:if>

    <xsl:call-template name="eachGraph">
      <xsl:with-param name="it" select='$it2'/>
      <xsl:with-param name="cluster" select='"cluster"'/>
      <xsl:with-param name="crossGraphLinking" select="$crossGraphLinking"/>
    </xsl:call-template>
  </xsl:for-each>

  <xsl:if test="$crossGraphLinking = 0">
    <xsl:text>}&#xA;</xsl:text>
  </xsl:if>
</xsl:template>

<xsl:template name="eachNode">
  <xsl:param name="graphElt"/>
  <xsl:param name="nodeElt"/>
  <xsl:param name="nodeURI"/>
  <xsl:param name="crossGraphLinking" select="0"/>

  <xsl:if test="$crossGraphLinking = 0">
    <xsl:text>"</xsl:text>
    <xsl:value-of select='$nodeURI'/>
    <xsl:text>" [</xsl:text>

    <!-- node attributes -->
    <xsl:for-each select='$nodeElt/g:label
                          |$nodeElt/g:color
                          |$nodeElt/g:shape
                          |$nodeElt/g:style
                          |$nodeElt/g:fontcolor
                          |$nodeElt/g:fontname
                          |$nodeElt/g:fontsize
                          |$nodeElt/g:height
                          |$nodeElt/g:width
                          |$nodeElt/g:layer
                          |$nodeElt/g:URL
                          |$nodeElt/g:sides
                          |$nodeElt/g:shapefile'>
      <!-- "URL" not in the original file format docs, but seems to be supported; -->
      <!-- cf http://www.graphviz.org/webdot/tut2.html -->
      <xsl:value-of select='local-name()'/>
      <xsl:text>="</xsl:text>
      <xsl:value-of select='.'/> <!-- @@quoting? -->
      <xsl:text>",&#xA;</xsl:text>
    </xsl:for-each>
    <xsl:text>];&#xA;</xsl:text>
  </xsl:if>

  <!-- edges -->
  <xsl:for-each select="$nodeElt/*[@web:resource]"> <!-- iterate over all properties -->
    <!-- compute full name of property -->
    <xsl:variable name="obj" select='./@web:resource'/>
    <xsl:variable name="pred" select='concat(namespace-uri(),  local-name())'/>

    <xsl:if test='$Debug>4'>
    <xsl:message>propertyElt in nodeElt:
      subj: <xsl:value-of select='$nodeURI'/>
      pred: <xsl:value-of select='$pred'/>
    </xsl:message>
    </xsl:if>

    <xsl:choose>
      <xsl:when test='$graphElt/g:hasEdgeProperty/@web:resource=$pred
		and $graphElt/g:hasNode/@web:resource=$obj'>
        <xsl:call-template name="doEdge">
          <xsl:with-param name="nodeURI" select='$nodeURI'/>
          <xsl:with-param name="pred" select='$pred'/>
          <xsl:with-param name="obj" select='$obj'/>
          <xsl:with-param name="edgeElt" select='key("about", $pred)'/>
          <xsl:with-param name="crossGraphLinking" select="$crossGraphLinking"/>
        </xsl:call-template>
      </xsl:when>

      <xsl:when test='/web:RDF/g:EdgeProperty[@web:about=$pred]'>
	<xsl:if test="0">
        <xsl:message>
          <xsl:value-of select='$pred'/> is an EdgeProperty.
          A given property might be used to make edges
          in one graph and not in another; so
          EdgeProperty(p) isn't well-defined those p's.
          It seems that edge-ness is a function of the
          graph and the property; i.e. a relation between
          them.

          So EdgeProperty is deprecated... use hasEdgeProperty.

          @@oops... what about g:style, g:label, etc... should
          those be a function of the property and the graph?
          Or should we have edgeLabel and nodeLabel properties?
          Hmm...
        </xsl:message>
	</xsl:if>

        <xsl:call-template name="doEdge">
          <xsl:with-param name="nodeURI" select='$nodeURI'/>
          <xsl:with-param name="pred" select='$pred'/>
          <xsl:with-param name="obj" select='$obj'/>
          <xsl:with-param name="edgeElt" select='key("about", $pred)'/>
        <xsl:with-param name="crossGraphLinking" select="$crossGraphLinking"/>
        </xsl:call-template>
      </xsl:when>

      <xsl:when test='/web:RDF/*[@web:about=$pred]/web:type
                       [@web:resource=concat($GVns, "EdgeProperty")]'>
	<xsl:if test="0">
        <xsl:message>
          <xsl:value-of select='$pred'/> is an EdgeProperty.

          A given property might be used to make edges
          in one graph and not in another; so
          EdgeProperty(p) isn't well-defined those p's.
          It seems that edge-ness is a function of the
          graph and the property; i.e. a relation between
          them.

          So EdgeProperty is deprecated... use hasEdgeProperty

          @@oops... what about g:style, g:label, etc... should
          those be a function of the property and the graph?
          Or should we have edgeLabel and nodeLabel properties?
          Hmm... maybe
                 my:graph g:nodeType my:Marbles;
                    g:edgeType my:GEdgeProp;
                    g:labelProp my:label;
                    g:styleProp my:styleProp;
        </xsl:message>
	</xsl:if>

        <xsl:call-template name="doEdge">
          <xsl:with-param name="nodeURI" select='$nodeURI'/>
          <xsl:with-param name="pred" select='$pred'/>
          <xsl:with-param name="obj" select='$obj'/>
          <xsl:with-param name="edgeElt" select='key("about", $pred)'/>
          <xsl:with-param name="crossGraphLinking" select="$crossGraphLinking"/>
        </xsl:call-template>

      </xsl:when>

      <xsl:otherwise>
        <!-- nothing -->
      </xsl:otherwise>
    </xsl:choose>

  </xsl:for-each>

</xsl:template>

<xsl:template name="doEdge">
  <xsl:param name="nodeURI"/>
  <xsl:param name="pred"/>
  <xsl:param name="obj"/>
  <xsl:param name="edgeElt"/>
  <xsl:param name="crossGraphLinking" select="0"/>

  <xsl:variable name="fromGraph"
                select="/web:RDF/*[g:hasNode[@web:resource=$nodeURI]]/@web:about"/>
  <xsl:variable name="toGraph"
                select="/web:RDF/*[g:hasNode[@web:resource=$obj]]/@web:about"/>

  <xsl:if test='$Debug>4'>
    <xsl:message>EdgeProperty:
      pred: <xsl:value-of select='$pred'/>
      obj: <xsl:value-of select='$obj'/>
      from: <xsl:value-of select="$fromGraph"/>
      to: <xsl:value-of select="$toGraph"/>
    </xsl:message>
  </xsl:if>

  <xsl:if test="($crossGraphLinking = 0 and $fromGraph = $toGraph)
                or ($crossGraphLinking != 0 and $fromGraph != $toGraph)">
    <xsl:text>"</xsl:text>
    <xsl:value-of select='$nodeURI'/>
    <xsl:text>" -&gt; "</xsl:text>
    <xsl:value-of select='$obj'/>
    <xsl:text>"</xsl:text>

    <xsl:text> [ /* edge attributes */&#xA;</xsl:text>
    <!-- edge attributes all except id -->
    <xsl:for-each select='$edgeElt/g:label
                          |$edgeElt/g:color
                          |$edgeElt/g:constraint
                          |$edgeElt/g:decorate
                          |$edgeElt/g:dir
                          |$edgeElt/g:fontcolor
                          |$edgeElt/g:fontname
                          |$edgeElt/g:fontsize
                          |$edgeElt/g:layer
                          |$edgeElt/g:minlen
                          |$edgeElt/g:style
                          |$edgeElt/g:weight'>
      <!--@@ ...others-->
      <xsl:value-of select='local-name()'/>
      <xsl:text>="</xsl:text>
      <xsl:value-of select='.'/> <!-- @@quoting? -->
      <xsl:text>",&#xA;</xsl:text>
    </xsl:for-each>

    <xsl:for-each select='$edgeElt/*[self::g:lhead or self::g:ltail]'>
      <xsl:variable name="subgraph" select="key('about', @web:resource)"/>
      <xsl:value-of select="local-name()"/>
      <xsl:text>=cluster</xsl:text>
      <xsl:value-of select="generate-id($subgraph)"/>
      <xsl:text>,&#10;</xsl:text>
    </xsl:for-each>

    <xsl:text>];&#xA;</xsl:text>
  </xsl:if>
</xsl:template>

<!-- don't pass text thru -->
<xsl:template match="text()|@*">
</xsl:template>


</xsl:transform>