<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY m "http://www.loc.gov/mods/v3">
]>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:foaf="http://xmlns.com/foaf/0.1/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:md="&m;"
  xmlns:m="&m;/"
>
<xsl:output indent="yes"/>

<xsl:template name="_doas_description">
 <rdf:RDF xmlns="http://purl.org/net/ns/doas#">
  <rdf:Description rdf:about="">
   <title>MODS/XML to RDF conversion stylesheet</title>
   <description>This stylesheet converts MODS</description>
   <author rdf:parseType="Resource">
    <name>Masahide Kanzaki</name>
    <mbox rdf:resource="mailto:webmaster@kanzaki.com"/>
   </author>
   <created>2007-11-21</created>
   <release rdf:parseType="Resource">
    <revision>0.4</revision>
    <created>2007-11-22</created>
   </release>
   <rights>(c) 2007 by the author, copyleft under GPL</rights>
   <license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/"/>
  </rdf:Description>
 </rdf:RDF>
</xsl:template>

<xsl:template match="/">
 <rdf:RDF>
  <xsl:apply-templates select="md:modsCollection"/>
  <xsl:apply-templates select="descendant-or-self::md:mods"/>
  <!--
  <rdf:Property rdf:about="&m;#title">
   <rdfs:subPropertyOf rdf:resource="http://www.w3.org/2000/01/rdf-schema#label"/>
  </rdf:Property>
  -->
 </rdf:RDF>
</xsl:template>

<xsl:template match="md:modsCollection">
 <!--** generates an rdf:Description for an entity and select attributes -->
 <m:ModsCollection rdf:ID="collection{position()}">
  <xsl:for-each select="md:mods">
   <m:member>
    <xsl:attribute name="rdf:resource">
     <xsl:call-template name="find-id"/>
    </xsl:attribute>
   </m:member>
  </xsl:for-each>
 </m:ModsCollection>
</xsl:template>

<xsl:template match="md:mods">
 <!--** generates an rdf:Description for an entity and select attributes -->
 <rdf:Description>
  <xsl:attribute name="rdf:about">
   <xsl:call-template name="find-id"/>
  </xsl:attribute>
  <xsl:call-template name="test-arc"/>
 </rdf:Description>
</xsl:template>


<xsl:template name="find-id">
 <xsl:choose>
  <xsl:when test="md:recordInfo/md:recordIdentifier">
   <xsl:value-of select="concat('#',md:recordInfo/md:recordIdentifier)"/>
  </xsl:when>
  <xsl:otherwise>
   <xsl:value-of select="concat('#item',position())"/>
  </xsl:otherwise>
 </xsl:choose>

</xsl:template>


<xsl:template name="test-value">
 <xsl:choose>
  <xsl:when test="*">
   <xsl:call-template name="gen-label"/>
   <xsl:apply-templates select="*[local-name() != 'role']" mode="arc"/>
   <xsl:apply-templates select="md:role" mode="arc"/>
  </xsl:when>
  <xsl:otherwise>
   <rdf:value>
    <xsl:value-of select="."/>
   </rdf:value>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>


<xsl:template match="*" mode="arc">
 <xsl:choose>
  <!-- esp. namePart. if has @type, use it as propety name. but if not @type, seems＠＠-->
  <xsl:when test="contains(local-name(),'Part') and @type">
   <xsl:element name="{concat('m:',@type)}">
    <xsl:call-template name="test-arc"/>
   </xsl:element>
  </xsl:when>
  <xsl:when test="local-name()='role' and position()=1">
   <!-- ignore first role because it is used for parent property by test-arc -->
  </xsl:when>
  <xsl:otherwise>
   <xsl:element name="{concat('m:',local-name())}">
    <xsl:call-template name="gen-node"/>
   </xsl:element>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>




<xsl:template name="test-arc">
 <!--** test if there is any node considered to be an arc. Steps -->
 <xsl:choose>
  <!--@ if child element found, for each child, switch -->
  <xsl:when test="*">
   <xsl:for-each select='*'>
    <xsl:choose>
     <!--@ _case name with role: use @type of the first role for property. experimental -->
     <xsl:when test="local-name()='name' and ./md:role">
      <xsl:element name="{concat('m:',translate(normalize-space(md:role[1]),' ','_'))}">
       <xsl:call-template name="gen-node"/>
      </xsl:element>
     </xsl:when>
     <!--@ _case subject: use first child (e.g. topic, geographic, etc) for property, and call test-datatype. experimental -->
     <xsl:when test="local-name()='subject'">
      <xsl:element name="{concat('m:',local-name(child::*[1]))}">
       <xsl:call-template name="test-datatype">
        <xsl:with-param name="type" select=".//@authority"/>
        <xsl:with-param name="action" select="'datatype'"/>
       </xsl:call-template>
      </xsl:element>
     </xsl:when>
     <!--@ _case note with @type: use @type for property. experimental -->
     <xsl:when test="local-name()='note' and @type">
      <xsl:element name="{concat('m:',translate(@type,' ','_'))}">
       <xsl:value-of select="normalize-space(.)"/>
      </xsl:element>
     </xsl:when>
      <!--@ _default: generates an property element, and call gen-node -->
     <xsl:otherwise>
      <xsl:element name="{concat('m:',local-name())}">
       <xsl:call-template name="gen-node"/>
      </xsl:element>
     </xsl:otherwise>
    </xsl:choose>
   </xsl:for-each>
  </xsl:when>
  <!--@ otherwise, generate a literal value -->
  <xsl:otherwise>
   <xsl:value-of select="normalize-space(.)"/>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<xsl:template name="gen-node">
 <xsl:choose>
  <!--@ _case @authority presents: generates typed element of @authority value, and test-value -->
  <xsl:when test="@authority">
   <xsl:call-template name="test-datatype">
    <xsl:with-param name="type" select="@authority"/>
   </xsl:call-template>
  </xsl:when>
  <!-- test for Statement_of_responsibility in note
  <xsl:when test="contains(@type,' ')">
   <xsl:call-template name="test-datatype">
    <xsl:with-param name="type" select="@type"/>
    <xsl:with-param name="action" select="'tnode'"/>
   </xsl:call-template>
  </xsl:when>
  -->
  <!--@ _case @type presents: generates typed element of @type value, and test-value -->
  <xsl:when test="@type">
   <xsl:call-template name="test-datatype">
    <xsl:with-param name="type" select="@type"/>
   </xsl:call-template>
  </xsl:when>
  <xsl:when test="@*">
   <xsl:call-template name="test-datatype">
    <xsl:with-param name="type" select="@*[1]"/>
   </xsl:call-template>
  </xsl:when>
  <xsl:when test="md:text and count(*)=1">
   <xsl:call-template name="test-datatype">
    <xsl:with-param name="type" select="'text'"/>
    <xsl:with-param name="action" select="'datatype'"/>
   </xsl:call-template>
  </xsl:when>
  <!--@ _default: call test-stripe -->
  <xsl:otherwise>
   <xsl:call-template name="test-stripe"/>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<xsl:template name="test-stripe">
 <!--** test if the element in place of arc is really a arc. Steps -->
 <xsl:variable name="n" select="concat(local-name(),'Term')"/>
 <xsl:choose>
  <!--@ if child element is xxxTerm for this element xxx, skip child and generate datatype. e.g ,place> has child <placeTerm authority=...>. this makes RDF model much simpler, but change the original model -->
  <xsl:when test="*[local-name() = $n]">
   <xsl:call-template name="test-datatype">
    <xsl:with-param name="type" select=".//@authority"/>
    <xsl:with-param name="action" select="'datatype'"/>
   </xsl:call-template>
  </xsl:when>
  <!--@ if has more than one child, apply parseType='Resource' because a propety cannot have multiple values. -->
  <xsl:when test="count(*) &gt; 1">
   <xsl:attribute name="rdf:parseType">Resource</xsl:attribute>
   <xsl:call-template name="gen-label"/>
   <xsl:call-template name="test-arc"/>
  </xsl:when>
  <!--@ if has a child but no grand child, apply parseType='Resource' because child with literal velue must be a property. -->
  <xsl:when test="* and not(*/*)">
   <xsl:attribute name="rdf:parseType">Resource</xsl:attribute>
   <xsl:call-template name="gen-label"/>
   <xsl:call-template name="test-arc"/>
  </xsl:when>
  <xsl:when test="*">
   <xsl:call-template name="test-value"/>
  </xsl:when>
  <xsl:otherwise>
   <xsl:value-of select="."/>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<xsl:template name="test-datatype">
 <xsl:param name="type"/><!-- element or attribute to test as datatype or class-->
 <xsl:param name="action"/><!--** ignore child element and generate datatype-->
 <xsl:choose>
  <xsl:when test="($action='tnode') or (* and not($action='datatype')) or (count(*) &gt; 1)">
   <xsl:call-template name="typed-node">
    <xsl:with-param name="type" select="$type"/>
   </xsl:call-template>
  </xsl:when>
  <xsl:when test="not($type) or $type=''">
   <xsl:value-of select="normalize-space(.)"/>
  </xsl:when>
  <xsl:otherwise>
   <!--xsl:element name="{concat('m:',local-name())}"-->
    <xsl:attribute name="rdf:resource">&m;/<xsl:value-of select="translate($type,' ','_')"/>#<xsl:value-of select="translate(normalize-space(.),' ','_')"/></xsl:attribute>
   <!--/xsl:element-->
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<xsl:template name="typed-node">
 <xsl:param name="type"/>
 <xsl:variable name="t">
  <xsl:call-template name="uc-first">
   <xsl:with-param name="n" select="$type"/>
  </xsl:call-template>
 </xsl:variable>
 <!--
 <m:test><xsl:value-of select="$t"/></m:test>
 -->
 <xsl:element name="{$t}">
  <xsl:call-template name="test-value"/>
 </xsl:element>
</xsl:template>

<xsl:template name="gen-label">
 <xsl:variable name="l" select="normalize-space(.)"/>
 <rdfs:label>
  <xsl:choose>
   <xsl:when test="string-length($l) &gt; 40">
    <xsl:value-of select="concat(substring($l,1,36),'...')"/>
   </xsl:when>
   <xsl:otherwise>
    <xsl:value-of select="$l"/>
   </xsl:otherwise>
  </xsl:choose>
 </rdfs:label>
<!--
 <xsl:if test="not(child::*[local-name()='title'])">
  <rdfs:label><xsl:value-of select="normalize-space(.)"/></rdfs:label>
 </xsl:if>
-->
</xsl:template>

<xsl:template name="uc-first">
 <xsl:param name="n"/>
 <xsl:value-of select="concat('m:',translate(substring($n,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),translate(substring($n,2),' ','_'))"/>
</xsl:template>

</xsl:stylesheet>
