Skip to content

Commit

Permalink
Supports copy instructions for media files
Browse files Browse the repository at this point in the history
  • Loading branch information
fsteimke committed May 12, 2024
1 parent a4fea04 commit 5cd436d
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 14 deletions.
42 changes: 37 additions & 5 deletions src/guide/xml/ch03.xml
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,11 @@ subdirectory.
the desired results for each combination of input and output arrangements.</para>

<note>
<para>Remember that in each case, the questions are: can the
stylesheets find the media files to query them and are the correct
HTML references produced? Actually copying the media files from where
they are in the source system to where they need to be in the HTML is
“not our problem.”</para>
<para>Remember that in each case, the questions are: can the stylesheets find the media files to
query them and are the correct HTML references produced? Actually copying the media files
from where they are in the source system to where they need to be in the HTML is “not our
problem”, but the stylesheets may offer some help. See <xref
linkend="copyinstructions" xrefstyle="%label"/> for details.</para>
</note>

<variablelist>
Expand Down Expand Up @@ -504,6 +504,38 @@ for example, run:</para>
<para>to see the results of processing “mo-3” in scenario 2. The output
will be in the <filename>build/actual</filename> directory. The build target
<buildtarget>all_mo_tests</buildtarget> will run them all.</para>

<section xml:id="copyinstructions">
<title>Copy instructions for media files</title>
<para>Because handling of media files can be complicated, the stylesheets may provide support
under certain circumstances. If the destination of the transformation is known within the
stylesheets, we can infer the destination for media files as well, and a script with
instructions for copying the media files can be created on request. If the <link
xlink:href="http://expath.org/spec/file">expath <code>file:copy</code> function</link> is
available, the copy instructions can even be executed. This is the case, for example, if you
are using <productname>Saxon-PE </productname>or <productname>Saxon-EE</productname>.</para>
<para>Two prerequisites must be met for copy instructions to be created and, if possible,
executed:</para>
<orderedlist>
<listitem>
<para>The target of the transformation must be specified with the two parameters
<parameter>chunk-output-base-uri</parameter> and <parameter>chunk</parameter>. In
other words: the support for copying media files only works for chunked output in
accordance with <xref linkend="chunking" xrefstyle="%label"/>. If you are not interested
in "chunked HTML", but prefer a single HTML file as output, you can set the parameter
<parameter>chunk-include</parameter> to the empty sequence <code>()</code>. You may
call this "fake chunking" if you want, but we have to rely on this trick because there
is currently no other way to determine the destination of the transformation</para>
</listitem>
<listitem>
<para>You must request copy instructions by setting the parameter
<parameter>copyinstructions-uri</parameter> to a file path. The copy instructions will be
written to this file.</para>
</listitem>
</orderedlist>
<para>The template <template>t:write-copyinstructions</template> is responsible for
writing the file which contains copy instructions.</para>
</section>
</section>

<section xml:id="numeration">
Expand Down
29 changes: 27 additions & 2 deletions src/guide/xml/ref-params.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2472,6 +2472,29 @@ settings.</para>
<para>See also <varname>table-accessibility</varname>.</para>
</refsection>
</refentry>

<refentry>
<refmeta>
<fieldsynopsis>
<type>xs:string?</type>
<varname>copyinstructions-uri</varname>
</fieldsynopsis>
</refmeta>
<refnamediv>
<refpurpose>URI for a file with copy instructions for media files</refpurpose>
</refnamediv>
<refsection>
<title>Description</title>
<para>You may specify the path of a file with instructions for copying media files in this
parameter. Please keep in mind, that support for copy-instructions for media files will only
work for "chunked" output, see <xref linkend="copyinstructions" xrefstyle="%label"/> for
details. If it is a relative path, it will be resolved against
<parameter>mediaobject-output-base-uri</parameter>. The template
<template>t:write-copyinstructions</template> is responsible for writing the file, it
determines the format of the "instructions".</para>
</refsection>
</refentry>


<refentry>
<refmeta>
Expand Down Expand Up @@ -2580,8 +2603,10 @@ audio files, etc.) is complicated. See <xref linkend="mediaobject-uris"/>.
The <parameter>mediaobject-output-base-uri</parameter> is used to compute
the base URI of media objects in the output.
</para>
<para>It defaults to the empty string.
See <varname>v:mediaobject-output-base-uri</varname>.
<para>It defaults to the empty string. In this case,
the <tag>img</tag> elements in the generated HTML file(s)
will reference the mediaobject files in their original places.
See <varname>v:mediaobject-input-base-uri</varname>.
</para>
</refsection>
</refentry>
Expand Down
33 changes: 32 additions & 1 deletion src/guide/xml/ref-templates.xml
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,38 @@ the element’s content.</para>
</variablelist>
</refsection>
</refentry>


<refentry xml:id="t_write-copyinstructions">
<refmeta>
<refentrytitle>t:write-copyinstructions</refentrytitle>
<refmiscinfo>{http://docbook.org/ns/docbook/templates}write-copyinstructions</refmiscinfo>
</refmeta>
<refnamediv>
<refname>t:write-copyinstructions</refname>
<refpurpose>Writes a file which contains copy instructions for mediaobject files</refpurpose>
<refclass>template</refclass>
</refnamediv>
<refsection>
<title>Description</title>
<para>This template writes a file at <parameter>copyinstructions-uri</parameter> for copying
the media files in the template parameter <code>$instructions</code>, which is a non-empty
sequence of maps with <code>source</code> and <code>destination</code>.</para>
<para>The default implementation will create an XML file with <code>copyinstructions</code> as
root element, and one <code>copy</code> Element for each map in <code>$instructions</code>.</para>
<programlisting>&lt;copyinstructions&gt;
&lt;copy source= &quot;file:/mnt/shared/kosit/xslTNG/src/test/resources/media/duck-small.gif&quot;
destination=&quot;file:/home/frank/kosit/xslTNG/test/html/duck-small.gif&quot;/&gt;
&lt;/copyinstructions&gt;
</programlisting>
<para>You may use a customization layer with your own implementation of this template to create a UNIX or Windows Script file.</para>
<para>Please note, that this templete will only be called if the expath function
<code>{http://expath.org/ns/file}:copy</code> is not available. Otherwise, the copy
instruction will pe performed by the stylesheets, in which case the file at
<parameter>copyinstructions-uri</parameter> will become a logfile with a slightly
different format.</para>
</refsection>
</refentry>

<refentry xml:id="t_mediaobject-img">
<?db filename="t_mediaobject-img"?>
<refmeta>
Expand Down
10 changes: 8 additions & 2 deletions src/main/xslt/docbook-paged.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,16 @@
</head>
<body>
<xsl:copy-of select="*/@*"/>
<xsl:apply-templates select="*/h:header" mode="m:chunk-cleanup"/>
<xsl:apply-templates select="*/h:header" mode="m:chunk-cleanup">
<xsl:with-param name="rootbaseuri" select="$rbu" tunnel="yes"/>
<xsl:with-param name="chunkbaseuri" select="$cbu" tunnel="yes"/>
</xsl:apply-templates>
<main>
<xsl:apply-templates select="*/* except */h:header"
mode="m:chunk-cleanup"/>
mode="m:chunk-cleanup">
<xsl:with-param name="rootbaseuri" select="$rbu" tunnel="yes"/>
<xsl:with-param name="chunkbaseuri" select="$cbu" tunnel="yes"/>
</xsl:apply-templates>
</main>
</body>
</html>
Expand Down
19 changes: 17 additions & 2 deletions src/main/xslt/docbook.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
xmlns:err='http://www.w3.org/2005/xqt-errors'
xmlns:ext="http://docbook.org/extensions/xslt"
xmlns:f="http://docbook.org/ns/docbook/functions"
xmlns:file="http://expath.org/ns/file"
xmlns:fp="http://docbook.org/ns/docbook/functions/private"
xmlns:ghost="http://docbook.org/ns/docbook/ephemeral"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:m="http://docbook.org/ns/docbook/modes"
xmlns:mp="http://docbook.org/ns/docbook/modes/private"
Expand Down Expand Up @@ -275,7 +277,15 @@
<xsl:variable name="result" as="document-node()">
<xsl:sequence select="fp:run-transforms($result, $post-processing)"/>
</xsl:variable>


<xsl:call-template name="tp:mediaobjects-copyinstructions">
<xsl:with-param name="html" select="$result"/>
</xsl:call-template>

<xsl:variable name="result" as="document-node()">
<xsl:apply-templates select="$result" mode="mp:final-cleanup"/>
</xsl:variable>

<xsl:choose>
<xsl:when test="$return = 'raw-results'">
<xsl:sequence select="map {
Expand Down Expand Up @@ -448,5 +458,10 @@
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!-- mp:final-cleanup removes attributes in the ghost namespace -->
<xsl:mode name="mp:final-cleanup" on-no-match="shallow-copy"/>

<xsl:template mode="mp:final-cleanup" match="@ghost:*"/>

</xsl:stylesheet>
</xsl:stylesheet>
1 change: 1 addition & 0 deletions src/main/xslt/main.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<xsl:import href="modules/chunk-cleanup.xsl"/>
<xsl:import href="modules/chunk-output.xsl"/>
<xsl:import href="modules/xform-locale.xsl"/>
<xsl:import href="modules/copyinstructions.xsl"/>

<xsl:output method="xhtml" encoding="utf-8" indent="no" html-version="5"
omit-xml-declaration="yes"/>
Expand Down
2 changes: 1 addition & 1 deletion src/main/xslt/modules/chunk-output.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@
</xsl:function>

<xsl:template match="element()">
<xsl:copy>
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@*,node()"/>
</xsl:copy>
</xsl:template>
Expand Down
104 changes: 104 additions & 0 deletions src/main/xslt/modules/copyinstructions.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:err="http://www.w3.org/2005/xqt-errors" xmlns:file="http://expath.org/ns/file"
xmlns:ghost="http://docbook.org/ns/docbook/ephemeral" xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:mp="http://docbook.org/ns/docbook/modes/private"
xmlns:t="http://docbook.org/ns/docbook/templates"
xmlns:tp="http://docbook.org/ns/docbook/templates/private"
xmlns:v="http://docbook.org/ns/docbook/variables"
xmlns:vp="http://docbook.org/ns/docbook/variables/private"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all" version="3.0">

<xsl:template name="tp:mediaobjects-copyinstructions">
<xsl:param name="html" as="document-node()"/>
<xsl:message select="'v:debug= ' || string-join($v:debug,', ') || '; $debug=' || $debug"/>
<xsl:choose>
<xsl:when test="$copyinstructions-uri and exists($vp:absolute-mediaobject-output-base-uri)">
<xsl:variable name="instructions" as="map(*)*">
<xsl:apply-templates select="$html//h:img[@ghost:sourcefile]"
mode="mp:mediaobject-copy-instruction"/>
</xsl:variable>
<xsl:if test="exists($instructions)" use-when="function-available('file:copy')">
<xsl:call-template name="tp:copy-mediaobjects">
<xsl:with-param name="instructions" as="map(*)+" select="$instructions"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="exists($instructions)" use-when="not(function-available('file:copy'))">
<xsl:call-template name="t:write-copyinstructions">
<xsl:with-param name="instructions" as="map(*)+" select="$instructions"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:when test="$copyinstructions-uri and not($vp:chunk-output-base-uri)">
<xsl:message
select="'Can''t construct copy instructions for mediaobjects: Don''t know absolute URI of mediaobject output base.'"
/>
</xsl:when>
</xsl:choose>
</xsl:template>

<xsl:template name="tp:copy-mediaobjects" use-when="function-available('file:copy')">
<xsl:param name="instructions" as="map(xs:string, xs:anyURI)+" required="yes"/>
<xsl:try>
<xsl:result-document href="{$vp:copyinstructions-uri}">
<mediaobjects xmlns="">
<xsl:for-each select="$instructions">
<xsl:try>
<copied source="{.?source}" destination="{.?destination}" result='successs'/>
<xsl:catch>
<error source="{.?source}" destination="{.?destination}">
<xsl:value-of select="$err:description"/>
</error>
</xsl:catch>
</xsl:try>
</xsl:for-each>
</mediaobjects>
</xsl:result-document>
<xsl:message select="'Wrote ' || $vp:copyinstructions-uri" use-when="$v:debug = 'mediaobject-uris'"/>
<xsl:catch>
<xsl:message
select="'Unable to write copyinstructions to ' || $vp:copyinstructions-uri || ': ' || $err:description"
/>
</xsl:catch>
</xsl:try>
</xsl:template>

<xsl:template name="t:write-copyinstructions">
<xsl:param name="instructions" as="map(xs:string, xs:anyURI)+" required="yes"/>
<xsl:try>
<xsl:result-document href="{$vp:copyinstructions-uri}">
<copyinstructions xmlns="">
<xsl:for-each select="$instructions">
<copy source="{.?source}" destination="{.?destination}"/>
</xsl:for-each>
</copyinstructions>
</xsl:result-document>
<xsl:message select="'Wrote ' || $vp:copyinstructions-uri" use-when="$v:debug = 'mediaobject-uris'"/>
<xsl:catch>
<xsl:message
select="'Unable to write copyinstructions to ' || $vp:copyinstructions-uri || ': ' || $err:description"
/>
</xsl:catch>
</xsl:try>
</xsl:template>

<!-- mp:mediaobject-copy-instruction calculates for some HTML Elements a map which can support copy instructions -->
<xsl:mode name="mp:mediaobject-copy-instruction"/>

<xsl:template match="h:img[@ghost:sourcefile]" mode="mp:mediaobject-copy-instruction"
as="map(xs:string, xs:anyURI)?">
<xsl:if test="exists($vp:absolute-mediaobject-output-base-uri)">
<xsl:variable name="destination" as="xs:anyURI" select="resolve-uri(@src, $vp:absolute-mediaobject-output-base-uri)" />
<xsl:message
select="'abs. uri (' || @src || ') &#x2192; ' || $destination" use-when="$v:debug = 'mediaobject-uris'"/>
<xsl:sequence select="
map {
'source': @ghost:sourcefile => xs:anyURI(),
'destination': $destination
}"/>
</xsl:if>
</xsl:template>

<xsl:template match="node()" mode="mp:mediaobject-copy-instruction" priority="-10"/>

</xsl:stylesheet>
5 changes: 4 additions & 1 deletion src/main/xslt/modules/objects.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
xmlns:ext="http://docbook.org/extensions/xslt"
xmlns:f="http://docbook.org/ns/docbook/functions"
xmlns:fp="http://docbook.org/ns/docbook/functions/private"
xmlns:ghost="http://docbook.org/ns/docbook/ephemeral"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:m="http://docbook.org/ns/docbook/modes"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
Expand Down Expand Up @@ -757,6 +758,7 @@
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="t:mediaobject-img">
<xsl:with-param name="sourcefile" select="$info?uri"/>
<xsl:with-param name="filename" select="$info?href"/>
<xsl:with-param name="styles" select="$styles"/>
<xsl:with-param name="viewport" select="$viewport"/>
Expand All @@ -767,12 +769,13 @@
</xsl:template>

<xsl:template name="t:mediaobject-img">
<xsl:param name="sourcefile" as="xs:string"/>
<xsl:param name="filename" as="xs:string"/>
<xsl:param name="styles" as="xs:string*"/>
<xsl:param name="viewport" as="map(*)?"/>
<xsl:param name="imageproperties" as="map(*)?"/>

<img src="{$filename}">
<img src="{$filename}" ghost:sourcefile='{$sourcefile}'>
<xsl:apply-templates select="." mode="m:attributes"/>

<!-- Apply any alt text in the media object to the image tag. -->
Expand Down
24 changes: 24 additions & 0 deletions src/main/xslt/modules/variable.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,30 @@
then $mediaobject-output-base-uri
else $mediaobject-output-base-uri || '/'"/>
</xsl:variable>

<xsl:variable name="vp:absolute-mediaobject-output-base-uri" as="xs:anyURI?">
<xsl:variable name="uri" as="xs:anyURI?">
<xsl:try>
<xsl:sequence
select="resolve-uri(($v:mediaobject-output-base-uri, './')[1], $vp:chunk-output-base-uri)"/>
<xsl:catch/>
</xsl:try>
</xsl:variable>
<xsl:message select="'$vp:absolute-mediaobject-output-base-uri:' || $uri"
use-when="'mediaobject-uris' = $v:debug"/>
<xsl:sequence select="$uri"/>
</xsl:variable>

<xsl:variable name="vp:copyinstructions-uri" as="xs:string?">
<xsl:if test="$copyinstructions-uri and $vp:chunk-output-base-uri">
<xsl:try>
<xsl:sequence select="resolve-uri($copyinstructions-uri, $vp:chunk-output-base-uri)"/>
<xsl:catch>
<xsl:sequence select="$copyinstructions-uri"/>
</xsl:catch>
</xsl:try>
</xsl:if>
</xsl:variable>

<xsl:variable name="v:mediaobject-exclude-extensions"
select="tokenize($mediaobject-exclude-extensions, '\s+')"/>
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/xml/test/instructions.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<mediaobjects><copied source="file:/home/frank/kosit/xslTNG/src/test/resources/media/duck-small.gif" destination="file:/home/frank/kosit/xslTNG/test/html/duck-small.gif" result="successs"></copied></mediaobjects>

0 comments on commit 5cd436d

Please sign in to comment.