# (callable) Get the list of dependency leiris for the given source files.
#
# Recursive dependencies are marked with a leading `-´.
+# Soft dependencies are marked with a leading `?´.
override dependencyuris = $(foreach file,$1,$(subst |, ,$(patsubst $(file)|%,%,$(filter $(file)|%,$(dependenciesforfile)))))
# (callable) Get the list of recursive dependencies for the given source files.
# (callable) Get the list of (nonrecursive) dependencies for the given source files.
#
# If the file cannot have dependencies (e·g is an asset file), the resulting value will be the empty string.
-override dependencies = $(foreach uri,$(filter-out -%,$(call dependencyuris,$1)),$(call sourcefile,$(uri)))
+override dependencies = $(foreach uri,$(filter-out -%,$(call dependencyuris,$1)),$(call sourcefile,$(if $(filter ?%,$(uri)),$(patsubst ?%,%,$(uri)),$(uri))))
endif
# Collect all files with recursive dependencies.
# List all source files and includes and their computed types.
list :
- @$(PRINTF) '%b' $(call quote,$(foreach file,$(sort $(sourcefiles)) $(sort $(sourceincludes)),\0033[1m$(file)\0033[22m|$(call typeoffile,$(file))|[\0033[3m$(if $(filter $(file),$(xmlfiles)),xml,$(if $(filter $(file),$(plaintextfiles)),text,asset))$(if $(filter $(file),$(sourceincludes)),|include,)\0033[23m]$(if $(call dependencies,$(file))$(call recursives,$(file)), $(strip $(foreach recursive,$(call recursives,$(file)),\0033[93;41m•|Recursive|Dependency|\0033[39;49m|$(recursive)) $(foreach dependency,$(call dependencies,$(file)),\0033[2m•|Dependency|\0033[22m|$(dependency))))$(if $(filter $(file),$(sourcefiles)), $(foreach dest,$(call destination,$(file)),→|<\0033[4m/$(dest)\0033[24m>),) )) | $(TR) ' |' '\n '
+ @$(PRINTF) '%b' $(call quote,$(foreach file,$(sort $(sourcefiles)) $(sort $(sourceincludes)),\0033[1m$(file)\0033[22m|$(call typeoffile,$(file))|[\0033[3m$(if $(filter $(file),$(xmlfiles)),xml,$(if $(filter $(file),$(plaintextfiles)),text,asset))$(if $(filter $(file),$(sourceincludes)),|include,)\0033[23m]$(if $(call dependencyuris,$(file)), $(strip $(foreach dep,$(call dependencyuris,$(file)),$(if $(filter -%,$(dep)),\0033[93;41m•|Recursive|Dependency|\0033[39;49m|$(call sourcefile,$(patsubst -%,%,$(dep))),$(if $(filter ?%,$(dep)),\0033[2m•|Soft|Dependency|\0033[22m|$(call sourcefile,$(patsubst ?%,%,$(dep))),\0033[2m•|Dependency|\0033[22m|$(call sourcefile,$(dep)))))))$(if $(filter $(file),$(sourcefiles)), $(foreach dest,$(call destination,$(file)),→|<\0033[4m/$(dest)\0033[24m>),) )) | $(TR) ' |' '\n '
# Lists out the destinations of all resulting files (relative to `DESTDIR´).
listout :
## Embedding
Documents can be embedded in other documents using a `<书社:link>`
- element with `@xlink:show="embed"`.
+ element with `@xlink:show="embed"` and an `@xlink:actuate` which is
+ absent or `"none"`.
The `@xlink:href`s of these elements should have the format
`about:shushe?source=<path>`, where `<path>` provides the path to the
file within `SRCDIR`.
freely embedded, instead use the format
`about:shushe?include=<path>`, where `<path>` provides the path
within `INCLUDEDIR`.
+If `<path>` indicates a directory and ends with a slash (`/`),
+ everything within that directory will be embedded.
Embeds are replaced with the parsed contents of a file, unless the file
is an asset, in which case an `<html:object>` element is produced
These attributes are used to scope any nested `<html:meta>` elements
with `@itemprop` attributes to their containing documents.
+## Soft Dependencies
+
+When a file depends only on the metadata of another file, and not its
+ contents, it can be added as a soft dependency rather than an embed.
+Soft dependencies are indicated using a `<书社:link>` element with an
+ `@xlink:show` of `"other"`, `"none"`, or absent, and an
+ `@xlink:actuate` which is absent or `"none"`.
+A change to a soft dependency requires a file to be rebuilt, but no
+ embedding occurs automatically.
+Because there is no automatic embedding, soft dependencies are allowed
+ to be recursive.
+
+The `@xlink:href`s of soft dependency `<书社:link>`s are processed in
+ exactly the same fashion as embeds, described above.
+
+If the value of `@xlink:show` is `"other"`, the soft dependency is
+ transitive.
+Any dependencies of the indicated file which have a `@name` which
+ matches that of the referencing `<书社:link>` element will also be
+ treated as soft dependencies.
+If no `@name` is given, it is treated as the empty string.
+
+When a document is embedded directly, all of its soft dependencies are
+ also treated as soft dependencies of the embedding object.
+However, a document is embedded in a transitive soft dependency, the
+ embed is treated exactly as tho it were itself a transitive soft
+ dependency.
+That means it must have a matching `@name` to be included, and
+ like·wise for any embeds or soft dependencies it contains.
+
+If the value of `@xlink:show` is `"none"` or absent, the soft
+ dependency is not transitive and its own dependencies are not
+ checked.
+
## Transforms
Transforms are used to convert X·M·L files into their final output,
>
<variable name="builddir" select="//书社vocab:BuildDirectory/@nfo:fileUrl"/>
<variable name="files" select="//书社vocab:SourceFile|//书社vocab:IncludeFile"/>
- <template name="书社:collect-dependency-paths">
- <param name="path" select="/.."/>
- <variable name="parent" select="string($path/*[last()])"/>
- <variable name="children-fragment">
- <for-each select="$files[@rdf:about=$parent and nie:interpretedAs/nfo:PlainTextDocument]">
- <variable name="uri" select="书社vocab:hasParsedFile/@nfo:fileUrl"/>
- <for-each select="document($uri)//书社:link[@xlink:show='embed']">
- <variable name="identifier" select="string(@xlink:href)"/>
- <variable name="is-dir" select="substring($identifier, string-length($identifier))='/'"/>
- <for-each select="$files/@rdf:about[string(.)=$identifier or $is-dir and starts-with(., $identifier)]">
- <sort select="." data-type="text" lang="zxx" case-order="upper-first"/>
+ <variable name="stated-dependencies-fragment">
+ <for-each select="$files[nie:interpretedAs/nfo:PlainTextDocument]">
+ <variable name="uri" select="书社vocab:hasParsedFile/@nfo:fileUrl"/>
+ <书社:Dependencies for="{@rdf:about}">
+ <for-each select="document($uri)//书社:link">
+ <variable name="spaced-show">
<choose>
- <when test="$path/*[string(.)=string(current())]">
- <书社:recursive-dependency>
- <value-of select="."/>
- </书社:recursive-dependency>
+ <when test="@xlink:show">
+ <text> </text>
+ <value-of select="@xlink:show"/>
+ <text> </text>
</when>
<otherwise>
- <书社:dependency>
- <value-of select="."/>
- </书社:dependency>
+ <text> none </text>
</otherwise>
</choose>
- </for-each>
+ </variable>
+ <variable name="actuate">
+ <choose>
+ <when test="@xlink:actuate">
+ <value-of select="@xlink:actuate"/>
+ </when>
+ <otherwise>
+ <text>none</text><!-- not the true default in all cases, but in the ones that matter -->
+ </otherwise>
+ </choose>
+ </variable>
+ <variable name="name" select="string(@name)"/>
+ <if test="contains(' embed other none ', $spaced-show) and $actuate='none'">
+ <variable name="identifier" select="string(@xlink:href)"/>
+ <variable name="is-dir" select="substring($identifier, string-length($identifier))='/'"/>
+ <for-each select="$files/@rdf:about[string(.)=$identifier or $is-dir and starts-with(., $identifier)]">
+ <sort select="." data-type="text" lang="zxx" case-order="upper-first"/>
+ <choose>
+ <when test="$spaced-show=' embed '">
+ <书社:dependency name="{$name}">
+ <value-of select="."/>
+ </书社:dependency>
+ </when>
+ <when test="$spaced-show=' other '">
+ <书社:transitive-soft-dependency name="{$name}">
+ <value-of select="."/>
+ </书社:transitive-soft-dependency>
+ </when>
+ <otherwise>
+ <书社:soft-dependency name="{$name}">
+ <value-of select="."/>
+ </书社:soft-dependency>
+ </otherwise>
+ </choose>
+ </for-each>
+ </if>
</for-each>
+ </书社:Dependencies>
+ </for-each>
+ </variable>
+ <variable name="stated-dependencies" select="exsl:node-set($stated-dependencies-fragment)/*"/>
+ <template name="书社:collect-dependency-paths">
+ <param name="path" select="/.."/>
+ <variable name="parent" select="$path/*[last()]"/>
+ <variable name="children-fragment">
+ <for-each select="$stated-dependencies[@for=string($parent)]/*">
+ <choose>
+ <when test="$path/*[string()=current()]">
+ <if test="self::书社:dependency">
+ <书社:recursive-dependency name="{@name}">
+ <value-of select="."/>
+ </书社:recursive-dependency>
+ </if>
+ </when>
+ <otherwise>
+ <copy-of select="."/>
+ </otherwise>
+ </choose>
</for-each>
</variable>
- <variable name="children" select="exsl:node-set($children-fragment)"/>
+ <variable name="children" select="exsl:node-set($children-fragment)/*"/>
+ <variable name="child-paths-fragment">
+ <for-each select="$children">
+ <choose>
+ <when test="self::书社:recursive-dependency">
+ <书社:dependency-path>
+ <copy-of select="$path/*[string()=current()][1]/preceding-sibling::*"/>
+ <copy-of select="."/><!-- replace first instance with recursive dependency -->
+ </书社:dependency-path>
+ </when>
+ <when test="$parent/self::书社:transitive-soft-dependency and string(@name)!=string($parent/@name)"/>
+ <when test="self::书社:soft-dependency">
+ <书社:dependency-path>
+ <copy-of select="$path"/>
+ <copy-of select="."/>
+ </书社:dependency-path>
+ </when>
+ <otherwise>
+ <variable name="path-fragment">
+ <copy-of select="$path"/>
+ <choose>
+ <when test="self::书社:dependency and $path/书社:transitive-soft-dependency">
+ <书社:transitive-soft-dependency name="{@name}">
+ <value-of select="."/>
+ </书社:transitive-soft-dependency>
+ </when>
+ <otherwise>
+ <copy-of select="."/>
+ </otherwise>
+ </choose>
+ </variable>
+ <call-template name="书社:collect-dependency-paths">
+ <with-param name="path" select="exsl:node-set($path-fragment)"/>
+ </call-template><!-- a little inefficient in the case of reflexive dependencies, as the path will be traversed once in each direction, but improving on this is a hard problem in X·S·L·T -->
+ </otherwise>
+ </choose>
+ </for-each>
+ </variable>
+ <variable name="child-paths" select="exsl:node-set($child-paths-fragment)/*"/>
<choose>
- <when test="$children/*">
- <for-each select="$children/书社:recursive-dependency">
- <书社:dependency-path>
- <copy-of select="$path[string(.)=string(current())]/preceding-sibling::*"/>
- <copy-of select="."/>
- </书社:dependency-path>
- </for-each>
- <for-each select="$children/书社:dependency">
- <variable name="path-fragment">
- <copy-of select="$path"/>
- <copy-of select="."/>
- </variable>
- <call-template name="书社:collect-dependency-paths">
- <with-param name="path" select="exsl:node-set($path-fragment)"/>
- </call-template>
- </for-each>
+ <when test="$child-paths">
+ <copy-of select="$child-paths"/>
</when>
- <otherwise>
+ <otherwise><!-- fallback result is just the input path -->
<书社:dependency-path>
<copy-of select="$path"/>
</书社:dependency-path>
</for-each>
</if>
</variable>
- <variable name="dependencies-fragment">
- <apply-templates select="." mode="书社:dependencies"/>
- </variable>
- <variable name="dependencies" select="exsl:node-set($dependencies-fragment)"/>
<variable name="destinations" select="exsl:node-set($destinations-fragment)/node()"/>
<variable name="bad-destinations-fragment">
<for-each select="$destinations">
<copy>
<apply-templates select="@*"/>
<apply-templates select="node()"/>
- <for-each select="$dependencies/书社:dependency">
- <书社vocab:hasDependencyOn rdf:resource="{.}"/>
- </for-each>
- <for-each select="$dependencies/书社:recursive-dependency">
- <书社vocab:hasRecursiveDependencyOn rdf:resource="{.}"/>
- </for-each>
+ <apply-templates select="." mode="书社:dependencies"/>
<choose>
<when test="not($destinations)">
<element name="书社vocab:destination">
</copy>
</template>
<template match="//书社vocab:IncludeFile[nie:interpretedAs/nfo:PlainTextDocument]" priority="1">
- <variable name="dependencies-fragment">
- <apply-templates select="." mode="书社:dependencies"/>
- </variable>
- <variable name="dependencies" select="exsl:node-set($dependencies-fragment)"/>
<copy>
<apply-templates select="@*|node()"/>
- <for-each select="$dependencies/书社:dependency">
- <书社vocab:hasDependencyOn rdf:resource="{.}"/>
- </for-each>
- <for-each select="$dependencies/书社:recursive-dependency">
- <书社vocab:hasRecursiveDependencyOn rdf:resource="{.}"/>
- </for-each>
+ <apply-templates select="." mode="书社:dependencies"/>
</copy>
</template>
<template match="书社vocab:hasParsedFileWithMetadata" priority="1"/>
<value-of select="@rdf:about"/>
<text>
</text>
<for-each select="书社vocab:hasRecursiveDependencyOn/@rdf:resource">
- <text>	</text>
- <text>-</text>
+ <text>	-</text>
+ <value-of select="."/>
+ <text>
</text>
+ </for-each>
+ <for-each select="书社vocab:hasSoftDependencyOn/@rdf:resource">
+ <text>	?</text>
<value-of select="."/>
<text>
</text>
</for-each>
<template match="书社vocab:SourceFile|书社vocab:IncludeFile" mode="书社:dependencies">
<if test="nie:interpretedAs/nfo:PlainTextDocument">
<variable name="path-fragment">
- <书社:dependency-root>
+ <element name="书社:dependency-root">
<value-of select="@rdf:about"/>
- </书社:dependency-root>
+ </element>
</variable>
<variable name="paths-fragment">
<call-template name="书社:collect-dependency-paths">
<with-param name="path" select="exsl:node-set($path-fragment)"/>
</call-template>
</variable>
- <for-each select="exsl:node-set($paths-fragment)/*/*[not(self::书社:dependency-root)]">
- <if test="not(preceding::*[string(.)=string(current())])">
- <copy-of select="."/>
+ <variable name="paths-document" select="exsl:node-set($paths-fragment)"/>
+ <for-each select="$paths-document//书社:recursive-dependency">
+ <if test="not(preceding::*[string()=string(current())])">
+ <element name="书社vocab:hasRecursiveDependencyOn">
+ <attribute name="rdf:resource">
+ <value-of select="."/>
+ </attribute>
+ </element>
+ </if>
+ </for-each>
+ <for-each select="$paths-document//书社:dependency">
+ <if test="not((preceding::*|//书社:recursive-dependency)[string()=string(current())])">
+ <element name="书社vocab:hasDependencyOn">
+ <attribute name="rdf:resource">
+ <value-of select="."/>
+ </attribute>
+ </element>
+ </if>
+ </for-each>
+ <for-each select="$paths-document//*[self::书社:soft-dependency or self::书社:transitive-soft-dependency]">
+ <if test="not((preceding::*|//书社:recursive-dependency|//书社:dependency)[string()=string(current())])">
+ <element name="书社vocab:hasSoftDependencyOn">
+ <attribute name="rdf:resource">
+ <value-of select="."/>
+ </attribute>
+ </element>
</if>
</for-each>
</if>