<!-- 
rdfToDB.xsl - XSLT to transform RDF to database API calls.
description and revision history at http://www.w3.org/2002/03/11-RDF-XSL/
$Id: rdfToDB.xsl,v 1.8 2003/12/23 07:22:11 eric Exp $
-->
<xsl:transform version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

  <!-- re-use Evan Lenz's xml-to-string from http://www.xmlportfolio.com/xml-to-string -->
  <xsl:import href="xml-to-string.xsl"/>
  <!-- overloaded global parameters -->
  <xsl:param name="attribute-delimiter" select="'\&quot;'"/>
  <!-- overloaded templates from xml-to-string -->
  <xsl:template match="/" name="xml-to-string-root-rule">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template name="escape-markup-characters">
    <xsl:param name="text"/>
    <xsl:variable name="ampEscaped">
      <xsl:call-template name="replace-string">
        <xsl:with-param name="text" select="$text"/>
        <xsl:with-param name="replace" select="'&amp;'"/>
        <xsl:with-param name="with" select="'&amp;amp;'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="ltEscaped">
      <xsl:call-template name="replace-string">
        <xsl:with-param name="text" select="$ampEscaped"/>
        <xsl:with-param name="replace" select="'&lt;'"/>
        <xsl:with-param name="with" select="'&amp;lt;'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="cDataClose">
      <xsl:call-template name="replace-string">
	<xsl:with-param name="text" select="$ltEscaped"/>
	<xsl:with-param name="replace" select="']]>'"/>
	<xsl:with-param name="with" select="']]&amp;gt;'"/>
      </xsl:call-template>
    </xsl:variable>

    <!-- overloaded to add N-Triples string encoding:
         http://www.w3.org/2001/sw/RDFCore/ntriples/#sec-string1 -->
    <xsl:variable name="backslash">
      <xsl:call-template name="replace-string">
	<xsl:with-param name="text" select="$cDataClose"/>
	<xsl:with-param name="replace" select="'\'"/>
	<xsl:with-param name="with" select="'\\'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="quote">
      <xsl:call-template name="replace-string">
	<xsl:with-param name="text" select="$backslash"/>
	<xsl:with-param name="replace" select="'&#x22;'"/>
	<xsl:with-param name="with" select="'\&#x22;'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="linefeed">
      <xsl:call-template name="replace-string">
	<xsl:with-param name="text" select="$quote"/>
	<xsl:with-param name="replace" select="'&#xA;'"/>
	<xsl:with-param name="with" select="'\n'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="return">
      <xsl:call-template name="replace-string">
	<xsl:with-param name="text" select="$linefeed"/>
	<xsl:with-param name="replace" select="'&#xD;'"/>
	<xsl:with-param name="with" select="'\r'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:call-template name="replace-string">
      <xsl:with-param name="text" select="$return"/>
      <xsl:with-param name="replace" select="'&#x9;'"/>
      <xsl:with-param name="with" select="'\t'"/>
    </xsl:call-template>
  </xsl:template>

  <!-- end xml-to-string -->

  <xsl:output method="text"/>

  <xsl:param name="baseURI"/>


  <!-- apply transformations to all RDF declarations in the document -->
  <xsl:template match="/r:RDF">
    <!-- expect a typedNode with no arcs into it -->
    <xsl:for-each select="./*">
      <xsl:call-template name="typedNode_0">
        <xsl:with-param name="predicate" select="'NULL'"/>
        <xsl:with-param name="subject" select="'NULL'"/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>


  <!-- typedNode - a typed node that is the implied object of arcs  -->
  <xsl:template name="typedNode_0">
    <xsl:param name="predicate"/>
    <xsl:param name="subject"/>

    <!-- look for the name of the typedNode -->
    <xsl:choose>
      <!-- rdf:about -->
      <xsl:when test="@r:about">
	<xsl:call-template name="typedNode_1">
	  <xsl:with-param name="predicate" select="$predicate"/>
	  <xsl:with-param name="subject" select="$subject"/>
	  <xsl:with-param name="object" select="concat('&lt;', @r:about, '&gt;')"/>
	</xsl:call-template>
      </xsl:when>

      <!-- rdf:ID -->
      <xsl:when test="@r:ID">
	<xsl:call-template name="typedNode_1">
	  <xsl:with-param name="predicate" select="$predicate"/>
	  <xsl:with-param name="subject" select="$subject"/>
	  <xsl:with-param name="object" select="concat('&lt;', $baseURI, '#', @r:ID, '&gt;')"/>
	</xsl:call-template>
      </xsl:when>

      <!-- rdf:nodeId -->
      <xsl:when test="@r:nodeId">
	<xsl:call-template name="typedNode_1">
	  <xsl:with-param name="predicate" select="$predicate"/>
	  <xsl:with-param name="subject" select="$subject"/>
	  <xsl:with-param name="object" select="concat('_:n', @r:nodeId)"/>
	</xsl:call-template>
      </xsl:when>

      <!-- bnode -->
      <xsl:otherwise>
	<xsl:call-template name="typedNode_1">
	  <xsl:with-param name="predicate" select="$predicate"/>
	  <xsl:with-param name="subject" select="$subject"/>
	  <xsl:with-param name="object" select="concat('_:g', generate-id(.))"/>
	</xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- typedNode_1 - look for the type of the node -->
  <xsl:template name="typedNode_1">
    <xsl:param name="predicate"/>
    <xsl:param name="subject"/>
    <xsl:param name="object"/>

    <!-- test type and maybe at type triple -->
    <xsl:if test="not(self::r:Description)">
      <xsl:call-template name="addTriple">
        <xsl:with-param name="predicate" select="concat('&lt;', document('')/*/namespace::r, 'type', '&gt;')"/>
        <xsl:with-param name="subject" select="$object"/>
        <xsl:with-param name="object" select="concat('&lt;', namespace-uri(), local-name(), '&gt;')"/>
      </xsl:call-template>
    </xsl:if>

    <!-- test predicate and maybe add incoming arc -->
    <xsl:if test="$predicate != 'NULL'">
      <xsl:call-template name="addTriple">
        <xsl:with-param name="predicate" select="$predicate"/>
        <xsl:with-param name="subject" select="$subject"/>
        <xsl:with-param name="object" select="$object"/>
      </xsl:call-template>
    </xsl:if>

    <!-- handle propertyAttrs -->
    <xsl:for-each select="./@*">
      <xsl:if test="not((namespace-uri()='') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='RDF') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='ID') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='about') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='parseType') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='resource') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='nodeID') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='datatype') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='li') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='Description') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='aboutEach') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='aboutEachPrefix') or
                        (namespace-uri()=document('')/*/namespace::r and local-name()='bagID'))">
        <xsl:call-template name="addTriple">
          <xsl:with-param name="predicate" select="concat('&lt;', namespace-uri(), local-name(), '&gt;')"/>
          <xsl:with-param name="subject" select="$object"/>
          <xsl:with-param name="object" select="concat('&quot;', string(.), '&quot;')"/>
        </xsl:call-template>
      </xsl:if>
    </xsl:for-each>

    <!-- handle nested propertyElts -->
    <xsl:for-each select="./*">
      <xsl:call-template name="propertyElt_0">
	<xsl:with-param name="subject" select="$object"/>
      </xsl:call-template>
    </xsl:for-each>

  </xsl:template>


  <!-- propertyElt - the arc name identifier element -->
  <xsl:template name="propertyElt_0">
    <xsl:param name="subject"/>
    <xsl:choose>

      <!-- parseType="Resource" implies an arc to a newly generated object
      and the nested element is a propertyElt -->
      <xsl:when test="@parseType = 'Resource'">
	<xsl:call-template name="addTriple">
	  <xsl:with-param name="predicate" select="concat('&lt;', namespace-uri(), local-name(), '&gt;')"/>
	  <xsl:with-param name="subject" select="$subject"/>
	  <xsl:with-param name="object" select="concat('_:g', generate-id(.))"/>
	</xsl:call-template>
	<xsl:call-template name="nestedPropertyElt_0">
	  <xsl:with-param name="subject" select="concat('_:g', generate-id(.))"/>
	</xsl:call-template>
      </xsl:when>

      <!-- parseType="Literal" -->
      <xsl:when test="@parseType = 'Literal'">
	<xsl:call-template name="addLiteralTriple">
	  <xsl:with-param name="predicate" select="concat('&lt;', namespace-uri(), local-name(), '&gt;')"/>
	  <xsl:with-param name="subject" select="$subject"/>
        </xsl:call-template>
      </xsl:when>

      <!-- parseType="Collection" implies an arc to a newly generated object
      and each nested element is a typedNode -->
      <xsl:when test="@parseType = 'Collection'">
	<xsl:call-template name="addTriple">
	  <xsl:with-param name="predicate" select="concat('&lt;', namespace-uri(), local-name(), '&gt;')"/>
	  <xsl:with-param name="subject" select="$subject"/>
	  <xsl:with-param name="object" select="concat('_:g', generate-id(.))"/>
	</xsl:call-template>
	<xsl:call-template name="collection_r">
	  <xsl:with-param name="subject" select="concat('_:g', generate-id(.))"/>
	  <xsl:with-param name="index" select="1"/>
	</xsl:call-template>
      </xsl:when>

      <!-- default interpretation - expected a nested typedNode -->
      <xsl:otherwise>
	<xsl:call-template name="nestedTypedNode_0">
	  <xsl:with-param name="predicate" select="concat('&lt;', namespace-uri(), local-name(), '&gt;')"/>
	  <xsl:with-param name="subject" select="$subject"/>
	</xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- nestedTypedNode - call typedNode with the sole nested element -->
  <xsl:template name="nestedTypedNode_0">
    <xsl:param name="predicate"/>
    <xsl:param name="subject"/>
    <xsl:for-each select="./*">
      <xsl:call-template name="typedNode_0">
        <xsl:with-param name="predicate" select="$predicate"/>
        <xsl:with-param name="subject" select="$subject"/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>


  <!-- nestedPropertyElt - call propertyElt with the sole nested element -->
  <xsl:template name="nestedPropertyElt_0">
    <xsl:param name="subject"/>
    <xsl:for-each select="./*">
      <xsl:call-template name="propertyElt_0">
        <xsl:with-param name="subject" select="$subject"/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>


  <!-- collect - recursive function to gather elements in a parseType="Collection" -->
  <xsl:template name="collection_r">
    <xsl:param name="subject"/>
    <xsl:param name="index"/>

    <!-- first -->
    <xsl:for-each select="./*[$index]"> <!-- for-each on only one element -->
      <xsl:call-template name="typedNode_0">
        <xsl:with-param name="predicate" select="concat('&lt;', document('')/*/namespace::r, 'first', '&gt;')"/>
        <xsl:with-param name="subject" select="$subject"/>
      </xsl:call-template>
    </xsl:for-each>

    <!-- rest -->
    <xsl:choose>
      <!-- either a typedNode and another collection -->
      <xsl:when test="./*[$index+1]">
        <xsl:call-template name="addTriple">
          <xsl:with-param name="predicate" select="concat('&lt;', document('')/*/namespace::r, 'rest', '&gt;')"/>
          <xsl:with-param name="subject" select="$subject"/>
          <xsl:with-param name="object" select="concat('_:g', generate-id(./*[$index]))"/>
        </xsl:call-template>

        <xsl:call-template name="collection_r">
          <xsl:with-param name="subject" select="concat('_:g', generate-id(./*[$index]))"/>
          <xsl:with-param name="index" select="$index+1"/>
        </xsl:call-template>
      </xsl:when>

      <!-- or a nill signfying the end of the list -->
      <xsl:otherwise>
        <xsl:call-template name="addTriple">
          <xsl:with-param name="predicate" select="concat('&lt;', document('')/*/namespace::r, 'rest', '&gt;')"/>
          <xsl:with-param name="subject" select="concat('_:', $subject)"/>
          <xsl:with-param name="object" select="concat('&lt;', document('')/*/namespace::r, 'nil', '&gt;')"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- generate a triple and add it to knowledge base -->
  <xsl:template name="addTriple">
    <xsl:param name="predicate"/>
    <xsl:param name="subject"/>
    <xsl:param name="object"/>

    <xsl:value-of select="$predicate"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="$subject"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="$object"/>
    <xsl:text> .&#xA;</xsl:text>
  </xsl:template>


  <!-- addLiteralTriple - encode nested elements and scoop out namespace -->
  <xsl:template name="addLiteralTriple">
    <xsl:param name="predicate"/>
    <xsl:param name="subject"/>
    <xsl:value-of select="$predicate"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="$subject"/>
    <xsl:text> literal("</xsl:text>
    <xsl:for-each select="./*">
      <xsl:call-template name="xml-to-string"/>
    </xsl:for-each>
    <xsl:text>", [</xsl:text>
    <xsl:for-each select="./namespace::*">
      <xsl:text>{"</xsl:text>
      <xsl:value-of select="name()"/>
      <xsl:text>", "</xsl:text>
      <xsl:value-of select="."/>
      <xsl:text>"}, </xsl:text>
    </xsl:for-each>
    <xsl:text>] .&#xA;</xsl:text>
  </xsl:template>

</xsl:transform>