<?xml version='1.0'?><!-- -*- mode: indented-text;-*- -->

<xsl:transform
	 xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
	 xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
	 xmlns:rdfp='http://www.w3.org/2000/07/hs78/rdf2kif?template='
	 xmlns='http://www.w3.org/2000/07/hs78/KIF#'

	 xmlns:xtj='http://www.jclark.com/xt/java'

	 exclude-result-prefixes='xsl rdf rdfp'>

<div xmlns="http://www.w3.org/1999/xhtml">

<h1>an RDF parser in XSLT</h1>

<p>$Id: rdf2kif.xsl,v 1.6 2000/08/14 08:05:34 connolly Exp $</p>

<p>cf <a href="http://www.w3.org/TR/1999/REC-rdf-syntax-19990222">RDF
spec</a>.</p>

<p>see also: <a href="../../../XML/2000/04rdf-parse">previous work</a></p>

</div>


<!--  <xsl:output method="xml"/> -->
<xsl:output method="xtj:kifOutput"/>

  <xsl:variable name='rdfNS'
		select='"http://www.w3.org/1999/02/22-rdf-syntax-ns#"'/>

  <xsl:variable name='RDFNumeralNS'
		select='"http://www.w3.org/1999/02/22-rdf-syntax-ns#_"'/>

<xsl:variable name='KIFWordNS'
		select='"http://www.w3.org/2000/07/hs78/KIF?word="'/>

<xsl:variable name='KIFNS'
		select='"http://www.w3.org/2000/07/hs78/KIF#"'/>

<!-- @@argh! how do I refer to XML Schema datatypes?  PLEASE can I have a canonical URI, in the appinfo, along with the has-facet stuff? -->
  <xsl:variable name='uriReferenceType'
		select='"http://www.w3.org/1999/XMLSchema#datatype_uriReference"'/>

  <xsl:variable name='stringType'
		select='"http://www.w3.org/1999/XMLSchema#datatype_string"'/>

<xsl:variable name="VarNS" select='"_:"'/> <!-- HACK! but the damage is local. -->


  <xsl:template match='rdf:RDF'>
	<!-- @@issue: dealing with RDF inside other stuff.
		see XML Schema for RDF@@ -->

<!-- [1] RDF -->
      <xsl:for-each select='text()[string-length(normalize-space())&gt;0]'>
        <xsl:call-template name='rdfp:badStuff'>
          <xsl:with-param name='expected' select='"description"'/>
        </xsl:call-template>
      </xsl:for-each>

      <xsl:call-template name='rdfp:description_s'/>
  </xsl:template>

  <xsl:template name='rdfp:description_s'>
    <xsl:param name='parentSubject'/>

    <xsl:param name='parentPredicate'/>

    <!-- do I need a parentID as well? @@-->

    <xsl:for-each select='*'>
<!-- [2] description -->
      <xsl:variable name='node' select='.'/>

      <xsl:choose>
<!-- REVIEW: about vs. rdf:about?
reported Wed, 26 Apr 2000 05:12:05 -0500
http://lists.w3.org/Archives/Public/www-rdf-comments/2000AprJun/0019.html
 -->
        <xsl:when test='(@rdf:ID and @rdf:about) or (@ID and @about)'>

          <xsl:call-template name='rdfp:badElement'>
            <xsl:with-param name='problem' select='"ID and about attribute"'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:when test='@rdf:ID'>
          <xsl:call-template name='rdfp:propertyElt_s'>
            <xsl:with-param name='node' select='$node'/>

            <xsl:with-param name='subject' select='concat("#", @rdf:ID)'/>

            <xsl:with-param name='parentSubject' select='$parentSubject'/>

            <xsl:with-param name='parentPredicate' select='$parentPredicate'/>
          </xsl:call-template>

          <xsl:call-template name='rdfp:propAttr_s'>
            <xsl:with-param name='subject' select='concat("#", @rdf:ID)'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:when test='@ID'>
          <xsl:call-template name='rdfp:propertyElt_s'>
            <xsl:with-param name='node' select='$node'/>

            <xsl:with-param name='subject' select='concat("#", @ID)'/>

            <xsl:with-param name='parentSubject' select='$parentSubject'/>

            <xsl:with-param name='parentPredicate' select='$parentPredicate'/>
          </xsl:call-template>

          <xsl:call-template name='rdfp:propAttr_s'>
            <xsl:with-param name='subject' select='concat("#", @ID)'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:when test='@rdf:about'>
          <xsl:call-template name='rdfp:propertyElt_s'>
            <xsl:with-param name='node' select='$node'/>

            <xsl:with-param name='subject' select='@rdf:about'/>

            <xsl:with-param name='parentSubject' select='$parentSubject'/>

            <xsl:with-param name='parentPredicate' select='$parentPredicate'/>
          </xsl:call-template>

          <xsl:call-template name='rdfp:propAttr_s'>
            <xsl:with-param name='subject' select='@rdf:about'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:when test='@about'>
          <xsl:call-template name='rdfp:propertyElt_s'>
            <xsl:with-param name='node' select='$node'/>

            <xsl:with-param name='subject' select='@about'/>

            <xsl:with-param name='parentSubject' select='$parentSubject'/>

            <xsl:with-param name='parentPredicate' select='$parentPredicate'/>
          </xsl:call-template>

          <xsl:call-template name='rdfp:propAttr_s'>
            <xsl:with-param name='subject' select='@about'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:otherwise>
	  <!-- existential -->
<!-- @@hmm... what subject to use for an anonymous node?TimBL mentioned that RDF syntax for nodes denotes an existentialquantifier... it didn't make sense to me at first, but yesterday(21 apr 2000) I realized that anonymous nodes are like skolemfunctions, and skolem functions are used to represent existentialquantifiers in horn clauses (cf discussion with Boyer in Austin).... which reminds me: the skolem function needs to varyw.r.t. all the universally quantified variables at this point inthe expression. So... @@when we add variables/forall,don't forget to tweak this. We probably need a "free variables"parameter to most of the templates here.Hmm... why should only anonymous nodes get "skolemized"?I wonder if IDentified nodes also represent existentials.I suppose about='..' should be treated as a constant,not an existential.-->

          <xsl:variable name="subjVar" select='generate-id()'/>

	  <!-- HACK! but the damage is local... -->
          <xsl:variable name="subject" select='concat($VarNS,
							 generate-id())'/>
	  <paren>
	    <exists/>
	    <paren>
	      <indvar n="{$subjVar}"/>
            </paren>

            <xsl:call-template name='rdfp:propertyElt_s'>
              <xsl:with-param name='node' select='$node'/>

              <xsl:with-param name='subject' select='$subject'/>

              <xsl:with-param name='parentSubject' select='$parentSubject'/>

              <xsl:with-param name='parentPredicate' select='$parentPredicate'/>
            </xsl:call-template>

            <xsl:call-template name='rdfp:propAttr_s'> <!-- @@ skip these? -->
              <xsl:with-param name='subject' select='$subject'/>
            </xsl:call-template>
	  </paren>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name='rdfp:propertyElt_s'>
    <xsl:param name='subject'/>

<!-- @@expand w.r.t. base? -->
    <xsl:param name='parentSubject'/>

    <xsl:param name='parentPredicate'/>

    <xsl:param name='node'/>

    <xsl:if test='$parentPredicate'>
      <xsl:call-template name='rdfp:statement'>
        <xsl:with-param name='subject' select='$parentSubject'/>

        <xsl:with-param name='predicate' select='$parentPredicate'/>

        <xsl:with-param name='object' select='$subject'/>

        <xsl:with-param name='objectType' select='$uriReferenceType'/>
      </xsl:call-template>
    </xsl:if>

<!-- [17] typedNode -->
    <xsl:if test='$node and (namespace-uri($node) != $rdfNS or local-name($node) != "Description")'>

      <xsl:call-template name='rdfp:statement'>
        <xsl:with-param name='subject' select='$subject'/>

        <xsl:with-param name='predicate' select='concat($rdfNS, "type")'/>

        <xsl:with-param name='object' select='concat(namespace-uri($node), local-name($node))'/>

        <xsl:with-param name='objectType' select='$uriReferenceType'/>
      </xsl:call-template>
    </xsl:if>

    <xsl:for-each select='*'>
<!-- [6] propertyElt -->
      <xsl:variable name='predicate' select='concat(namespace-uri(), local-name())'/>
      <xsl:variable name="stID" select="@rdf:ID"/> <!-- or just ID@@ -->

      <xsl:choose>
<!-- [8] value -->
        <xsl:when test='text()[string-length(normalize-space())&gt;0] and *'>
          <xsl:call-template name='badElement'>
            <xsl:with-param name='problem' select='"text and subelements mixed in property value"'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:when test='text()[string-length(normalize-space())&gt;0]'>
<!-- @@ barf if any attrs except ID -->
          <xsl:call-template name='rdfp:statement'>
<!-- @@parameterize the template to call for each statement? -->
	    <xsl:with-param name="stID" select="$stID"/>

            <xsl:with-param name='subject' select='$subject'/>

            <xsl:with-param name='predicate' select='$predicate'/>

            <xsl:with-param name='object'>
              <xsl:copy-of select='text()'/>
            </xsl:with-param>

            <xsl:with-param name='objectType' select='$stringType'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:when test='*'>
<!-- @@ barf if any attrs except ID -->
          <xsl:call-template name='rdfp:description_s'>
            <xsl:with-param name='parentSubject' select='$subject'/>

            <xsl:with-param name='parentPredicate' select='$predicate'/>
	    <!-- pass $stID as $parentID? -->
          </xsl:call-template>
        </xsl:when>

<!-- @@parseLiteral and parseResource -->
        <xsl:when test='@rdf:resource or @resource'>

          <xsl:for-each select='text()[string-length(normalize-space())&gt;0]|*'>
            <xsl:call-template name='rdfp:badElement'>
              <xsl:with-param name='problem' select='"propertyElt with resource attribute should be empty"'/>
            </xsl:call-template>
          </xsl:for-each>

          <xsl:variable name='resAttr' select='@*[local-name()="resource" and (namespace-uri() = $rdfNS or namespace-uri()="")]'/>

	  <xsl:if test="0">
	    <xsl:message> resattr: [<xsl:value-of select="$resAttr"/>]</xsl:message>
	  </xsl:if>

          <xsl:call-template name='rdfp:statement'>
	    <xsl:with-param name="stID" select="$stID"/>
            <xsl:with-param name='subject' select='$subject'/>

            <xsl:with-param name='predicate' select='$predicate'/>

            <xsl:with-param name='object' select='$resAttr'/>

            <xsl:with-param name='objectType' select='$uriReferenceType'/>
          </xsl:call-template>

<!-- [16] propAttr -->
          <xsl:call-template name='rdfp:propAttr_s'>
            <xsl:with-param name='subject' select='$resAttr'/>
          </xsl:call-template>
        </xsl:when>

        <xsl:otherwise>
<!-- [16] propAttr -->
<!--@@ idAttr, bagIdAttr -->
          <xsl:variable name='genid' select='concat("#,", generate-id())'/>

          <xsl:call-template name='rdfp:propAttr_s'>
            <xsl:with-param name='subject' select='$genid'/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>

    <xsl:for-each select='text()[string-length(normalize-space())&gt;0]'>
      <xsl:call-template name='rdfp:badStuff'>
        <xsl:with-param name='expected' select='"description"'/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name='rdfp:propAttr_s'>
    <xsl:param name='subject'/>

<!-- @@expand w.r.t. base? -->
    <xsl:for-each select='@*[not ((local-name() = "about" or local-name() = "resource" or local-name() = "ID" or local-name() = "bagID" or local-name() = "aboutEach" or local-name() = "aboutEachPrefix") and (namespace-uri() = "" or namespace-uri() = $rdfNS)) ]'>

      <xsl:call-template name='rdfp:statement'>
        <xsl:with-param name='subject' select='$subject'/>

        <xsl:with-param name='predicate' select='concat(namespace-uri(.), local-name(.))'/>

        <xsl:with-param name='object'>
          <xsl:value-of select='.'/>
        </xsl:with-param>

        <xsl:with-param name='objectType' select='$stringType'/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name='rdfp:statement'>
    <xsl:param name="stID"/>

    <xsl:param name='subject'/>

<!-- @@expand w.r.t. base? -->
    <xsl:param name='predicate'/>

    <xsl:param name='object'/>

    <xsl:param name='objectType'/>

    <xsl:if test="$stID"> <!-- reification, at least a little bit -->
      <xsl:call-template name="rdfp:statement">
        <xsl:with-param name="subject" select='concat("#", $stID)'/>
	<xsl:with-param name="predicate" select='concat($rdfNS, "type")'/>
	<xsl:with-param name="object" select='concat($rdfNS, "Statement")'/>
	<xsl:with-param name="objectType" select="$uriReferenceType"/>
      </xsl:call-template>

      <xsl:call-template name="rdfp:statement">
        <xsl:with-param name="subject" select='concat("#", $stID)'/>
	<xsl:with-param name="predicate" select='concat($rdfNS, "subject")'/>
	<xsl:with-param name="object" select='$subject'/>
	<xsl:with-param name="objectType" select="$uriReferenceType"/>
      </xsl:call-template>

      <xsl:call-template name="rdfp:statement">
        <xsl:with-param name="subject" select='concat("#", $stID)'/>
	<xsl:with-param name="predicate" select='concat($rdfNS, "predicate")'/>
	<xsl:with-param name="object" select='$predicate'/>
	<xsl:with-param name="objectType" select="$uriReferenceType"/>
      </xsl:call-template>

      <xsl:call-template name="rdfp:statement">
        <xsl:with-param name="subject" select='concat("#", $stID)'/>
	<xsl:with-param name="predicate" select='concat($rdfNS, "object")'/>
	<xsl:with-param name="object" select='$object'/>
	<xsl:with-param name="objectType" select="$objectType"/>
      </xsl:call-template>
    </xsl:if>

    <xsl:call-template name="assert-kif">
      <xsl:with-param name="subject" select="$subject"/>
      <xsl:with-param name="predicate" select="$predicate"/>
      <xsl:with-param name="object" select="$object"/>
      <xsl:with-param name="objectType" select="$objectType"/>
    </xsl:call-template>
  </xsl:template>


<xsl:template name="assert-kif">
  <xsl:param name='subject'/>
  <xsl:param name='predicate'/>
  <xsl:param name='object'/>
  <xsl:param name='objectType'/>

  <!--@@ resolve URIs to absolute form -->
  <paren>
    <holds/>
    <xsl:choose>
      <!-- (rdf:type i c) => (c i) -->
      <xsl:when test='$predicate = concat($rdfNS, "type")'>
        <xsl:call-template name="kif-term">
	  <xsl:with-param name="predicate" select="$predicate"/>
	  <xsl:with-param name="uri" select="$object"/>
	</xsl:call-template>

        <xsl:call-template name="kif-term">
          <xsl:with-param name="predicate" select="$predicate"/>
          <xsl:with-param name="uri" select="$subject"/>
        </xsl:call-template>

      </xsl:when>

      <xsl:otherwise>
        <!-- didn't bother to indent from here[[[ -->
    <constant n="{$predicate}"/>

    <xsl:call-template name="kif-term">
      <xsl:with-param name="predicate" select="$predicate"/>
      <xsl:with-param name="uri" select="$subject"/>
    </xsl:call-template>

    <xsl:choose>
      <xsl:when test='$objectType = $uriReferenceType'>
        <xsl:call-template name="kif-term">
	  <xsl:with-param name="predicate" select="$predicate"/>
	  <xsl:with-param name="uri" select="$object"/>
	</xsl:call-template>

      </xsl:when>

      <xsl:when test='$objectType = $stringType'>
        <!-- escape ", \ inside strings @@-->
        <string v="{$object}"/>
      </xsl:when>

      <xsl:otherwise>
        <xsl:message>unknown object type: 
        <xsl:value-of select='$objectType'/>
        </xsl:message>
      </xsl:otherwise>
    </xsl:choose>
      <!-- ]]] to here -->

      </xsl:otherwise>
    </xsl:choose>
  </paren>
</xsl:template>

<xsl:template name="kif-term">
  <xsl:param name="predicate"/>
  <xsl:param name="uri"/>

  <xsl:choose>
    <xsl:when test='starts-with($uri, $VarNS)'>
      <xsl:variable name="v"
		    select='substring($uri, string-length($VarNS)+1)'
		    />

      <indvar n='{$v}'/>
    </xsl:when>

    <xsl:otherwise>
      <constant n="{$uri}"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


  <xsl:template name='rdfp:badStuff'>
    <xsl:param name='expected'/>

    <xsl:message>expected 
    <xsl:value-of select='$expected'/>

    but got: [[
    <xsl:copy-of select='.'/>

    ]]</xsl:message>
  </xsl:template>

  <xsl:template name='rdfp:badElement'>
    <xsl:param name='problem'/>

    <xsl:message>problem in &lt;<xsl:value-of select='name(.)'/>&gt;: 
    <xsl:value-of select='$problem'/>
    </xsl:message>
  </xsl:template>

</xsl:transform>
