<p:declare-step xmlns:p="http://www.w3.org/ns/xproc" xmlns:pf="http://www.daisy.org/ns/pipeline/functions" xmlns:px="http://www.daisy.org/ns/pipeline/xproc" xmlns:cx="http://xmlcalabash.com/ns/extensions" xmlns:c="http://www.w3.org/ns/xproc-step" xmlns:d="http://www.daisy.org/ns/pipeline/data" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:html="http://www.w3.org/1999/xhtml" version="1.0" type="px:html-to-epub3" name="main" exclude-inline-prefixes="#all"> <p:documentation>Transforms XHTML into an EPUB 3 publication.</p:documentation> <p:input port="input.fileset" primary="true"/> <p:input port="input.in-memory" sequence="true"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Input HTML document(s) and resources</p> <p>If the fileset includes a navigation document, it should be marked with a <code>role</code> attribute with value <code>nav</code>, and it should be a HTML document. At most one navigation document may be specified. If no navigation document is specified, one is generated from all the HTML documents.</p> <p>If the fileset includes a <a href="http://www.idpf.org/epub/301/spec/epub-publications.html#cover-image"><code>cover-image</code></a>, it should be marked with a <code>role</code> attribute with value <code>cover-image</code>.</p> </p:documentation> </p:input> <p:input port="metadata" sequence="true"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Metadata</p> </p:documentation> <p:empty/> </p:input> <p:input port="tts-config"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>TTS configuration file</p> <p>Configuration file with voice mappings, PLS lexicons and annotations.</p> </p:documentation> <p:inline><d:config/></p:inline> </p:input> <p:option name="stylesheet" select="''"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>CSS style sheets as space separated list of absolute URIs.</p> </p:documentation> </p:option> <p:option name="epub-stylesheet" cx:as="xs:string*" select="()"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>CSS style sheets to be attached to the HTML documents of the EPUB.</p> <p>Sequence of absolute URIs of files that exist on disk.</p> </p:documentation> </p:option> <p:option name="lexicon" cx:as="xs:anyURI*" select="()"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>PLS lexicons as list of absolute URIs.</p> </p:documentation> </p:option> <p:output port="fileset.out" primary="true"> <p:pipe step="ocf" port="fileset"/> </p:output> <p:output port="in-memory.out" sequence="true"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>The EPUB 3 publication (not zipped)</p> </p:documentation> <p:pipe step="ocf" port="in-memory"/> </p:output> <p:output port="status" px:media-type="application/vnd.pipeline.status+xml"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Status of the TTS step and EPUB validation.</p> <p>A <code>result</code> attribute indicates whether both the TTS step and the EPUB validation were successful ("ok"), or whether at least one of them failed ("error").</p> <p>A <code>tts-success-rate</code> attribute contains the percentage of the input text that got successfully converted to speech.</p> </p:documentation> <p:pipe step="status" port="result"/> </p:output> <p:output port="temp-audio-files"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <h2>List of audio files</h2> <p>List of audio files generated by the TTS step. May be deleted when the result fileset is stored.</p> </p:documentation> <p:pipe step="add-mediaoverlays" port="temp-audio.fileset"/> </p:output> <p:option name="include-tts-log" select="'false'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Whether or not to make the TTS log available on the "tts-log" port.</p> </p:documentation> </p:option> <p:output port="tts-log" sequence="true"> <p:pipe step="tts" port="log"/> </p:output> <p:option name="output-dir" required="true"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Root directory of the (expanded) EPUB 3.</p> </p:documentation> </p:option> <p:option name="package-doc-path" required="false" select="'EPUB/package.opf'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>File path, relative to the root directory of the package document.</p> </p:documentation> </p:option> <p:option name="navigation-doc-path" required="false" select="'EPUB/toc.xhtml'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>File path, relative to the root directory, of the navigation document, if it is generated.</p> </p:documentation> </p:option> <p:option name="content-path" required="false" select="'EPUB/'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>File path, relative to the root directory, of the directory that will contain all files except <code>mimetype</code>, the files that need to be in <code>META-INF</code>, and the package and navigation documents which have their own setting.</p> </p:documentation> </p:option> <p:option name="css-path" required="false" cx:as="xs:string?" select="()"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>File path, relative to the content directory, of the directory that will contain the CSS style sheets specified through the epub-stylesheet option, and all other style sheets and resources references from it.</p> <p>It is an error if an epub-stylesheet is specified without settings this option.</p> </p:documentation> </p:option> <p:option name="temp-dir" select="''"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Empty directory dedicated to this conversion. May be left empty in which case temporary directories will be automatically created where needed.</p> </p:documentation> </p:option> <p:option name="output-validation" cx:type="off|report|abort" select="'off'"> <p:documentation> Determines whether to validate the EPUB output and what to do on validation errors. Defaults to 'off'. </p:documentation> </p:option> <p:option name="skip-cleanup" required="false" select="'false'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Skip the HTML upgrade and clean up steps.</p> </p:documentation> </p:option> <p:option name="audio" required="false" select="'false'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Enable TTS</p> <p>Whether to use a speech synthesizer to produce audio files.</p> </p:documentation> </p:option> <p:option name="audio-file-type" select="'audio/mpeg'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>The desired file type of the generated audio files, specified as a MIME type.</p> <p>Examples:</p> <ul> <li>"audio/mpeg"</li> <li>"audio/x-wav" (but note that this is not a core media type)</li> </ul> </p:documentation> </p:option> <p:option name="process-css" required="false" select="'true'"> <p:documentation xmlns="http://www.w3.org/1999/xhtml"> <p>Set to false to bypass aural CSS processing.</p> </p:documentation> </p:option> <p:import href="http://www.daisy.org/pipeline/modules/epub-utils/library.xpl"> <p:documentation> px:epub3-safe-uris px:epub3-ensure-core-media px:epub3-add-navigation-doc px:epub3-create-mediaoverlays px:epub3-create-package-doc px:epub3-ocf-finalize px:epub-validate px:tts-for-epub3 </p:documentation> </p:import> <p:import href="http://www.daisy.org/pipeline/modules/css-utils/library.xpl"> <p:documentation> px:css-to-fileset </p:documentation> </p:import> <p:import href="http://www.daisy.org/pipeline/modules/file-utils/library.xpl"> <p:documentation> px:set-base-uri </p:documentation> </p:import> <p:import href="http://www.daisy.org/pipeline/modules/fileset-utils/library.xpl"> <p:documentation> px:fileset-load px:fileset-join px:fileset-rebase px:fileset-purge px:fileset-update px:fileset-filter-in-memory px:fileset-add-entry </p:documentation> </p:import> <p:import href="http://www.daisy.org/pipeline/modules/common-utils/library.xpl"> <p:documentation> px:assert px:tokenize </p:documentation> </p:import> <p:import href="http://www.daisy.org/pipeline/modules/html-utils/library.xpl"> <p:documentation> px:html-fixer px:html-upgrade </p:documentation> </p:import> <p:import href="http://www.daisy.org/pipeline/modules/zedai-to-html/library.xpl"> <p:documentation> px:diagram-to-html </p:documentation> </p:import> <p:import href="html-to-opf-metadata.xpl"> <p:documentation> px:html-to-opf-metadata </p:documentation> </p:import> <cx:import href="http://www.daisy.org/pipeline/modules/file-utils/uri-functions.xsl" type="application/xslt+xml"> <p:documentation> pf:normalize-uri pf:longest-common-uri </p:documentation> </cx:import> <p:variable name="content-dir" select="pf:normalize-uri(concat($output-dir,$content-path,'/'))"> <p:empty/> </p:variable> <px:assert message="'css-path' option is mandatory when an 'epub-stylesheet' is specified" error-code="XXXXX"> <p:with-option name="test" select="not(exists($epub-stylesheet)) or exists($css-path)"/> </px:assert> <p:documentation>Move to EPUB/ directory</p:documentation> <px:fileset-rebase> <p:with-option name="new-base" select="pf:longest-common-uri(//d:file/resolve-uri(@href,base-uri(.)))"/> </px:fileset-rebase> <px:fileset-copy name="move"> <p:input port="source.in-memory"> <p:pipe step="main" port="input.in-memory"/> </p:input> <p:with-option name="target" select="$content-dir"/> </px:fileset-copy> <px:diagram-to-html name="diagram-to-html" px:progress=".05"> <p:input port="source.in-memory"> <p:pipe step="move" port="result.in-memory"/> </p:input> </px:diagram-to-html> <p:choose name="clean" px:progress=".1"> <p:when test="$skip-cleanup='true'"> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="diagram-to-html" port="result.in-memory"/> </p:output> <p:identity/> </p:when> <p:otherwise> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="clean-resource-refs" port="result.in-memory"/> </p:output> <p:documentation>Remove resources that do not exist on disk or in memory</p:documentation> <px:fileset-purge> <p:documentation>Also normalizes @href, @original-href and @xml:base</p:documentation> <p:input port="source.in-memory"> <p:pipe step="diagram-to-html" port="result.in-memory"/> </p:input> </px:fileset-purge> <p:documentation>Change @href with EPUB-safe URIs</p:documentation> <px:epub3-safe-uris name="safe-uris"> <p:input port="source.in-memory"> <p:pipe step="diagram-to-html" port="result.in-memory"/> </p:input> </px:epub3-safe-uris> <p:group name="clean-html"> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="update" port="result.in-memory"/> </p:output> <px:fileset-load media-types="application/xhtml+xml" name="html"> <p:input port="in-memory"> <p:pipe step="safe-uris" port="result.in-memory"/> </p:input> </px:fileset-load> <px:assert message="No XHTML documents found." test-count-min="1" error-code="PEZE00"/> <p:for-each> <p:documentation>Upgrade to XHTML 5</p:documentation> <px:html-upgrade/> <p:documentation>Clean http-equiv</p:documentation> <p:delete match="/html:html/html:head/html:meta[matches(@http-equiv,'Content-Type','i')]"/> <p:documentation>Set language</p:documentation> <p:group> <p:variable name="lang" select="/*/(if (@lang|@xml:lang) then (@lang|@xml:lang)[1] else p:system-property('p:language'))"/> <p:add-attribute match="/*" attribute-name="lang"> <p:with-option name="attribute-value" select="$lang"/> </p:add-attribute> <p:add-attribute match="/*" attribute-name="xml:lang"> <p:with-option name="attribute-value" select="$lang"/> </p:add-attribute> </p:group> <p:documentation>Fix content models</p:documentation> <px:html-fixer/> <p:documentation>Clean outline</p:documentation> </p:for-each> <p:identity name="xhtml5.in-memory"/> <p:sink/> <p:documentation>Fix doctype</p:documentation> <p:add-attribute match="d:file" attribute-name="doctype" attribute-value="<!DOCTYPE html>" name="xhtml5.fileset"> <p:input port="source"> <p:pipe step="html" port="result.fileset"/> </p:input> </p:add-attribute> <p:sink/> <px:fileset-update name="update"> <p:input port="source.fileset"> <p:pipe step="safe-uris" port="result.fileset"/> </p:input> <p:input port="source.in-memory"> <p:pipe step="safe-uris" port="result.in-memory"/> </p:input> <p:input port="update.fileset"> <p:pipe step="xhtml5.fileset" port="result"/> </p:input> <p:input port="update.in-memory"> <p:pipe step="xhtml5.in-memory" port="result"/> </p:input> </px:fileset-update> </p:group> <p:documentation>Clean resource references</p:documentation> <px:epub3-ensure-core-media name="clean-resource-refs"> <p:input port="source.in-memory"> <p:pipe step="clean-html" port="in-memory"/> </p:input> </px:epub3-ensure-core-media> </p:otherwise> </p:choose> <px:fileset-diff> <p:input port="secondary"> <p:pipe step="diagram-to-html" port="mapping"/> </p:input> </px:fileset-diff> <px:fileset-load media-types="application/xhtml+xml" name="content-docs-except-nav-and-diagram"> <p:input port="in-memory"> <p:pipe step="clean" port="in-memory"/> </p:input> </px:fileset-load> <p:sink/> <p:documentation>Generate the EPUB 3 navigation document</p:documentation> <px:epub3-add-navigation-doc name="add-navigation-doc" px:progress=".05"> <p:input port="source.fileset"> <p:pipe step="clean" port="fileset"/> </p:input> <p:input port="source.in-memory"> <p:pipe step="clean" port="in-memory"/> </p:input> <p:input port="content"> <p:pipe step="content-docs-except-nav-and-diagram" port="result.fileset"/> </p:input> <p:with-option name="output-base-uri" select="concat($output-dir,$navigation-doc-path)"/> </px:epub3-add-navigation-doc> <p:identity px:message="Navigation Document Created."/> <p:group name="attach-css"> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="update" port="result.in-memory"/> </p:output> <p:sink/> <px:fileset-load name="load-spine"> <p:input port="fileset"> <p:pipe step="content-docs-except-nav-and-diagram" port="result.fileset"/> </p:input> <p:input port="in-memory"> <p:pipe step="add-navigation-doc" port="result.in-memory"/> </p:input> </px:fileset-load> <p:for-each> <p:xslt> <p:input port="stylesheet"> <p:document href="attach-css.xsl"/> </p:input> <p:with-param name="stylesheet-links" select="//d:file[@role='stylesheet']/resolve-uri(@href,base-uri(.))"> <p:pipe step="css" port="fileset"/> </p:with-param> </p:xslt> </p:for-each> <p:identity name="html-with-css-link"/> <p:sink/> <p:group name="css"> <p:output port="fileset"/> <p:documentation>CSS style sheets to be attached to the HTML documents, together with any referenced resources (fonts, images, imported style sheets). The top-level files are marked with a <code>role</code> attribute with value <code>stylesheet</code>. The order of the style sheets in the fileset determines the order in which <code>link</code> elements are inserted in the HTML.</p:documentation> <px:tokenize regex="\s+"> <p:with-option name="string" select="string-join($epub-stylesheet,' ')"/> </px:tokenize> <p:for-each> <p:variable name="href" select="string(.)"/> <px:fileset-create> <p:with-option name="base" select="resolve-uri('./',$href)"/> </px:fileset-create> <px:fileset-add-entry media-type="text/css"> <p:with-option name="href" select="$href"/> </px:fileset-add-entry> <p:add-attribute match="d:file[@media-type='text/css']" attribute-name="role" attribute-value="stylesheet"/> <px:css-to-fileset> </px:css-to-fileset> <px:fileset-copy name="copy"> <p:documentation>Copy all style sheets to a common place. This will raise an error if some referenced resources fall outside the directory that contains the style sheet.</p:documentation> <p:with-option name="target" select="pf:normalize-uri(concat($content-dir,$css-path,'/'))"/> </px:fileset-copy> </p:for-each> <px:fileset-join/> <px:epub3-safe-uris/> </p:group> <p:sink/> <px:fileset-join> <p:input port="source"> <p:pipe step="add-navigation-doc" port="result.fileset"/> <p:pipe step="css" port="fileset"/> </p:input> </px:fileset-join> <px:fileset-update name="update"> <p:input port="source.in-memory"> <p:pipe step="add-navigation-doc" port="result.in-memory"/> </p:input> <p:input port="update.fileset"> <p:pipe step="load-spine" port="result.fileset"/> </p:input> <p:input port="update.in-memory"> <p:pipe step="html-with-css-link" port="result"/> </p:input> </px:fileset-update> </p:group> <px:tts-for-epub3 name="tts" px:progress=".6"> <p:input port="source.in-memory"> <p:pipe step="attach-css" port="in-memory"/> </p:input> <p:input port="config"> <p:pipe step="main" port="tts-config"/> </p:input> <p:with-option name="stylesheet" select="$stylesheet"/> <p:with-option name="lexicon" select="$lexicon"/> <p:with-option name="audio" select="$audio"/> <p:with-option name="audio-file-type" select="$audio-file-type"/> <p:with-option name="process-css" select="$process-css"/> <p:with-option name="temp-dir" select="if ($temp-dir='') then '' else concat($temp-dir,'tts/')"/> </px:tts-for-epub3> <p:documentation>Add SMIL and audio files</p:documentation> <p:group name="add-mediaoverlays" px:progress=".05"> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="tts" port="result.in-memory"/> <p:pipe step="mo" port="result.in-memory"/> </p:output> <p:output port="temp-audio.fileset"> <p:pipe step="mo" port="original-audio.fileset"/> </p:output> <p:documentation>Generate SMIL files and copy audio files</p:documentation> <px:epub3-create-mediaoverlays flatten="true" name="mo"> <p:input port="source.in-memory"> <p:pipe step="tts" port="result.in-memory"/> </p:input> <p:input port="audio-map"> <p:pipe step="tts" port="audio-map"/> </p:input> <p:with-option name="mediaoverlay-dir" select="concat($content-dir,'mo/')"> <p:empty/> </p:with-option> <p:with-option name="audio-dir" select="concat($content-dir,'audio/')"> <p:empty/> </p:with-option> </px:epub3-create-mediaoverlays> <p:sink/> <px:fileset-join> <p:input port="source"> <p:pipe step="tts" port="result.fileset"/> <p:pipe step="mo" port="result.fileset"/> </p:input> </px:fileset-join> </p:group> <p:sink/> <p:documentation>Extract metadata</p:documentation> <p:split-sequence test="position()=1"> <p:input port="source"> <p:pipe step="content-docs-except-nav-and-diagram" port="result"/> </p:input> </p:split-sequence> <px:html-to-opf-metadata name="metadata" px:progress=".05"/> <p:sink/> <p:documentation>Generate the EPUB 3 package document</p:documentation> <p:group name="add-package-doc" px:progress=".05"> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="add-mediaoverlays" port="in-memory"/> <p:pipe step="package-doc" port="result"/> </p:output> <px:epub3-create-package-doc compatibility-mode="false" name="create-package-doc"> <p:input port="source.fileset"> <p:pipe step="add-mediaoverlays" port="fileset"/> </p:input> <p:input port="source.in-memory"> <p:pipe step="add-mediaoverlays" port="in-memory"/> </p:input> <p:input port="spine"> <p:pipe step="content-docs-except-nav-and-diagram" port="result.fileset"/> </p:input> <p:input port="metadata"> <p:pipe step="main" port="metadata"/> <p:pipe step="metadata" port="result"/> </p:input> <p:with-option name="output-base-uri" select="concat($output-dir,$package-doc-path)"/> </px:epub3-create-package-doc> <p:identity name="package-doc" px:message="Package Document Created."/> <p:sink/> <px:fileset-join> <p:input port="source"> <p:pipe step="add-mediaoverlays" port="fileset"/> <p:pipe step="create-package-doc" port="result.fileset"/> </p:input> </px:fileset-join> <p:delete match="d:file/@role[.='nav']"/> </p:group> <px:fileset-rebase> <p:with-option name="new-base" select="$output-dir"/> </px:fileset-rebase> <p:group name="ocf" px:progress=".05"> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="maybe-validate" port="in-memory"/> </p:output> <p:output port="validation-status"> <p:pipe step="maybe-validate" port="validation-status"/> </p:output> <px:epub3-ocf-finalize name="ocf-finalize"/> <p:documentation> Remove files from memory that are not in fileset </p:documentation> <px:fileset-filter-in-memory name="filter-in-memory"> <p:input port="source.in-memory"> <p:pipe step="ocf-finalize" port="in-memory.out"/> <p:pipe step="add-package-doc" port="in-memory"/> </p:input> </px:fileset-filter-in-memory> <p:sink/> <p:identity> <p:input port="source"> <p:pipe step="ocf-finalize" port="result"/> </p:input> </p:identity> <p:documentation> Validation EPUB </p:documentation> <p:choose name="maybe-validate"> <p:when test="$output-validation='off'"> <p:output port="fileset" primary="true"/> <p:output port="in-memory" sequence="true"> <p:pipe step="filter-in-memory" port="result.in-memory"/> </p:output> <p:output port="validation-status"> <p:inline><d:status result="ok"/></p:inline> </p:output> <p:identity/> </p:when> <p:otherwise px:message="Validating EPUB"> <p:output port="fileset" primary="true"> <p:pipe step="store" port="fileset.out"/> </p:output> <p:output port="in-memory" sequence="true"> <p:empty/> </p:output> <p:output port="validation-status"> <p:pipe step="validate" port="validation-status"/> </p:output> <p:identity name="fileset"/> <p:sink/> <px:set-base-uri name="mimetype"> <p:input port="source"> <p:inline><c:data content-type="text/plain">application/epub+zip</c:data></p:inline> </p:input> <p:with-option name="base-uri" select="resolve-uri('mimetype',$output-dir)"/> </px:set-base-uri> <p:sink/> <px:fileset-add-entry first="true" media-type="text/plain" name="add-mimetype"> <p:input port="source.fileset"> <p:pipe step="fileset" port="result"/> </p:input> <p:input port="source.in-memory"> <p:pipe step="filter-in-memory" port="result.in-memory"/> </p:input> <p:input port="entry"> <p:pipe step="mimetype" port="result"/> </p:input> <p:with-param port="file-attributes" name="compression-method" select="'stored'"/> </px:fileset-add-entry> <px:fileset-store name="store" px:message="Storing EPUB"> <p:input port="in-memory.in"> <p:pipe step="add-mimetype" port="result.in-memory"/> </p:input> </px:fileset-store> <px:epub-validate name="validate" version="3" cx:depends-on="store"> <p:with-option name="epub" select="concat($output-dir,$package-doc-path)"/> <p:with-option name="temp-dir" select="if ($temp-dir='') then '' else concat($temp-dir,'validate-epub/')"/> <p:with-option name="report-method" select="if ($output-validation='report') then 'log' else 'error'"/> </px:epub-validate> </p:otherwise> </p:choose> </p:group> <p:sink/> <p:group name="status"> <p:output port="result"/> <p:identity> <p:input port="source"> <p:pipe step="tts" port="status"/> </p:input> </p:identity> <p:choose> <p:when test="/*/@result='error'"> <p:identity/> </p:when> <p:otherwise> <p:add-attribute match="/*" attribute-name="result"> <p:with-option name="attribute-value" select="/*/@result"> <p:pipe step="ocf" port="validation-status"/> </p:with-option> </p:add-attribute> </p:otherwise> </p:choose> </p:group> <p:sink/> </p:declare-step>