Skip to content

Instantly share code, notes, and snippets.

@gregoriopellegrino
Last active November 16, 2024 10:55
Show Gist options
  • Save gregoriopellegrino/764d9e8689b1a54908da67fd493456e4 to your computer and use it in GitHub Desktop.
Save gregoriopellegrino/764d9e8689b1a54908da67fd493456e4 to your computer and use it in GitHub Desktop.
XSLT to transform ONIX for Books metadata into EPUB metadata
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="Header" />
<xsl:template match="Product">
<!-- dc:identifier https://www.w3.org/TR/epub-33/#sec-opf-dcidentifier -->
<dc:identifier id="bookid">
<xsl:value-of select="concat('urn:isbn:', ProductIdentifier[ProductIDType='15']/IDValue)" />
</dc:identifier>
<meta property="identifier-type" refines="#bookid" scheme="onix:codelist5">15</meta>
<!-- dc:title https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dctitle -->
<dc:title id="main-title">
<xsl:value-of select="normalize-space(concat(DescriptiveDetail/TitleDetail[TitleType = '01']/TitleElement[TitleElementLevel = '01']/TitleText/text(), ' ', DescriptiveDetail/TitleDetail[TitleType = '01']/TitleElement[TitleElementLevel = '01']/TitlePrefix/text(), ' ', DescriptiveDetail/TitleDetail[TitleType = '01']/TitleElement[TitleElementLevel = '01']/TitleWithoutPrefix/text()))" />
</dc:title>
<meta property="title-type" refines="#main-title">main</meta>
<!-- dc:date https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dcdate -->
<!-- I don't set the field dc:date because I start from an ONIX made for the paper book, so the date of publication does not coincide -->
<!-- dc:creator https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dccreator -->
<xsl:for-each select="DescriptiveDetail/Contributor[not(UnnamedPersons) and ((ContributorRole = 'A01') or (ContributorRole = 'B01') or (ContributorRole = 'A12'))]">
<dc:creator id="{concat('creator',position())}">
<xsl:value-of select="PersonName" />
</dc:creator>
<!-- MARC relators roles https://www.loc.gov/marc/relators/relaterm.html -->
<!-- based on https://www.oclc.org/content/dam/research/publications/library/2012/2012-04.pdf -->
<meta refines="{concat('#creator',position())}" property="role" scheme="marc:relators">
<xsl:choose>
<xsl:when test="ContributorRole = 'A01'">aut</xsl:when>
<xsl:when test="ContributorRole = 'A12'">ill</xsl:when>
<xsl:when test="ContributorRole = 'B01'">edt</xsl:when>
</xsl:choose>
</meta>
<meta refines="{concat('#creator',position())}" property="file-as">
<xsl:value-of select="PersonNameInverted" />
</meta>
</xsl:for-each>
<!-- dc:contributor https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dccontributor -->
<xsl:for-each select="DescriptiveDetail/Contributor[not(UnnamedPersons) and (ContributorRole != 'A01') and (ContributorRole != 'B01') and (ContributorRole != 'A12')]">
<dc:contributor id="{concat('contributor',position())}">
<xsl:value-of select="PersonName" />
</dc:contributor>
<!-- MARC relators roles https://www.loc.gov/marc/relators/relaterm.html -->
<!-- based on https://www.oclc.org/content/dam/research/publications/library/2012/2012-04.pdf -->
<meta refines="{concat('#contributor',position())}" property="role" scheme="marc:relators">
<xsl:choose>
<xsl:when test="ContributorRole = 'A01'">aut</xsl:when>
<xsl:when test="ContributorRole = 'A02'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A03'">aus</xsl:when>
<xsl:when test="ContributorRole = 'A04'">lbt</xsl:when>
<xsl:when test="ContributorRole = 'A05'">lyr</xsl:when>
<xsl:when test="ContributorRole = 'A06'">cmp</xsl:when>
<xsl:when test="ContributorRole = 'A07'">art</xsl:when>
<xsl:when test="ContributorRole = 'A08'">pht</xsl:when>
<xsl:when test="ContributorRole = 'A09'">cre</xsl:when>
<xsl:when test="ContributorRole = 'A10'">cre</xsl:when>
<xsl:when test="ContributorRole = 'A11'">dsr</xsl:when>
<xsl:when test="ContributorRole = 'A12'">ill</xsl:when>
<xsl:when test="ContributorRole = 'A13'">pht</xsl:when>
<xsl:when test="ContributorRole = 'A14'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A15'">aui</xsl:when>
<xsl:when test="ContributorRole = 'A16'">aui</xsl:when>
<xsl:when test="ContributorRole = 'A17'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A18'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A19'">aft</xsl:when>
<xsl:when test="ContributorRole = 'A20'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A21'">cwt</xsl:when>
<xsl:when test="ContributorRole = 'A22'">aft</xsl:when>
<xsl:when test="ContributorRole = 'A23'">aui</xsl:when>
<xsl:when test="ContributorRole = 'A24'">aui</xsl:when>
<xsl:when test="ContributorRole = 'A25'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A27'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A29'">aui</xsl:when>
<xsl:when test="ContributorRole = 'A30'">prg</xsl:when>
<xsl:when test="ContributorRole = 'A31'">lyr</xsl:when>
<xsl:when test="ContributorRole = 'A32'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A33'">clb</xsl:when>
<xsl:when test="ContributorRole = 'A34'">ctb</xsl:when>
<xsl:when test="ContributorRole = 'A35'">ill</xsl:when>
<xsl:when test="ContributorRole = 'A36'">cov</xsl:when>
<xsl:when test="ContributorRole = 'A37'">ant</xsl:when>
<xsl:when test="ContributorRole = 'A38'">aut</xsl:when>
<xsl:when test="ContributorRole = 'A39'">ctg</xsl:when>
<xsl:when test="ContributorRole = 'A40'">ill</xsl:when>
<xsl:when test="ContributorRole = 'A43'">ivr</xsl:when>
<xsl:when test="ContributorRole = 'A44'">ive</xsl:when>
<xsl:when test="ContributorRole = 'A99'">cre</xsl:when>
<xsl:when test="ContributorRole = 'B01'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B02'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B03'">nrt</xsl:when>
<xsl:when test="ContributorRole = 'B04'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B05'">adp</xsl:when>
<xsl:when test="ContributorRole = 'B06'">trl</xsl:when>
<xsl:when test="ContributorRole = 'B07'">nrt</xsl:when>
<xsl:when test="ContributorRole = 'B08'">trl</xsl:when>
<xsl:when test="ContributorRole = 'B09'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B10'">trl</xsl:when>
<xsl:when test="ContributorRole = 'B11'">pbd</xsl:when>
<xsl:when test="ContributorRole = 'B12'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B13'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B14'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B15'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B16'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B18'">pbl</xsl:when>
<xsl:when test="ContributorRole = 'B19'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B20'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B21'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B23'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B24'">edt</xsl:when>
<xsl:when test="ContributorRole = 'B25'">arr</xsl:when>
<xsl:when test="ContributorRole = 'B99'">adp</xsl:when>
<xsl:when test="ContributorRole = 'C01'">com</xsl:when>
<xsl:when test="ContributorRole = 'C02'">com</xsl:when>
<xsl:when test="ContributorRole = 'C99'">com</xsl:when>
<xsl:when test="ContributorRole = 'D01'">pro</xsl:when>
<xsl:when test="ContributorRole = 'D02'">drt</xsl:when>
<xsl:when test="ContributorRole = 'D03'">cnd</xsl:when>
<xsl:when test="ContributorRole = 'D99'">drt</xsl:when>
<xsl:when test="ContributorRole = 'E01'">act</xsl:when>
<xsl:when test="ContributorRole = 'E02'">dnc</xsl:when>
<xsl:when test="ContributorRole = 'E03'">nrt</xsl:when>
<xsl:when test="ContributorRole = 'E04'">cmm</xsl:when>
<xsl:when test="ContributorRole = 'E05'">voc</xsl:when>
<xsl:when test="ContributorRole = 'E06'">itr</xsl:when>
<xsl:when test="ContributorRole = 'E07'">nrt</xsl:when>
<xsl:when test="ContributorRole = 'E08'">prf</xsl:when>
<xsl:when test="ContributorRole = 'E99'">prf</xsl:when>
<xsl:when test="ContributorRole = 'F01'">pht</xsl:when>
</xsl:choose>
</meta>
<meta refines="#creator" property="file-as">
<xsl:value-of select="PersonNameInverted" />
</meta>
</xsl:for-each>
<!-- dc:description https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dcmes-optional-def -->
<dc:description>
<xsl:value-of select="CollateralDetail/TextContent[TextType='02']/Text[@language='ita']" />
</dc:description>
<!-- dc:publisher https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dcmes-optional-def -->
<dc:publisher>
<xsl:value-of select="PublishingDetail/Publisher/PublisherName" />
</dc:publisher>
<!-- dc:rights https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dcmes-optional-def -->
<dc:rights>
<xsl:value-of select="concat('© ', PublishingDetail/Publisher[PublishingRole='01']/PublisherName, ' ', PublishingDetail/Publisher/Website[WebsiteRole='01'][1]/WebsiteLink)" />
</dc:rights>
<!-- dc:source https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dcmes-optional-def -->
<dc:source id="paper-version">
<xsl:value-of select="concat('urn:isbn:', RelatedMaterial/RelatedProduct[ProductRelationCode='13']/ProductIdentifier[ProductIDType='15']/IDValue)" />
</dc:source>
<meta property="identifier-type" refines="#paper-version" scheme="onix:codelist5">15</meta>
<!-- dc:subject https://www.w3.org/publishing/epub3/epub-packages.html#sec-opf-dcsubject -->
<xsl:for-each select="tokenize(DescriptiveDetail/Subject[SubjectSchemeIdentifier='20']/SubjectHeadingText, ';')">
<dc:subject>
<xsl:value-of select="normalize-space(.)" />
</dc:subject>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
@gregoriopellegrino
Copy link
Author

@jenstroeger: thanks, fixed!

Oh and I just noticed that dc:source (line 128) doesn’t generate a <meta refine>?

I don't think it is required: https://w3c.github.io/publ-epub-revision/epub32/spec/epub-packages.html#sec-source-of

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment