Commit e9984626 authored by Neveux Anais's avatar Neveux Anais

Merge branch 'master' of gitlab.utc.fr:crozatst/hdoc

parents b718f5dc 31638183
...@@ -54,7 +54,14 @@ Example : ...@@ -54,7 +54,14 @@ Example :
Currently available on: https://framemo.org/framapad_to_opale Currently available on: https://framemo.org/framapad_to_opale
See also : https://bimestriel.framapad.org/p/nf29_framapad_to_opale for the full documentation of our working process.
## TODO ## TODO
- Nested Lists
- Indentation
- Titles (and therefore Structure of the doc)
- Coloured text
- Code
- Markdown - Markdown
## Technical notes ## Technical notes
......
...@@ -6,11 +6,11 @@ ...@@ -6,11 +6,11 @@
xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"> exclude-result-prefixes="xs">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:param name="filename"/> <xsl:param name="filename"/>
<xsl:strip-space elements="*"/> <xsl:strip-space elements="*"/>
<!-- This template matches the root. One hdoc file = one Canoprof's Programme" --> <!-- This template matches the root. One hdoc file = one Canoprof's Programme" -->
<xsl:template match="h:html"> <xsl:template match="h:html">
<sc:item xmlns:sc="http://www.utc.fr/ics/scenari/v3/core"> <sc:item xmlns:sc="http://www.utc.fr/ics/scenari/v3/core">
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
</cp:program> </cp:program>
</sc:item> </sc:item>
</xsl:template> </xsl:template>
<!-- Head related templates. --> <!-- Head related templates. -->
<xsl:template match="h:head"> <xsl:template match="h:head">
<cp:programM> <cp:programM>
...@@ -28,22 +28,22 @@ ...@@ -28,22 +28,22 @@
<sp:title> <sp:title>
<xsl:value-of select="./h:title"/> <xsl:value-of select="./h:title"/>
</sp:title> </sp:title>
<!-- Hdoc's "date" = Programme's period. --> <!-- Hdoc's "date" = Programme's period. -->
<xsl:apply-templates select="./h:meta[@name='date']"/> <xsl:apply-templates select="./h:meta[@name='date']"/>
<!-- Hdoc's "description" = Programme's resume. --> <!-- Hdoc's "description" = Programme's resume. -->
<xsl:apply-templates select="./h:meta[@name='description']"/> <xsl:apply-templates select="./h:meta[@name='description']"/>
</cp:programM> </cp:programM>
</xsl:template> </xsl:template>
<xsl:template match="h:head/h:meta[@name='date']"> <xsl:template match="h:head/h:meta[@name='date']">
<sp:period> <sp:period>
<xsl:value-of select="./@content"/> <xsl:value-of select="./@content"/>
</sp:period> </sp:period>
</xsl:template> </xsl:template>
<xsl:template match="h:head/h:meta[@name='description']"> <xsl:template match="h:head/h:meta[@name='description']">
<sp:abstract> <sp:abstract>
<cp:txtDesc> <cp:txtDesc>
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
</sp:abstract> </sp:abstract>
</xsl:template> </xsl:template>
<!-- Body related templates. --> <!-- Body related templates. -->
<xsl:template match="h:body"> <xsl:template match="h:body">
<xsl:if test="./*"> <xsl:if test="./*">
...@@ -66,19 +67,216 @@ ...@@ -66,19 +67,216 @@
<!-- CanoProf's Activite TetM = hdoc's body/Section/Section = Opale's Grain --> <!-- CanoProf's Activite TetM = hdoc's body/Section/Section = Opale's Grain -->
<!-- CanoProf's Activite TetM (section) = hdoc's body/Section/Section/(Section...) = Opale's Grain (partie) --> <!-- CanoProf's Activite TetM (section) = hdoc's body/Section/Section/(Section...) = Opale's Grain (partie) -->
<!-- TODO :CanoProf's Seance = hdoc's body/Section = Opale's Division --> <!-- CanoProf's Seance = hdoc's body/Section = Opale's Division or Activite-->
<xsl:template match="h:body/h:section"> <xsl:template match="h:body/h:section">
<xsl:if test="./*">
<sp:session>
<cp:session>
<cp:sessionM>
<sp:title>
<xsl:if test="not(./h:header/h:h1/text())"> Untitled </xsl:if>
<xsl:value-of select="./h:header/h:h1"/>
</sp:title>
</cp:sessionM>
<xsl:apply-templates select="./*"/>
</cp:session>
</sp:session>
</xsl:if>
</xsl:template> </xsl:template>
<!-- TODO : if Section have only a dev (no sub section), we create a short activty to print text into a seance --> <!-- if Section have only a dev (no sub section), we create a short activty to print text into a seance -->
<xsl:template match="h:body/h:section/h:div"> <xsl:template match="h:body/h:section/h:div">
<sp:shortActivity>
<cp:shortActivity>
<cp:activityM>
<sp:title>
<xsl:value-of select="../h:header/h:h1"/>
</sp:title>
</cp:activityM>
<sp:body>
<cp:flow>
<xsl:apply-templates select="./*"/>
</cp:flow>
</sp:body>
</cp:shortActivity>
</sp:shortActivity>
</xsl:template>
<!-- Toutes les introductions de sections sont transformés en résumé. -->
<xsl:template match="h:header/h:div[@data-hdoc-type = 'introduction']">
<sp:abstract>
<cp:txtDesc>
<sc:para xml:space="preserve">
<xsl:value-of select="./text()"/>
</sc:para>
</cp:txtDesc>
</sp:abstract>
</xsl:template>
<!-- Text related templates -->
<xsl:template match="h:p | h:ul | h:ol">
<xsl:if test="not(preceding-sibling::h:p)">
<xsl:if test="not(preceding-sibling::h:ul)">
<xsl:if test="not(preceding-sibling::h:ol)">
<xsl:choose>
<!-- If it is directly included in a div, we have to add Canoprof's text markups -->
<xsl:when test="parent::*[name() = 'div']">
<sp:txt>
<cp:txt>
<xsl:call-template name="blockloop"/>
</cp:txt>
</sp:txt>
</xsl:when>
<!-- Otherwise, we can directly display it (this can happen when it is included within a list or a table) -->
<xsl:otherwise>
<xsl:call-template name="blockloop"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="blockloop">
<xsl:for-each select=". | ./following-sibling::*">
<xsl:choose>
<!-- Paragraph -->
<xsl:when test="name() = 'p' and (./* | ./text())">
<sc:para xml:space="preserve">
<xsl:apply-templates select="./* | ./text()"/>
</sc:para>
</xsl:when>
<!-- Unordered list -->
<xsl:when test="name() = 'ul' and (./h:li/h:p/text())">
<sc:itemizedList>
<xsl:apply-templates select="./* | ./text()"/>
</sc:itemizedList>
</xsl:when>
<!-- Ordered list -->
<xsl:when test="name() = 'ol' and (./h:li/h:p/text())">
<sc:orderedList>
<xsl:apply-templates select="./* | ./text()"/>
</sc:orderedList>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template> </xsl:template>
<!-- TODO : CanoProf's Activite TetM = hdoc's body/Section/Section = Opale's Grain --> <xsl:template match="h:li">
<xsl:template match="h:body/h:section/h:section"> <sc:listItem>
<xsl:apply-templates select="./* | ./text()"/>
</sc:listItem>
</xsl:template> </xsl:template>
<xsl:template match="h:i">
<xsl:if test="./* | ./text()">
<sc:inlineStyle role="specific">
<xsl:apply-templates select="./* | ./text()"/>
</sc:inlineStyle>
</xsl:if>
</xsl:template>
<xsl:template match="h:em">
<xsl:if test="./* | ./text()">
<sc:inlineStyle role="emphasis">
<xsl:apply-templates select="./* | ./text()"/>
</sc:inlineStyle>
</xsl:if>
</xsl:template>
<xsl:template match="h:q">
<xsl:if test="./* | ./text()">
<sc:phrase role="quote">
<xsl:apply-templates select="./* | ./text()"/>
</sc:phrase>
</xsl:if>
</xsl:template>
<xsl:template match="h:sub">
<xsl:if test="./* | ./text()">
<sc:textLeaf role="ind">
<xsl:apply-templates select="./* | ./text()"/>
</sc:textLeaf>
</xsl:if>
</xsl:template>
<xsl:template match="h:sup">
<xsl:if test="./* | ./text()">
<sc:textLeaf role="exp">
<xsl:apply-templates select="./* | ./text()"/>
</sc:textLeaf>
</xsl:if>
</xsl:template>
<xsl:template match="h:a">
<xsl:if test="./* | ./text()">
<sc:phrase role="url">
<cp:link xmlns:sc="http://www.utc.fr/ics/scenari/v3/core"
xmlns:cp="canope.fr:canoprof"
xmlns:sp="http://www.utc.fr/ics/scenari/v3/primitive">
<sp:url>
<xsl:value-of select="./@href"/>
</sp:url>
</cp:link>
<xsl:if test="./@title">
<sp:title>
<xsl:value-of select="./@title"/>
</sp:title>
</xsl:if>
<xsl:value-of select="."/>
</sc:phrase>
</xsl:if>
</xsl:template>
<!-- Table related templates -->
<xsl:template match="h:table">
<xsl:choose>
<xsl:when test="parent::*[name() = 'div']">
<!-- If this <table> is a direct child of a <div> then it must be surrounded by Opale's text markups. -->
<sp:txt>
<cp:txt>
<sc:table>
<xsl:if test="./h:caption">
<sc:caption>
<xsl:value-of select="./h:caption"/>
</sc:caption>
</xsl:if>
<xsl:apply-templates select="./h:tr"/>
</sc:table>
</cp:txt>
</sp:txt>
</xsl:when>
<xsl:otherwise>
<sc:table>
<xsl:if test="./h:caption">
<sc:caption>
<xsl:value-of select="./h:caption"/>
</sc:caption>
</xsl:if>
<xsl:apply-templates select="./h:tr"/>
</sc:table>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="h:tr">
<sc:row>
<xsl:apply-templates select="./h:td"/>
</sc:row>
</xsl:template>
<xsl:template match="h:td">
<sc:cell>
<xsl:apply-templates select="./*"/>
</sc:cell>
</xsl:template>
<xsl:template match="h:header"/>
<!-- Its content is already used in <xsl:template match="h:section"> -->
<xsl:template match="h:h6"/>
<!-- Its content is already used in <xsl:template match="h:div"> -->
<xsl:template match="h:h1"/>
<!-- Its content is already used in <xsl:template match="h:section"> -->
</xsl:stylesheet> </xsl:stylesheet>
libdir=${basedir}/lib libdir=${basedir}/lib
xsldir=${basedir}/xsl xsldir=${basedir}/xsl
inputPath=${basedir}/input inputPath=${basedir}/input
outputPath=${basedir}/output tmpHdoc=${basedir}/tmp_hdoc
\ No newline at end of file outputPath=${basedir}/output
<project name="hdoc_to_elasticsearch" default="unzipSource"> <project name="hdoc_to_elasticsearch" default="clean">
<property file="build.properties"/> <property file="build.properties"/>
<target name="unzipSource">
<target name="unzipSource">
<echo message="Conversion begin" /> <echo message="Conversion begin" />
<path id="hdocDirPath"> <path id="hdocDirPath">
<fileset dir="${inputPath}" id="hdocFile"> <fileset dir="${inputPath}" id="hdocFile">
<include name="*.hdoc"/> <include name="*.hdoc"/>
</fileset> </fileset>
</path> </path>
<property name="hdocFile" refId="hdocDirPath"/>
<property name="hdocFile" refId="hdocDirPath"/>
<basename property="hdocFileName" file="${hdocFile}" suffix=".hdoc"/> <basename property="hdocFileName" file="${hdocFile}" suffix=".hdoc"/>
<echo>Entry file : ${hdocFileName}</echo>
<echo>Entry file : ${hdocFileName}</echo>
<!-- create subdirectory for each file --> <!-- create subdirectory for each file -->
<mkdir dir="${outputPath}/${hdocFileName}"/> <mkdir dir="${tmpHdoc}/${hdocFileName}"/>
<!--unzips the hdoc to be converted into the previously created directory--> <!--unzips the hdoc to be converted into the previously created directory-->
<unzip dest="${outputPath}/${hdocFileName}"> <unzip dest="${tmpHdoc}/${hdocFileName}">
<fileset dir="${inputPath}" id="hdocFile"> <fileset dir="${inputPath}" id="hdocFile">
<include name="${hdocFileName}.hdoc"/> <include name="${hdocFileName}.hdoc"/>
</fileset> </fileset>
</unzip> </unzip>
<echo message="Conversion end" />
</target> </target>
<target name="jsonFiles" depends="unzipSource"> <target name="jsonFiles" depends="unzipSource">
<echo message="JSON File creation" /> <echo message="JSON File creation" />
<!-- TODO : create JSON & extract data --> <xslt in="${tmpHdoc}/${hdocFileName}/content.xml" out="${outputPath}/${hdocFileName}.json" style="xsl/content_extractor.xsl"/>
</target> </target>
<!-- Clear tmp files --> <!-- Clear tmp files -->
<target name="clean" depends="jsonFiles"> <target name="clean" depends="jsonFiles">
<echo message="Clean files" />
</target> <!-- -->
<delete includeemptydirs="true" verbose="true">
<fileset dir="${tmpHdoc}"> </fileset>
<dirset dir="${tmpHdoc}" includes="**/*" />
</delete>
<echo message="Conversion end" />
</target>
</project>
<echo message="Conversion end" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://www.utc.fr/ics/hdoc/xhtml"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output omit-xml-declaration="yes"
encoding="UTF-8">
<!-- Encodage UTF-8 pour caractères spéciaux (accents...) -->
</xsl:output>
<!-- -->
<xsl:template match="/" >
{
<xsl:apply-templates select="html"/>
}
</xsl:template>
<!-- Extraction des informations du head -->
<xsl:template match="head">
"title" : "<xsl:value-of select="title/text()"/>",
"keywords" : [
<xsl:for-each select="meta[@name='keywords']">
"<xsl:value-of select="@content"/>"<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
],
<xsl:apply-templates select="meta"/>
</xsl:template>
<!-- Extraction des informations du body -->
<xsl:template match="body" />
<xsl:template match="meta[@name='author']">
"author" : "<xsl:value-of select="@content"/>"
</xsl:template>
<xsl:template match="meta[@name='date']">
"date" : "<xsl:value-of select="@content"/>",
</xsl:template>
<xsl:template match="meta[@name='rights']">
"rights" : "<xsl:value-of select="@content"/>",
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
...@@ -35,15 +35,23 @@ La personne possède un hdoc et voudrait le convertir en epub. Il se dirige vers ...@@ -35,15 +35,23 @@ La personne possède un hdoc et voudrait le convertir en epub. Il se dirige vers
Unsupported Unsupported
----------- -----------
Known bugs Known bugs
---------- ----------
Problème dans le hdoc : contient des images mais ne sont pas référencées.
Problème avec les keywords : le hdoc contient des keywords mais nous ne savons pas où les utiliser.
Todo list Todo list
--------- ---------
Validation de l'epub actuel
Mise en place de la première page
Validation
Étude compatibilité entre EPUB2 et EPUB3
Technical Notes Technical Notes
--------------- ---------------
<?xml version="1.0"?> <?xml version="1.0"?>
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0"> <container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
<rootfiles> <rootfiles>
<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/> <rootfile full-path="oebps/content.opf" media-type="application/oebps-package+xml"/>
</rootfiles> </rootfiles>
</container> </container>
...@@ -7,9 +7,12 @@ ...@@ -7,9 +7,12 @@
<property name="in" location="${basedir}/input"/> <property name="in" location="${basedir}/input"/>
<property name="out" location="${basedir}/output"/> <property name="out" location="${basedir}/output"/>
<property name="tmp" location="${basedir}/tmp"/> <property name="tmp" location="${basedir}/tmp"/>
<property name="xsl" location="${basedir}/xsl"/>
<property name="file" location="${basedir}/file"/> <property name="file" location="${basedir}/file"/>
<property name="schema" location="${basedir}/schema"/> <property name="schema" location="${basedir}/schema"/>
<property name="lib" location="${basedir}/lib"/>
<property name="tmpRetour" location="${basedir}/tmp/retour"/>
<target name="convert"> <target name="convert">
<delete dir="${tmp}" failonerror="false"/> <delete dir="${tmp}" failonerror="false"/>
<sleep seconds="1"/> <sleep seconds="1"/>
...@@ -18,6 +21,8 @@ ...@@ -18,6 +21,8 @@
<delete dir="${out}" failonerror="false"/> <delete dir="${out}" failonerror="false"/>
<sleep seconds="1"/> <sleep seconds="1"/>
<mkdir dir="${out}"/> <mkdir dir="${out}"/>
<mkdir dir="${tmpRetour}"/>
<for param="inputFile"> <for param="inputFile">
<path> <path>
...@@ -27,7 +32,7 @@ ...@@ -27,7 +32,7 @@
<sequential> <sequential>
<local name="filename"/> <local name="filename"/>
<basename property="filename" file="@{inputFile}"/> <basename property="filename" file="@{inputFile}"/>
<antcall target="UnzipHdocFile"> <antcall target="UnzipHdocFile">
<param name="filename" value="${filename}"/> <param name="filename" value="${filename}"/>
</antcall> </antcall>
...@@ -36,12 +41,27 @@ ...@@ -36,12 +41,27 @@
<param name="filename" value="${filename}"/> <param name="filename" value="${filename}"/>
</antcall> </antcall>
<antcall target="MakeOCF"/> <antcall target="MakeOCF">
<param name="filename" value="${filename}"/>
</antcall>
<!--<antcall target="MakeOPF"/> --> <antcall target="MakeOPF">
<param name="filename" value="${filename}"/>
</antcall>
<antcall target="MakeOPS">
<param name="filename" value="${filename}"/>
</antcall>
<antcall target="MakeOPS"/> <antcall target="ZipEpubFile">
<param name="filename" value="${filename}"/>
</antcall>
<antcall target="ValidateOutput">
<param name="filename" value="${filename}"/>
</antcall>
<antcall target="CleanTmp"/>
</sequential> </sequential>
</for> </for>
</target> </target>
...@@ -66,20 +86,49 @@ ...@@ -66,20 +86,49 @@
</target> </target>
<target name="MakeOCF"> <target name="MakeOCF">
<mkdir dir="${out}/META-INF"/> <mkdir dir="${tmpRetour}/META-INF"/>
<mkdir dir="${out}/oebps"/> <mkdir dir="${tmpRetour}/oebps"/>
<copy file="${file}/mimetype" todir="${out}"/> <copy file="${file}/mimetype" todir="${tmpRetour}"/>
<copy file="${file}/container.xml" todir="${out}/META-INF"/> <copy file="${file}/container.xml" todir="${tmpRetour}/META-INF"/>
</target> </target>
<target name="MakeOPF"> <target name="MakeOPF">
<xslt in="${tmp}/${filename}/decompressedHdoc/content.xml" out="${tmpRetour}/oebps/content.opf" classpath="${lib}/saxon9he.jar" style="${xsl}/content.xsl"/>
</target> </target>
<target name="MakeOPS"> <target name="MakeOPS">
<mkdir dir="${out}/oebps/images"/> <mkdir dir="${tmpRetour}/oebps/images"/>
<mkdir dir="${out}/oebps/styles"/> <copy todir="${tmpRetour}/oebps/images">
<mkdir dir="${out}/oebps/text"/> <fileset dir="${tmp}/${filename}/decompressedHdoc/re" includes="**"/>
</copy>
<mkdir dir="${tmpRetour}/oebps/styles"/>
<mkdir dir="${tmpRetour}/oebps/chapitres"/>
<xslt in="${tmp}/${filename}/decompressedHdoc/content.xml" out="${tmpRetour}/oebps/tableDesMatieres.ncx" classpath="${lib}/saxon9he.jar" style="${xsl}/tdmncx.xsl"/>
<xslt destdir="${tmpRetour}/oebps/chapitres" basedir="${tmp}/${filename}/decompressedHdoc" includes="content.xml" classpath="${lib}/saxon9he.jar" style="${xsl}/chapitre.xsl"/>
<delete file="${tmpRetour}/oebps/chapitres/content.html"/>
</target> </target>
<target name="ZipEpubFile">
<propertyregex property="properFilename" input="${filename}" regexp=".hdoc" replace="" casesensitive="false" override="true" />
<zip destfile="${out}/${properFilename}.epub" update="true" encoding="UTF-8">
<zipfileset dir="${tmpRetour}/META-INF"
includes="*" prefix="META-INF"/>
<zipfileset dir="${tmpRetour}/oebps"
includes="**" prefix="oebps"/>
</zip>
<!-- zip64Mode="never" -->
<zip destfile="${out}/${properFilename}.epub" update="true" compress="false" encoding="UTF-8" keepcompression="true" createunicodeextrafields="never">
<zipfileset dir="${tmpRetour}"
includes="mimetype"/>
</zip>
</target>
<target name="ValidateOutput">
</target>
<target name="CleanTmp">
<delete dir="${tmp}" failonerror="false"/>
</target>
</project> </project>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
xpath-default-namespace="http://www.utc.fr/ics/hdoc/xhtml"
xmlns="http://www.w3.org/1999/xhtml"
version="2.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="/html" priority="10">
<xsl:for-each select="body/section">
<xsl:variable name="path">../../../retour/oebps/chapitres/chapitre<xsl:number level="multiple" count="section" format="1"/>.xhtml</xsl:variable>
<xsl:result-document method="xml" href="{$path}">
<html xml:lang="en" lang="en" xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<title><xsl:value-of select="header/h1"/></title>
</head>
<body>
<h1><xsl:value-of select="header/h1"/></h1>
<xsl:apply-templates select="div|section"/>
</body>
</html>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
<xsl:template match="section" priority="3">
<xsl:element name="h{count(ancestor::section)+1}">
<xsl:value-of select="header/h1"/>
<xsl:apply-templates select="div|section"/>
</xsl:element>
</xsl:template>
<!-- Identity transformation -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- Namespace substitution for hdoc elements -->
<xsl:template match="*" priority="1">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:dc="http://www.idpf.org/2007/opf"
xpath-default-namespace="http://www.utc.fr/ics/hdoc/xhtml"
exclude-result-prefixes="xs"
version="2.0">
<xsl:import href="content/metadata.xsl"/>
<xsl:import href="content/manifest.xsl"/>
<xsl:import href="content/spine.xsl"/>
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="html">