Print

Print


Bruce had requested that I post these documents to the list.  I hope that
someone may find them useful and I encourage all feedback and criticism.

These were developed to transform MODS (encoded in METS) into Dublin Core
for internal indexing purposes.  While this is not a final version, it is
in production and seems to be doing what it is supposed to.  A slightly
modified production version can be viewed at
http://ark.cdlib.org/xslt/extract-dc/OAC-LSTA-MODS2DC.qdc21.xsl.

I took the DC to MODS mapping stylesheet as a starting point, but as we all
know round-tripping is never the same both ways and I had to make a lot of
logical modification.  Also, we are still working with MODS 2.0 so this
will need work when we make the transition.

I have attached the documents (an .xslt and a .txt) and have also pasted
them below.  Again, please let me hear any opinions you may have.

Paul Fogel
California Digital Library
[log in to unmask]
510.987.0680


<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xlink="http://www.w3.org/TR/xlink"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:mets="http://www.loc.gov/METS/"
   xmlns:cdl="http://ark.cdlib.org/schemas/appqualifieddc/"
   xmlns:dcterms="http://purl.org/dc/terms/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:mods="http://www.loc.gov/mods/"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

   <xsl:strip-space elements="*"/>

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

   <xsl:template match="/">
     <xsl:apply-templates select="mets:mets"/>
   </xsl:template>

   <xsl:template match="mets:mets">
     <qdc2>
       <xsl:call-template name="title"/>
       <xsl:call-template name="creator"/>
       <xsl:call-template name="subject"/>
       <xsl:call-template name="description"/>
       <xsl:call-template name="publisher"/>
       <xsl:call-template name="contributor"/>
       <xsl:call-template name="date"/>
       <xsl:call-template name="type"/>
       <xsl:call-template name="format"/>
       <xsl:call-template name="identifier"/>
       <xsl:call-template name="source"/>
       <xsl:call-template name="language"/>
       <xsl:call-template name="relation"/>
       <xsl:call-template name="coverage"/>
       <xsl:call-template name="rights"/>
       <xsl:call-template name="dcterms"/>
     </qdc2>
   </xsl:template>

   <xsl:template name="title">
     <dc:title>
       <xsl:value-of select="//mods:mods/mods:titleInfo/mods:title"/>
       <xsl:if test="//mods:mods/mods:titleInfo/mods:subTitle">
         <xsl:text>: </xsl:text>
         <xsl:value-of select="//mods:mods/mods:titleInfo/mods:subTitle"/>
       </xsl:if>
     </dc:title>
   </xsl:template>

   <xsl:template name="creator">
     <!-- This may be used in the future for alternate encoding practices -->
     <!-- xsl:if test="contains(//mods:mods/mods:name/mods:role/mods:text,
'creator')" -->
       <!-- dc:creator-->
         <!-- xsl:value-of select="//mods:mods/mods:name[1]/mods:namePart"/-->
       <!--/dc:creator-->
     <!--/xsl:if-->
     <xsl:if test="contains(//mods:mods/mods:name/mods:role, 'creator')">
       <dc:creator>
         <xsl:value-of select="//mods:mods/mods:name[1]/mods:namePart"/>
       </dc:creator>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:recordInfo/mods:recordContentSource">
       <dc:creator>
         <xsl:value-of
select="//mods:mods/mods:recordInfo/mods:recordContentSource"/>
       </dc:creator>
     </xsl:if>
   </xsl:template>

   <xsl:template name="subject">
     <xsl:for-each select="//mods:mods/mods:subject/mods:topic">
       <dc:subject>
         <xsl:value-of select="."/>
       </dc:subject>
     </xsl:for-each>
     <xsl:for-each select="//mods:mods/mods:subject/mods:name">
       <dc:subject>
         <xsl:value-of select="."/>
       </dc:subject>
     </xsl:for-each>
     <xsl:if test="//mods:mods/mods:subject/mods:titleInfo/mods:title">
       <dc:subject>
         <xsl:value-of
select="//mods:mods/mods:subject/mods:titleInfo/mods:title"/>
       </dc:subject>
     </xsl:if>
   </xsl:template>

   <xsl:template name="description">
     <xsl:if test="//mods:mods/mods:abstract">
       <description>
         <xsl:value-of select="//mods:mods/mods:abstract"/>
       </description>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:tableOfContents">
       <dc:description>
         <xsl:value-of select="//mods:mods/mods:tableOfContents"/>
       </dc:description>
     </xsl:if>
     <xsl:for-each select="//mods:mods/mods:note">
       <dc:description>
         <xsl:value-of select="."/>
       </dc:description>
     </xsl:for-each>
     <xsl:if test="//mods:mods/mods:subject/mods:name/mods:description">
       <dc:description>
         <xsl:value-of
select="//mods:mods/mods:subject/mods:name/mods:description"/>
       </dc:description>
     </xsl:if>
   </xsl:template>

   <xsl:template name="publisher">
     <xsl:if test="//mods:mods/mods:originInfo/mods:publisher">
       <dc:publisher>
         <xsl:value-of select="//mods:mods/mods:originInfo/mods:publisher"/>
       </dc:publisher>
     </xsl:if>
     <!-- may be used in the future, if deemed appropriate -->
     <!--xsl:if test="//mods:mods/mods:recordInfo/mods:recordContentSource"-->
       <!--dc:publisher-->
         <!--xsl:value-of
select="//mods:mods/mods:recordInfo/mods:recordContentSource"/-->
       <!--/dc:publisher-->
     <!--/xsl:if-->
     <xsl:if test="//mods:mods/mods:publicationInfo/mods:publisher">
       <dc:publisher>
         <xsl:value-of
select="//mods:mods/mods:publicationInfo/mods:publisher"/>
       </dc:publisher>
     </xsl:if>
   </xsl:template>

   <xsl:template name="contributor">
     <xsl:if test="contains(//mods:mods/mods:name/mods:role/mods:text,
'contributor')">
       <dc:contributor>
         <xsl:value-of select="//mods:mods/mods:name[1]/mods:namePart"/>
       </dc:contributor>
     </xsl:if>
   </xsl:template>

   <xsl:template name="date">
     <xsl:if test="//mods:mods/mods:originInfo/mods:dateIssued">
       <dc:date>
         <xsl:value-of select="//mods:mods/mods:originInfo/mods:dateIssued"/>
       </dc:date>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:publicationInfo/mods:dateIssued">
       <dc:date>
         <xsl:value-of
select="//mods:mods/mods:publicationInfo/mods:dateIssued"/>
       </dc:date>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:originInfo/mods:dateCreated">
       <dc:date>
         <xsl:value-of select="//mods:mods/mods:originInfo/mods:dateCreated"/>
       </dc:date>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:originInfo/mods:dateCaptured">
       <dc:date>
         <xsl:value-of select="//mods:mods/mods:originInfo/mods:dateCaptured"/>
       </dc:date>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:originInfo/mods:dateOther">
       <dc:date>
         <xsl:value-of select="//mods:mods/mods:originInfo/mods:dateOther"/>
       </dc:date>
     </xsl:if>
   </xsl:template>

   <xsl:template name="type">
     <xsl:if test="//mods:mods/mods:typeOfResource">
     <dc:type>
         <xsl:value-of select="//mods:mods/mods:typeOfResource"/>
     </dc:type>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:genre">
     <dc:type>
         <xsl:value-of select="//mods:mods/mods:genre"/>
     </dc:type>
     </xsl:if>
   </xsl:template>

   <xsl:template name="format">
     <xsl:if test="//mods:mods/mods:physicalDescription/mods:extent">
       <dc:format>
         <xsl:value-of
select="//mods:mods/mods:physicalDescription/mods:extent"/>
       </dc:format>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:physicalDescription/mods:form">
       <dc:format>
         <xsl:value-of
select="//mods:mods/mods:physicalDescription/mods:form"/>
       </dc:format>
     </xsl:if>
     <xsl:if
test="//mods:mods/mods:physicalDescription/mods:internetMediaType">
       <dc:format>
         <xsl:value-of
select="//mods:mods/mods:physicalDescription/mods:internetMediaType"/>
       </dc:format>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:physicalDescription/mods:digitalOrigin">
       <dc:format>
         <xsl:value-of
select="//mods:mods/mods:physicalDescription/mods:digitalOrigin"/>
       </dc:format>
     </xsl:if>
     <xsl:if test="//mods:mods/mods:physicalDescription/mods:note">
       <dc:format>
         <xsl:value-of
select="//mods:mods/mods:physicalDescription/mods:note"/>
       </dc:format>
     </xsl:if>
   </xsl:template>

   <xsl:template name="identifier">
     <xsl:for-each select="//mods:mods/mods:identifier">
       <xsl:choose>
         <xsl:when test="@type='isbn'">
           <dc:identifier>
             <xsl:text>isbn: </xsl:text>
             <xsl:value-of select="."/>
           </dc:identifier>
         </xsl:when>
         <xsl:when test="@type='issn'">
           <dc:identifier>
             <xsl:text>issn: </xsl:text>
             <xsl:value-of select="."/>
           </dc:identifier>
         </xsl:when>
         <xsl:when test="@type='doi'">
           <dc:identifier>
             <xsl:text>doi: </xsl:text>
             <xsl:value-of select="."/>
           </dc:identifier>
         </xsl:when>
         <xsl:when test="@type='lccn'">
           <dc:identifier>
             <xsl:text>lccn: </xsl:text>
             <xsl:value-of select="."/>
           </dc:identifier>
         </xsl:when>
         <xsl:when test="@type='uri'">
           <dc:identifier>
             <xsl:text>uri: </xsl:text>
             <xsl:value-of select="."/>
           </dc:identifier>
         </xsl:when>
         <xsl:otherwise>
           <dc:identifier>
             <xsl:value-of select="."/>
           </dc:identifier>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
   </xsl:template>

   <xsl:template name="source">
     <xsl:if test="//mods:mods/mods:relatedItem[@type='original']">
       <xsl:for-each select="//mods:mods/mods:relatedItem[@type='original']/*">
         <dc:source>
           <xsl:value-of select="."/>
         </dc:source>
       </xsl:for-each>
     </xsl:if>
   </xsl:template>

   <xsl:template name="language">
     <dc:language>
       <xsl:value-of select="//mods:mods/mods:language"/>
     </dc:language>
   </xsl:template>

   <xsl:template name="relation">
     <xsl:for-each select="//mods:mods/mods:relatedItem">
       <xsl:choose>
         <xsl:when test="@type='original'"/>
         <xsl:when test="@type='series'"/>
         <xsl:otherwise>
           <xsl:apply-templates mode="makeRelations"/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
     <xsl:if test="//*[local-name()='relation']">
       <dc:relation>
         <xsl:value-of select="//*[local-name()='relation']"/>
       </dc:relation>
     </xsl:if>
   </xsl:template>

<xsl:template match="*" mode="makeRelations">
   <xsl:apply-templates mode="makeRelations"/>
</xsl:template>

<xsl:template match="text()" mode="makeRelations">
   <xsl:if test="normalize-space(.) != ''">
     <dc:relation>
       <xsl:value-of select="normalize-space(.)"/>
     </dc:relation>
   </xsl:if>
</xsl:template>

<xsl:template name="coverage">
   <xsl:if test="//mods:mods/mods:subject/mods:geographic">
     <dc:coverage>
       <xsl:value-of select="//mods:mods/mods:subject/mods:geographic"/>
     </dc:coverage>
   </xsl:if>
   <xsl:if test="//mods:mods/mods:subject/mods:temporal">
     <dc:coverage>
       <xsl:value-of select="//mods:mods/mods:subject/mods:temporal"/>
     </dc:coverage>
   </xsl:if>
   <xsl:if test="//mods:mods/mods:subject/mods:hierarchicalGeographic">
     <xsl:apply-templates mode="coverage1"
select="//mods:mods/mods:subject/mods:hierarchicalGeographic"/>
   </xsl:if>
   <xsl:if test="//mods:mods/mods:subject/mods:cartographic">
     <xsl:apply-templates mode="coverage2"
select="//mods:mods/mods:subject/mods:cartographic"/>
   </xsl:if>
   <xsl:for-each select="//mods:mods/mods:classification">
     <dc:coverage>
       <xsl:value-of select="."/>
     </dc:coverage>
   </xsl:for-each>
</xsl:template>

<xsl:template match="*" mode="coverage1">
   <xsl:apply-templates mode="coverage1"/>
</xsl:template>

<xsl:template match="text()" mode="coverage1">
   <xsl:if test="normalize-space(.) != ''">
     <dc:coverage>
       <xsl:value-of select="normalize-space(.)"/>
     </dc:coverage>
   </xsl:if>
</xsl:template>

<xsl:template match="*" mode="coverage2">
   <xsl:apply-templates mode="coverage2"/>
</xsl:template>

<xsl:template match="text()" mode="coverage2">
   <xsl:if test="normalize-space(.) != ''">
     <dc:coverage>
       <xsl:value-of select="normalize-space(.)"/>
     </dc:coverage>
   </xsl:if>
</xsl:template>

<xsl:template name="rights">
   <xsl:if test="//mods:mods/mods:accessCondition">
     <dc:rights>
       <xsl:value-of select="//mods:mods/mods:accessCondition"/>
     </dc:rights>
   </xsl:if>
</xsl:template>

<xsl:template name="dcterms">
   <xsl:if test="//mods:mods/mods:abstract">
     <dcterms:abstract>
       <xsl:value-of select="//mods:mods/mods:abstract"/>
     </dcterms:abstract>
   </xsl:if>
   <xsl:if test="//mods:mods/mods:recordInfo/mods:recordCreationDate">
     <dcterms:created>
       <xsl:value-of
select="//mods:mods/mods:recordInfo/mods:recordCreationDate"/>
     </dcterms:created>
   </xsl:if>
   <xsl:if test="//mods:mods/mods:originInfo/mods:dateCreated">
     <dcterms:created>
       <xsl:value-of select="//mods:mods/mods:originInfo/mods:dateCreated"/>
     </dcterms:created>
   </xsl:if>
   <xsl:if test="//mods:mods/mods:recordInfo/mods:recordChangeDate">
     <dcterms:modified>
       <xsl:value-of
select="//mods:mods/mods:recordInfo/mods:recordChangeDate"/>
     </dcterms:modified>
   </xsl:if>
   <xsl:for-each select="//mods:mods/mods:relatedItem">
     <xsl:choose>
       <xsl:when test="@type='series'">
         <xsl:apply-templates mode="makeIsPartOf"/>
       </xsl:when>
     </xsl:choose>
   </xsl:for-each>
</xsl:template>

<xsl:template match="*" mode="makeIsPartOf">
   <xsl:apply-templates mode="makeIsPartOf"/>
</xsl:template>

<xsl:template match="text()" mode="makeIsPartOf">
   <xsl:if test="normalize-space(.) != ''">
     <dcterms:isPartOf>
       <xsl:value-of select="normalize-space(.)"/>
     </dcterms:isPartOf>
   </xsl:if>
</xsl:template>

</xsl:stylesheet>


MODS to Dublin Core Mapping



By Dublin Core Element, from MODS Element

Title:
//mods/titleInfo/title - A conditional IF statement is included to catch
<titleInfo><subTitle> and append it to the title, separated by colon space
(: ).

Creator:
//mods/name/namePart -  when //mods/name/role[. = 'creator']
//mods/recordInfo/recordContentSource

Subject:
//mods/subject/topic
//mods/subject/name
//mods/subject/titleInfo/title

Description:
//mods/abstract
//mods/tableOfContents
//mods/note
//mods/subject/name<description>

Publisher:
//mods/originInfo/publisher
//mods/publicationInfo/publisher - to accommodate earlier encoding
practices; this usage is outdated

Contributor:
//mods/name/namePart -  when //mods/name/role/text[. = 'contributor']

Date:
Mapped from:
//mods/originInfo/dateIssued
//mods/originInfo/dateCreated
//mods/originInfo/dateCaptured
//mods/originInfo/dateOther
//mods/publicationInfo/dateIssued - to accommodate earlier encoding
practices; this usage is outdated

Type:
//mods/typeOfResource
//mods/genre

Format:
//mods/physicalDescription/extent
//mods/physicalDescription/form
//mods/physicalDescription/internetMediaType
//mods/physicalDescription/digitalOrigin
//mods/physicalDescription/note

Identifier:
//mods/identifier - If @TYPE= 'isbn', 'issn', 'lccn', 'doi' or 'uri', then
this value precedes the data, separated by colon space.
         Example:        <identifier>uri:
http://www.ucpress.edu/books/pages/6178.html&amp;isbn=0520081994</identifier>
         If there is no TYPE attribute, or if it is not set to one of these
values, the data is mapped without qualification.

Source:
//mods/relatedItem[@TYPE='original']

Language:
//mods/language

Relation:
//mods/relatedItem - except when relatedItem[(@TYPE='original') or
(@TYPE='series')]

Coverage:
Mapped from:
//mods/subject/geographic
//mods/subject/temporal
//mods/subject/hierarchicalGeographic
//mods/subject/cartographic
//mods/classification
         The hierarchicalGeographic and cartographic nodes are flattened so
that repeating values as well as sub-elements (and their children) are
strung into one element.

Rights:
//mods/accessCondition

DCTerms:Abstract:
//mods/abstract - this data is also mapped (see above) into Description, so
that data is not lost in Unqualified Dublin Core.

DCTerms:Created
//mods/recordInfo/recordCreationDate.  This is also mapped to Date, so that
data is not lost in Unqualified Dublin Core.

DCTerms:Modified
//mods/recordInfo/recordChangeDate.  This is also mapped to Date, so that
data is not lost in Unqualified Dublin Core.

DCTerms:isPartOf
//mods/relatedItem - when //mods/relatedItem[@TYPE='series'].  This is also
mapped to Relation, so that data is not lost in Unqualified Dublin Core.







By MODS Element, to Dublin Core Element

ELEMENT MAPPED TO
//mods/titleInfo/title                          title
//mods/titleInfo/subTitle                       title
//mods/titleInfo/partNumber                     ignored
//mods/titleInfo/partName                       ignored
//mods/titleInfo/nonSort                        ignored

//mods/name/namePart                            creator, contributor (see
above)
//mods/name/displayForm                         ignored
//mods/name/affiliation                         ignored
//mods/name/role                                Used to assign creator and
contributor, otherwise ignored.
//mods/name/description                         description

//mods/typeOfResource                           type

//mods/genre                                    type

//mods/originInfo/place                         ignored
//mods/originInfo/publisher                     publisher
//mods/originInfo/dateIssued                    date
//mods/originInfo/dateCreated                   date, dcterms:created
//mods/originInfo/dateCaptured                  date
//mods/originInfo/dateOther                     date
//mods/originInfo/edition                       ignored
//mods/originInfo/issuance                      ignored
//mods/originInfo/frequency                     ignored

//mods/language                                 language

//mods/physicalDescription/form                 format
//mods/physicalDescription/reformattingQuality  ignored
//mods/physicalDescription/internetMediaType    format
//mods/physicalDescription/extent               format
//mods/physicalDescription/digitalOrigin        format
//mods/physicalDescription/note                 format

//mods/abstract                                 description, dcterms:absctract

//mods/tableOfContents                          description

//mods/targetAudience                           ignored

//mods/note                                     description

//mods/subject/topic                            subject
//mods/subject/geographical                     coverage
//mods/subject/temporal                         coverage
//mods/subject/titleInfo/title                  subject
         (other subelements for titleInfo ignored)
//mods/subject/name<description>                subject
         (other subelements for name ignored)
//mods/subject/hierarchicalGeographic           coverage
         (subelements flattened to appear in one string)
//mods/subject/cartographic                     coverage
         (subelements flattened to appear in one string)
//mods/classification                           coverage

//mods/relatedItem[@type='original']            source
//mods/relatedItem[@type='series']              dcterms:isPartOf
//mods/relatedItem[@type='*']                   relation
         (subelements flattened to appear in one string)

//mods/identifier                               identifier
         (if type is issn, isbn, lccn, uri, or doi, it is applied at
beginning of data string; otherwise data is applied as is)
         Ex. <dc:identifier>isbn: 0123456789</dc:identifier>
             <dc:identifier>12-34567-8901234-5-67</dc:identifier>

//mods/location                                 ignored

//mods/accessCondition                          rights

//mods/extension                                ignored

//mods/recordInfo/recordContentSource           creator,
//mods/recordInfo/recordCreationDate            dcterms:created
//mods/recordInfo/recordChangeDate              dcterms:modified
//mods/recordInfo/recordIdentifier              ignored
//mods/recordInfo/languageOfCataloging          ignored