<xsl:stylesheet 
    xmlns:xsl  ="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:h    ="http://www.w3.org/1999/xhtml"
    xmlns:s    ="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:kif    ="http://www.w3.org/2000/07/hs78/KIF#"
    xmlns:inf  ="http://www.w3.org/2000/04shoe-swell/inference#"
    xmlns:uri  ="http://www.w3.org/2000/07/uri43/uri.xsl?template="
    xmlns:r    ="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rddlp="http://www.rddl.org/purposes#"
    xmlns:rddln="http://www.rddl.org/natures#"
    exclude-result-prefixes="uri">

<xsl:import href="../uri43/uri.xsl"/>

<xsl:param name="Base"/>

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

<div xmlns="http://www.w3.org/1999/xhtml">
<p>$Id: html2rdfs.xsl,v 1.21 2007/10/04 16:08:29 connolly Exp $</p>

<p>See <a href="./">documentation</a>.</p>

<p>@@idea: an option to spit out a merge of the input HTML
and the generated RDF.</p>

<p>@@idea: extract the relationship between the generic
resource, the HTML input, and the RDF output.</p>

<p>@@idea: extract the RCS/CVS $foo$ information. See site summary hack...</p>

<p>@@issue: rdf:resource= vs. resource= ; similarly for ID/rdf:ID
about, etc.  issue also comes up in <a href="../rdf.xsd">XML Schema
for RDF</a></p>

</div>

<xsl:output method="xml" indent="yes"/>

<xsl:variable name="Debug" select="0"/>

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

<xsl:variable name="rdfsNS"
	      select='"http://www.w3.org/2000/01/rdf-schema#"'/>

<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#"'/>

<xsl:template match='h:html'>
  <r:RDF>
    <r:Description r:about="">
      <xsl:for-each select='.//h:a[@rel="normative-reference"]'>
	<rddlp:normative-reference r:parseType="Resource">
	  <rddln:target r:resource="{@href}" />
	</rddlp:normative-reference>
      </xsl:for-each>
    </r:Description>

    <!-- diabolical hack: XPath doen't have test ? good : bad,
	 or I'd write string-length(h:head/@id) ? ":" : ""
	 -->

    <xsl:variable name="relPrefix" select='concat(h:head/@id, substring(":", 1, string-length(h:head/@id)))'/>

    <xsl:if test="not(h:head/@id)">
      <xsl:message>no id attribute to go with profile on head; use id='' to denote the empty prefix.</xsl:message>
    </xsl:if>

    <xsl:if test="string-length($relPrefix) &lt; 2">
      <xsl:message>no link relationship prefix found: <xsl:value-of select="$relPrefix"/></xsl:message>
    </xsl:if>

    <xsl:variable name="classLink"
		  select='h:head/h:link[@rel=concat($relPrefix, "classes")]'/>

    <xsl:if test="not($classLink)">
      <xsl:message>no classes link</xsl:message>
    </xsl:if>

    <xsl:if test="not($classLink/@id)">
      <xsl:message>no id attribute on classes link; use id='' to denote the empty prefix.</xsl:message>
    </xsl:if>

    <xsl:variable name="classPrefix"
		  select='concat($classLink/@id,
			 substring(":", 1, string-length($classLink/@id)))'/>

    <xsl:for-each select='.//h:div[@class=concat($classPrefix, "ClassTree")]'>
      <xsl:for-each select=".//h:ul/h:li">
        <xsl:call-template name="extract-subclass"/>
      </xsl:for-each>
    </xsl:for-each>

    <xsl:for-each select='.//h:div[@class=concat($classPrefix, "Classes")]'>
      <xsl:message>Anachronistic usage: 'ClassTree' replaces 'Classes'</xsl:message> due to class with 'classes'.
    </xsl:for-each>

    <xsl:for-each select='.//h:li[@class=concat($classPrefix, "Property")]'>
      <xsl:variable name='plabel' select='normalize-space(*[1])'/>

      <xsl:element name="Property" namespace="{$rdfsNS}">
        <xsl:choose>
	  <xsl:when test='local-name(*[1]) = "b"
	                  or local-name(*[1]) = "dfn"'>
	    <xsl:variable name='pname' select='*[1]/@id'/>

	    <xsl:if test='string-length($pname) &lt; 1'>
	      <xsl:message>no property name; label: <xsl:value-of select='*[1]'/></xsl:message>
	    </xsl:if>

	    <xsl:if test='not($pname = $plabel)'>
	      <xsl:message>property ID (<xsl:value-of select='$pname'/>) different from property label (<xsl:value-of select='$plabel'/>)</xsl:message>
	    </xsl:if>

	    <!-- @@hhmm... ID="foo" or about="http:...#foo" ? -->
	    <xsl:attribute name="about">
	      <xsl:value-of select='concat($Base, "#", $pname)'/>
	    </xsl:attribute>
	  </xsl:when>

	  <xsl:when test='local-name(*[1]) = "a"'>
	    <xsl:variable name="target">
	      <xsl:call-template name="uri:expand">
	        <xsl:with-param name="base" select='$Base'/>
	        <xsl:with-param name="there" select='h:a[1]/@href'/>
	      </xsl:call-template>
	    </xsl:variable>


	    <xsl:attribute name="about">
	      <xsl:value-of select='$target'/>
	    </xsl:attribute>
	  </xsl:when>

	</xsl:choose>

	<s:label><xsl:value-of select='$plabel'/></s:label>

        <xsl:if test='local-name(*[2])="a"'> <!--@@should check namespace too-->
	  <xsl:variable name="target">
	    <xsl:call-template name="uri:expand">
	      <xsl:with-param name="base" select='$Base'/>
	      <xsl:with-param name="there" select='*[2]/@href'/>
	    </xsl:call-template>
	  </xsl:variable>
	  <s:domain resource='{$target}'/>
	</xsl:if>

        <xsl:if test='local-name(*[3])="a"'>
	  <xsl:variable name="target">
	    <xsl:call-template name="uri:expand">
	      <xsl:with-param name="base" select='$Base'/>
	      <xsl:with-param name="there" select='*[3]/@href'/>
	    </xsl:call-template>
	  </xsl:variable>
	  <s:range resource='{$target}'/>
	</xsl:if>

        <xsl:call-template name="extract-comment"/>

      </xsl:element>
    </xsl:for-each>

    <xsl:for-each select='.//h:dl[@class=concat($classPrefix, "Rule")]'> <!--MARKUP-->
      <kif:wtr>

        <kif:first resource='{concat($KIFWordNS, "%3d%3e")}'/> <!-- => uri-escaped -->
	<kif:rest><kif:list><kif:first>
	  <kif:list>
	    <kif:first resource='{concat($KIFWordNS, "and")}'/>

	    <xsl:call-template name="list-premises">
              <xsl:with-param name="qty" select="count(h:dd/h:ul/h:li)"/>
	      <xsl:with-param name="idx" select="1"/>
	      <xsl:with-param name="rule" select="."/>
            </xsl:call-template>
	  </kif:list>
        </kif:first>
	<kif:rest><kif:list><kif:first>

        <xsl:for-each select="h:dt">
	  <xsl:call-template name="extract-prop"/>
        </xsl:for-each>

        </kif:first>
        <kif:rest><kif:null/></kif:rest>
	</kif:list></kif:rest></kif:list></kif:rest>
      </kif:wtr>
    </xsl:for-each>

    <xsl:for-each select=".//h:h2[@class='Property']">
      <xsl:message>@@obsolete Property markup used</xsl:message>
    </xsl:for-each>

    <xsl:for-each select=".//h:h2[@class='Class']">
      <xsl:message>@@obsolete Class markup used</xsl:message>
    </xsl:for-each>
  </r:RDF>
</xsl:template>


<xsl:template name="extract-subclass">
  <xsl:param name="superClass"/>

  <xsl:variable name="it" select='*[1]'/>
  <xsl:variable name='ln' select="normalize-space($it)"/>

  <xsl:choose>
    <xsl:when test='local-name($it) = "a"'>

      <xsl:variable name="target">
	<xsl:call-template name="uri:expand">
	  <xsl:with-param name="base" select='$Base'/>
	  <xsl:with-param name="there" select='$it/@href'/>
	</xsl:call-template>
      </xsl:variable>

      <s:Class about='{$target}'>
	<s:label><xsl:value-of select='$ln'/></s:label>

	<xsl:call-template name="extract-comment"/>

        <xsl:if test="$superClass">
          <s:subClassOf resource='{$superClass}'/>
        </xsl:if>
      </s:Class>

      <xsl:call-template name='extract-instances'>
        <xsl:with-param name='class' select='$target'/>
      </xsl:call-template>

      <xsl:for-each select="h:ul/h:li">
        <xsl:call-template name="extract-subclass">
          <xsl:with-param name="superClass"
    		      select="$target"/>
        </xsl:call-template>
      </xsl:for-each>

    </xsl:when>

    <xsl:otherwise>
      <xsl:variable name="itsName" select='h:b/@id'/>

      <xsl:if test="not($itsName)">
        <xsl:message>no class identifier</xsl:message>
      </xsl:if>

      <xsl:variable name="refIt" select='concat($Base, "#", $itsName)'/>

      <xsl:if test="not($itsName = $ln)">
        <xsl:message>class identifier '<xsl:value-of select='$itsName'/>' != label '<xsl:value-of select='$ln'/>'</xsl:message>
      </xsl:if>

      <!-- @@hhmm... ID="foo" or about="http:...#foo" ? -->
      <s:Class about='{$refIt}'>
	<s:label><xsl:value-of select='$ln'/></s:label>
        <xsl:if test="$superClass">
          <s:subClassOf resource='{$superClass}'/>
        </xsl:if>
      </s:Class>

      <xsl:call-template name='extract-instances'>
        <xsl:with-param name='class' select='$refIt'/>
      </xsl:call-template>

      <xsl:for-each select="h:ul/h:li">
        <xsl:call-template name="extract-subclass">
          <xsl:with-param name="superClass"
    		      select="$refIt"/>
        </xsl:call-template>
      </xsl:for-each>

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


<xsl:template name="extract-comment">
  <xsl:if test="h:p">
    <s:comment> <!-- @@use parseType=literal, copy-of rather than value-of, to get embedded markup in the comment paragraph -->
      <xsl:value-of select="normalize-space(h:p)"/>
    </s:comment>
  </xsl:if>
</xsl:template>

<xsl:template name="extract-instances">
  <xsl:param name="class"/>

  <xsl:for-each select="h:em">
    <xsl:variable name="memName" select='@id'/>

    <xsl:if test="not($memName)">
      <xsl:message>no instance identifier: <xsl:value-of select="."/></xsl:message>
    </xsl:if>

    <!-- @@hhmm... ID="foo" or about="http:...#foo" ? -->
    <r:Description about='{concat($Base, "#", $memName)}'>
      <r:type resource='{$class}'/>
      <s:label><xsl:value-of select="normalize-space(.)" /></s:label>
    </r:Description>
  </xsl:for-each>

  <xsl:for-each select="h:a[position()>1]">
    <xsl:variable name="target">
      <xsl:call-template name="uri:expand">
        <xsl:with-param name="base" select='$Base'/>
	<xsl:with-param name="there" select='@href'/>
      </xsl:call-template>
    </xsl:variable>

    <r:Description about='{$target}'>
      <r:type resource='{$class}'/>
    </r:Description>
  </xsl:for-each>

</xsl:template>


<xsl:template name="list-premises">
  <xsl:param name="rule"/>
  <xsl:param name="qty"/>
  <xsl:param name="idx"/>

  <xsl:if test="$Debug">
    <xsl:message>list-premises: qty: <xsl:value-of select="$qty"/></xsl:message>
  </xsl:if>

  <xsl:choose>
    <xsl:when test='$idx &lt;= $qty'>
      <xsl:for-each select='$rule/h:dd/h:ul/h:li[$idx]'>
          <kif:rest>
            <kif:list>
              <kif:first>
	        <xsl:call-template name="extract-prop"/>
	      </kif:first>

	        <xsl:call-template name="list-premises">
		  <xsl:with-param name="qty" select="$qty"/>
		  <xsl:with-param name="idx" select="$idx + 1"/>
		  <xsl:with-param name="rule" select="$rule"/>
		</xsl:call-template>
	    </kif:list>
          </kif:rest>
      </xsl:for-each>
    </xsl:when>

    <xsl:otherwise>
      <kif:rest resource='{concat($KIFNS, "nil")}'/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<xsl:template name="extract-prop">
  <r:Statement>
    <xsl:call-template name="extract-sentence-part">
      <xsl:with-param name="elt" select="*[1]"/>
      <xsl:with-param name="part" select='"predicate"'/>
    </xsl:call-template>

    <xsl:call-template name="extract-sentence-part">
      <xsl:with-param name="elt" select="*[2]"/>
      <xsl:with-param name="part" select='"subject"'/>
    </xsl:call-template>

    <xsl:call-template name="extract-sentence-part">
      <xsl:with-param name="elt" select="*[3]"/>
      <xsl:with-param name="part" select='"object"'/>
    </xsl:call-template>
  </r:Statement>
</xsl:template>

<xsl:template name="extract-sentence-part">
  <xsl:param name="part"/>
  <xsl:param name="elt"/>

  <xsl:choose>
    <xsl:when test='local-name($elt) = "var"'>
      <xsl:element name="{$part}" namespace="{$rdfNS}">
        <xsl:attribute name="resource">
	  <xsl:value-of select='concat($KIFWordNS, "%3f", normalize-space($elt))'/> <!-- %3f for ? . @@ escape non-URI characters-->
	</xsl:attribute>
      </xsl:element>

    </xsl:when>

    <xsl:when test='local-name($elt) = "a"'>
      <xsl:variable name="target">
	<xsl:call-template name="uri:expand">
	  <xsl:with-param name="base" select='$Base'/>
	  <xsl:with-param name="there" select='$elt/@href'/>
	</xsl:call-template>
      </xsl:variable>

      <xsl:element name="{$part}" namespace="{$rdfNS}">
	<xsl:attribute name="resource"><xsl:value-of select='concat($KIFWordNS, $target)'/> <!-- @@escape non-URI characters -->
	</xsl:attribute>
      </xsl:element>

    </xsl:when>

    <xsl:otherwise>
      <xsl:message>cannot find <xsl:value-of select="$part"/> in rule</xsl:message>	
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>



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


</xsl:stylesheet>
