]> Lady’s Gitweb - Shushe/commitdiff
Support multiple destinations current
authorLady <redacted>
Sat, 25 Oct 2025 01:06:15 +0000 (21:06 -0400)
committerLady <redacted>
Sat, 25 Oct 2025 01:06:15 +0000 (21:06 -0400)
This commit enables transforming the same source file to multiple
destinations, and provides a new variable for determining which
destination is currently being written to.

.metadata-format-changed-since
GNUmakefile
README.markdown
lib/catalog2parser.xslt
lib/catalog2transform.xslt
lib/expandmetadata.xslt
parsers/tsv.xslt
transforms/expansion.xslt [new file with mode: 0644]

index 6cf4047917a5feb4fd9637e12153c6aa0feff88a..36e448cb04f68706a11e03db61e91473aa7d8f26 100644 (file)
@@ -1,10 +1,10 @@
-SPDX-FileCopyrightText: 2024 Lady <https://www.ladys.computer/about/#lady>
+SPDX-FileCopyrightText: 2024, 2025 Lady <https://www.ladys.computer/about/#lady>
 SPDX-License-Identifier: CC0-1.0
 
 The following hash indicates a commit in which the metadata format
 generated by ⛩📰 书社 was different than it currently is :⁠—
 
 SPDX-License-Identifier: CC0-1.0
 
 The following hash indicates a commit in which the metadata format
 generated by ⛩📰 书社 was different than it currently is :⁠—
 
-c84c2b38caf34807fd1c52a8f19fcf0af7e9807e
+d64a8d34c7638243f90421664268766df75a42d7
 
 The purpose of this file is to serve as a trackable dependency which
 will prompt a rebuild of metadata when the generation mechanism
 
 The purpose of this file is to serve as a trackable dependency which
 will prompt a rebuild of metadata when the generation mechanism
index a9cf3b803a28e6a83e53ae4d7f9a4fdba3dd6c8e..a3624ccd944425e9185ab93f66f6ea3e78256037 100644 (file)
@@ -83,7 +83,7 @@ override define makefileinfo
 ║╰────────────────────────────────────────────────────────────╯║
 ╟┬ ¶ Copyright & License ─────────────────────────────────────┬╢
 ║│                                                            │║
 ║╰────────────────────────────────────────────────────────────╯║
 ╟┬ ¶ Copyright & License ─────────────────────────────────────┬╢
 ║│                                                            │║
-║│ Copyright © 2023–2024 Lady [@ Ladys Computer].             │║
+║│ Copyright © 2023–2025 Lady [@ Ladys Computer].             │║
 ║│                                                            │║
 ║│ This Source Code Form is subject to the terms of the       │║
 ║│ Mozilla Public License, v 2.0. If a copy of the M·P·L was  │║
 ║│                                                            │║
 ║│ This Source Code Form is subject to the terms of the       │║
 ║│ Mozilla Public License, v 2.0. If a copy of the M·P·L was  │║
@@ -188,6 +188,11 @@ EXTRAFINDINCLUDERULES :=
 FINDRULES := '!' '(' '(' -name '[.-]*' -a '!' -name '.' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a '(' $(EXTRAFINDRULES) ')',)
 FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a '(' $(EXTRAFINDINCLUDERULES) ')',)
 
 FINDRULES := '!' '(' '(' -name '[.-]*' -a '!' -name '.' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a '(' $(EXTRAFINDRULES) ')',)
 FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a '(' $(EXTRAFINDINCLUDERULES) ')',)
 
+# Options to use when calling Make for the first build of a two‐stage build.
+#
+# This can be used to override variables which are only applicable to the second build.
+DATAOPTS :=
+
 # File extensions which indicate files in `SRCDIR´ which should be built as part of the first, rather than second, stage of the two‐stage `MODE´.
 DATAEXT := rdf
 
 # File extensions which indicate files in `SRCDIR´ which should be built as part of the first, rather than second, stage of the two‐stage `MODE´.
 DATAEXT := rdf
 
@@ -351,6 +356,9 @@ override not = $(if $1,,1)
 # (callable) Quote the given string for use within shell calls.
 override quote = '$(subst ','"'"',$1)'
 
 # (callable) Quote the given string for use within shell calls.
 override quote = '$(subst ','"'"',$1)'
 
+# (callable) Quote the given string for use defining a variable to send to a submake.
+override varquote = $(subst $$,$$$$,$(call quote,$1))
+
 # The command to use for percent‐decoding.
 override perdeccmd := $(SED) 's/|/%7C/g;s/[\]/%5C/g;s/%[0123456789ABCDEFabcdef]\{2\}/|&|/g' | $(TR) '|' '\n' | $(SED) '/^%[0123456789ABCDEFabcdef]\{2\}$$/!s/%/|%25|/' | $(TR) '|' '\n' | $(AWK) '$$0!~/%/{printf "%s",$$0}/%/{d="0123456789ABCDEF";v=substr(toupper($$0),2,2);printf "\\%04o",(index(d,substr(v,1,1))-1)*16+index(d,substr(v,2,1))-1}' | $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/;$$!s/$$/\\/) | $(XARGS) -E '' $(PRINTF) '%b'
 
 # The command to use for percent‐decoding.
 override perdeccmd := $(SED) 's/|/%7C/g;s/[\]/%5C/g;s/%[0123456789ABCDEFabcdef]\{2\}/|&|/g' | $(TR) '|' '\n' | $(SED) '/^%[0123456789ABCDEFabcdef]\{2\}$$/!s/%/|%25|/' | $(TR) '|' '\n' | $(AWK) '$$0!~/%/{printf "%s",$$0}/%/{d="0123456789ABCDEF";v=substr(toupper($$0),2,2);printf "\\%04o",(index(d,substr(v,1,1))-1)*16+index(d,substr(v,2,1))-1}' | $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/;$$!s/$$/\\/) | $(XARGS) -E '' $(PRINTF) '%b'
 
@@ -425,7 +433,7 @@ override id = $(XMLLINT) --noent --nonet --xpath '/*/*[local-name()="id" and nam
 override extracttext = $(PRINTF) '%s' '<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0"><output method="text" encoding="UTF-8"/></transform>' | $(XSLTPROC) --nonet --novalid --nomkdir --nowrite - $(call quote,$1)
 
 # (callable) Process the provided transformation result and output the result to the provided location, given the provided relative path.
 override extracttext = $(PRINTF) '%s' '<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0"><output method="text" encoding="UTF-8"/></transform>' | $(XSLTPROC) --nonet --novalid --nomkdir --nowrite - $(call quote,$1)
 
 # (callable) Process the provided transformation result and output the result to the provided location, given the provided relative path.
-override processresultto = if $(call xpath,/*[local-name()="raw-text" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(call extracttext,$1) >|$(call quote,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then { $(PRINTF) '%s\n' 'begin-base64 644 -'; $(call extracttext,$1) | $(TR) -d '\t\n\f\r '; $(PRINTF) '\n%s\n' '===='; } | $(UUDECODE) -o /dev/stdout >|$(call quote,$2); elif $(call xpath,/*[local-name()="archive" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(makefile) NAME=$(call quote,$3) SRC=$(call quote,$1) BUILDDIR=$(call quote,$(BUILDDIR)/archive/$3) DESTDIR=$(call quote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive' $(call quote,$2); else $(FINALIZE) $(call quote,$1) >|$(call quote,$2); fi
+override processresultto = if $(call xpath,/*[local-name()="raw-text" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(call extracttext,$1) >|$(call quote,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then { $(PRINTF) '%s\n' 'begin-base64 644 -'; $(call extracttext,$1) | $(TR) -d '\t\n\f\r '; $(PRINTF) '\n%s\n' '===='; } | $(UUDECODE) -o /dev/stdout >|$(call quote,$2); elif $(call xpath,/*[local-name()="archive" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(makefile) NAME=$(call varquote,$3) SRC=$(call varquote,$1) BUILDDIR=$(call varquote,$(BUILDDIR)/archive/$3) DESTDIR=$(call varquote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive' $(call varquote,$2); else $(FINALIZE) $(call quote,$1) >|$(call quote,$2); fi
 
 # ━ § BEGIN DEFAULT MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
 
 # ━ § BEGIN DEFAULT MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
@@ -480,7 +488,7 @@ override includepath = $(or $(firstword $(foreach directory,$(INCLUDEDIR),$(if $
 # (callable) Get base64 data u·r·i’s for the given files.
 #
 # ☡ This variable creates a subshell every time it is computed.
 # (callable) Get base64 data u·r·i’s for the given files.
 #
 # ☡ This variable creates a subshell every time it is computed.
-override datauri = $(foreach file,$1,data:$(call typeoffile,$(file));base64,$(shell $(UUENCODE) -m $(call quote,$(file)) _ | $(SED) '2,$$!d;$$d' | $(TR) -d ' \n'))
+override datauri = $(foreach file,$1,data:$(call typeoffile,$(file));base64,$(shell $(UUENCODE) -m $(call quote,$(abspath $(file))) _ | $(SED) '2,$$!d;$$d' | $(TR) -d ' \n'))
 
 # Pair each source file and include with its local u·r·i.
 override sourcelocalpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|about:shushe?$(if $(filter $(file),$(sourceincludes)),include=$(call pathenc,$(call includepath,$(file))),source=$(call pathenc,$(call sourcepath,$(file)))))
 
 # Pair each source file and include with its local u·r·i.
 override sourcelocalpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|about:shushe?$(if $(filter $(file),$(sourceincludes)),include=$(call pathenc,$(call includepath,$(file))),source=$(call pathenc,$(call sourcepath,$(file)))))
@@ -500,23 +508,32 @@ override typeupdates := $(and $(wildcard $(BUILDDIR)/.update-types),FORCE)
 # Pair each source file and include with its metadata location.
 override sourcemetadatapair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes.metadata/$(call includepath,$(file)),sources.metadata/$(call sourcepath,$(file))))
 
 # Pair each source file and include with its metadata location.
 override sourcemetadatapair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes.metadata/$(call includepath,$(file)),sources.metadata/$(call sourcepath,$(file))))
 
-# (callable) Get the location of the transformed X·M·L files for the given source files.
+# (callable) Get the location of the metadata files for the given source files.
 override metadata = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcemetadatapair))))
 
 override metadata = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcemetadatapair))))
 
-# (callable) Get the source files for the given parsed file.
+# (callable) Get the source files for the given metadata files.
 override datadata = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourcemetadatapair))))
 
 # Pair each source file and include with its parsed location.
 override datadata = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourcemetadatapair))))
 
 # Pair each source file and include with its parsed location.
-override sourceparsedpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes/$(call includepath,$(file)),sources/$(call sourcepath,$(file))))
+override sourceparsedpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes.parsed/$(call includepath,$(file)),sources.parsed/$(call sourcepath,$(file))))
 
 # (callable) Get the location of the transformed X·M·L files for the given source files.
 override parsed = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourceparsedpair))))
 
 
 # (callable) Get the location of the transformed X·M·L files for the given source files.
 override parsed = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourceparsedpair))))
 
-# (callable) Get the source files for the given parsed file.
+# (callable) Get the source files for the given parsed files.
 override unparsed = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourceparsedpair))))
 
 override unparsed = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourceparsedpair))))
 
-# Pair each build directory, transform, source file, or parsed file with its file u·r·i.
-override fileuripairs := $(join $(patsubst %,%|,$(BUILDDIR) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes))),$(call pathenc,$(foreach uriable,$(BUILDDIR) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes)),file://$(abspath $(uriable)))))
+# Pair each source file and include with its parsed result location.
+override parsepair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes/$(call includepath,$(file)),sources/$(call sourcepath,$(file))))
+
+# (callable) Get the location of the parsed results for the given source files.
+override parseresult = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(parsepair))))
+
+# (callable) Get the source files for the given parsed results.
+override parsesource = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(parsepair))))
+
+# Pair each build directory, transform, source file, or parsed file, parse result file with its file u·r·i.
+override fileuripairs := $(join $(patsubst %,%|,$(BUILDDIR) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes)) $(call parseresult,$(sourcefiles) $(sourceincludes))),$(call pathenc,$(foreach uriable,$(BUILDDIR) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes)) $(call parseresult,$(sourcefiles) $(sourceincludes)),file://$(abspath $(uriable)))))
 
 # (callable) Get the file u·r·is for the given transforms, source file or parsed files.
 override fileuri = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(fileuripairs))),$(error Unable to get file u·r·i for `$(file)´)))
 
 # (callable) Get the file u·r·is for the given transforms, source file or parsed files.
 override fileuri = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(fileuripairs))),$(error Unable to get file u·r·i for `$(file)´)))
@@ -565,16 +582,16 @@ endif
 # (callable) Get the destination for the given source files, or return `.NOTDEF/$1´.
 #
 # The fallback here is because destinations are used to generate targets and thus must always be non·empty and should be unique, even when they haven’t been generated yet.
 # (callable) Get the destination for the given source files, or return `.NOTDEF/$1´.
 #
 # The fallback here is because destinations are used to generate targets and thus must always be non·empty and should be unique, even when they haven’t been generated yet.
-override destination = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcedestinationpair))),.NOTDEF/$1))
+override destination = $(foreach file,$1,$(subst ;, ,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcedestinationpair))),.NOTDEF/$1)))
 
 # Pair each source file with its compiled location.
 
 # Pair each source file with its compiled location.
-override sourcecompiledpair := $(foreach file,$(sourcefiles),$(file)|$(BUILDDIR)/results/$(call destination,$(file)))
+override sourcecompiledpair := $(foreach file,$(sourcefiles),$(file)|$(subst $(space),;,$(patsubst %,$(BUILDDIR)/results/%,$(call destination,$(file)))))
 
 # (callable) Get the location of the transformed X·M·L files for the given source files.
 
 # (callable) Get the location of the transformed X·M·L files for the given source files.
-override compiled = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcecompiledpair))))
+override compiled = $(foreach file,$1,$(subst ;, ,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcecompiledpair)))))
 
 # (callable) Get the location of the source files for the given compiled file.
 
 # (callable) Get the location of the source files for the given compiled file.
-override uncompiled = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourcecompiledpair))))
+override uncompiled = $(foreach pair,$(sourcecompiledpair),$(foreach src,$(firstword $(subst |, , $(pair))),$(if $(filter $(subst ;, ,$(patsubst $(src)|%,%,$(pair))),$1),$(src),)))
 
 # (callable) Get the location of the final built files for the given source files.
 override built = $(foreach file,$1,$(patsubst $(BUILDDIR)/results/%,$(BUILDDIR)/public/%,$(call compiled,$(file))))
 
 # (callable) Get the location of the final built files for the given source files.
 override built = $(foreach file,$1,$(patsubst $(BUILDDIR)/results/%,$(BUILDDIR)/public/%,$(call compiled,$(file))))
@@ -583,19 +600,19 @@ override built = $(foreach file,$1,$(patsubst $(BUILDDIR)/results/%,$(BUILDDIR)/
 override unbuilt = $(foreach file,$1,$(call uncompiled,$(patsubst $(BUILDDIR)/public/%,$(BUILDDIR)/results/%,$(file))))
 
 # (callable) Get the installed locations for the given source files.
 override unbuilt = $(foreach file,$1,$(call uncompiled,$(patsubst $(BUILDDIR)/public/%,$(BUILDDIR)/results/%,$(file))))
 
 # (callable) Get the installed locations for the given source files.
-override installed = $(foreach file,$1,$(DESTDIR)/$(call destination,$(file)))
+override installed = $(foreach file,$1,$(patsubst %,$(DESTDIR)/%,$(call destination,$(file))))
 
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 
 # (callable) Sanitize and wrap the provided plaintext file in X·M·L, printing to `stdout´.
 
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 
 # (callable) Sanitize and wrap the provided plaintext file in X·M·L, printing to `stdout´.
-override wrapplaintext = { $(PRINTF) '%s\n%s' '<?xml version="1.0"?>' '<script xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$1)"><![CDATA['; $(TR) '\000\013\014' '\032\011\012' <$(call quote,$1) | $(SED) "$$($(PRINTF) '%b' 's/]]>/]]]]><!\\[CDATA\\[>/g\ns/\0357\0277\0276/�/g\ns/\0357\0277\0277/�/g\n$$!s/\\r$$//g\ns/\\r/\\n/g\n$$!s/\0302\0205$$//g\ns/\0302\0205/\\n/g\ns/\0342\0200\0250/\\n/g\ns/[\0001\0002\0003\0004\0005\0006\0007\0010]/�/g\ns/[\0016\0017\0020\0021\0022\0023\0024\0025\0026\0027\0031\0032\0033\0034\0035\0036\0037]/�/g')"; $(PRINTF) '%s\n' ']]></script>'; }
+override wrapplaintext = { $(PRINTF) '%s\n%s' '<?xml version="1.0"?>' '<script xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$1)"><![CDATA['; $(TR) '\000\013\014' '\032\011\012' <$(call quote,$(abspath $1)) | $(SED) "$$($(PRINTF) '%b' 's/]]>/]]]]><!\\[CDATA\\[>/g\ns/\0357\0277\0276/�/g\ns/\0357\0277\0277/�/g\n$$!s/\\r$$//g\ns/\\r/\\n/g\n$$!s/\0302\0205$$//g\ns/\0302\0205/\\n/g\ns/\0342\0200\0250/\\n/g\ns/[\0001\0002\0003\0004\0005\0006\0007\0010]/�/g\ns/[\0016\0017\0020\0021\0022\0023\0024\0025\0026\0027\0031\0032\0033\0034\0035\0036\0037]/�/g')"; $(PRINTF) '%s\n' ']]></script>'; }
 
 # (callable) Check if the provided X·M·L file is X·M·L 1.1, and if so, coerce to X·M·L 1.0 as best as possible, printing the result (or the original file contents) to `stdout´.
 #
 # The X·M·L declaration will be dropped and character escapes for C0 control codes will be replaced with a literal `U+0091 PRIVATE USE ONE´, which is invalid in X·M·L 1.1, but valid X·M·L 1.0 (making the replacement obvious).
 #
 # This isn’t a perfect substitution (it makes some assumptions about the format of the underlying X·M·L), but it should be workable for most sensible, welformed files.
 
 # (callable) Check if the provided X·M·L file is X·M·L 1.1, and if so, coerce to X·M·L 1.0 as best as possible, printing the result (or the original file contents) to `stdout´.
 #
 # The X·M·L declaration will be dropped and character escapes for C0 control codes will be replaced with a literal `U+0091 PRIVATE USE ONE´, which is invalid in X·M·L 1.1, but valid X·M·L 1.0 (making the replacement obvious).
 #
 # This isn’t a perfect substitution (it makes some assumptions about the format of the underlying X·M·L), but it should be workable for most sensible, welformed files.
-override serializexml = $(SED) "$$($(PRINTF) '%b' '/<?xml[ \t]\\{1,\\}version=[\0042\0047]1.1/,$${ s/<?xml[^>]*?>/<!--<?xml version=\00421.1\0042?>-->/\n s/&\0043x0*[12345678BCEFbcef];/\0302\0221/g\n s/&\0043x0*1[0123456789ABCDEFabcdef];/\0302\0221/g\n s/&\00430*[12345678];/\0302\0221/g\n s/&\00430*1[12456789];/\0302\0221/g\n s/&\00430*2[0123456789];/\0302\0221/g\n s/&\00430*3[01];/\0302\0221/g\n}')" <$(call quote,$1) | $(SED) "$$($(PRINTF) '%b' ':a\n/^\\n*$$/{ $$d\n N\n ba\n}')"
+override serializexml = $(SED) "$$($(PRINTF) '%b' '/<?xml[ \t]\\{1,\\}version=[\0042\0047]1.1/,$${ s/<?xml[^>]*?>/<!--<?xml version=\00421.1\0042?>-->/\n s/&\0043x0*[12345678BCEFbcef];/\0302\0221/g\n s/&\0043x0*1[0123456789ABCDEFabcdef];/\0302\0221/g\n s/&\00430*[12345678];/\0302\0221/g\n s/&\00430*1[12456789];/\0302\0221/g\n s/&\00430*2[0123456789];/\0302\0221/g\n s/&\00430*3[01];/\0302\0221/g\n}')" <$(call quote,$(abspath $1)) | $(SED) "$$($(PRINTF) '%b' ':a\n/^\\n*$$/{ $$d\n N\n ba\n}')"
 
 # ─ ¶ Phony Targets ───────────────────────────────────────────────────
 
 
 # ─ ¶ Phony Targets ───────────────────────────────────────────────────
 
@@ -607,7 +624,7 @@ install : $(call installed,$(recursivefiles) $(installablefiles)) ;
 
 # List all source files and includes and their computed types.
 list :
 
 # 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)), →|<\0033[4m/$(call destination,$(file))\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 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 '
 
 # Lists out the destinations of all resulting files (relative to `DESTDIR´).
 listout :
 
 # Lists out the destinations of all resulting files (relative to `DESTDIR´).
 listout :
@@ -648,12 +665,6 @@ $(THISDIR)/GNUmakefile : $(BUILDDIR)/transform.xslt
 
 # ─ ¶ Build Targets ───────────────────────────────────────────────────
 
 
 # ─ ¶ Build Targets ───────────────────────────────────────────────────
 
-# Generate R·D·F metadata for files.
-$(call metadata,$(sourcefiles) $(sourceincludes)) : % : $$(call datadata,$$@) $(THISDIR)/.metadata-format-changed-since $(typeupdates)
-       $(call inform,$(PRINTF) '%s\n' $(call quote,Generating metadata for `$<´…) >&2)
-       $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent){ if $(TEST) ! -f $(call quote,$(BUILDDIR)/.mtime); then $(PRINTF) '%b' '\n' >|$(call quote,$(BUILDDIR)/.mtime); fi; $(TOUCH) -r $(call quote,$<) $(call quote,$(BUILDDIR)/.mtime); $(DIFF) -u $(call quote,$(BUILDDIR)/.mtime) /dev/null | $(SED) '1!d;s/.*   \([^ ]*\) \([^ ]*\).*$$/\1T\2Z/'; $(CKSUM) $(call quote,$<) | $(SED) 's/[ ].*//'; } | $(xargsmultiquote) | $(XARGS) -E '' $(PRINTF) '<?xml version="1.0"?><书社vocab:$(if $(filter $<,$(sourceincludes)),IncludeFile,SourceFile) xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#" xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:" rdf:about="%s" 书社vocab:path="%s" nfo:fileUrl="%s"><nie:interpretedAs>$(if $(filter $<,$(assetfiles)),<nfo:InformationElement nie:mimeType="%s"/>,<nfo:PlainTextDocument nie:mimeType="%s"/>)</nie:interpretedAs><书社vocab:hasParsedFile nfo:fileUrl="%s"/><nfo:fileLastModified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">%s</nfo:fileLastModified><nfo:hasHash nfo:hashAlgorithm="CRC32" nfo:hashValue="%s"/></书社vocab:$(if $(filter $<,$(sourceincludes)),IncludeFile,SourceFile)>' $(call quote,$(call attresc,$(call localuri,$<))) $(call quote,$(call attresc,$(if $(filter $<,$(sourceincludes)),$(call includepath,$<),$(call sourcepath,$<)))) $(call quote,$(call attresc,$(call fileuri,$<))) $(call quote,$(call attresc,$(call typeoffile,$<))) $(call quote,$(call attresc,$(call fileuri,$(call parsed,$<)))) >|$(call quote,$@)
-
 # Parse the files.
 #
 # Even plain X·M·L files are parsed, because they may contain X·H·T·M·L `<script>´ elements which contain other kinds of data.
 # Parse the files.
 #
 # Even plain X·M·L files are parsed, because they may contain X·H·T·M·L `<script>´ elements which contain other kinds of data.
@@ -661,12 +672,23 @@ $(call metadata,$(sourcefiles) $(sourceincludes)) : % : $$(call datadata,$$@) $(
 $(call parsed,$(sourcefiles) $(sourceincludes)) : % : $$(call unparsed,$$@) $(BUILDDIR)/parser.xslt $(PARSERLIBS) $(typeupdates)
        $(call inform,$(PRINTF) '%s\n' $(call quote,Processing `$<´…) >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
 $(call parsed,$(sourcefiles) $(sourceincludes)) : % : $$(call unparsed,$$@) $(BUILDDIR)/parser.xslt $(PARSERLIBS) $(typeupdates)
        $(call inform,$(PRINTF) '%s\n' $(call quote,Processing `$<´…) >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<?xml version="1.0"?><object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$<)" data="$(call datauri,$<)"/>) >|$(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(call serializexml,$<)) | $(XSLTPROC) --nonet --novalid --nomkdir --nowrite --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<))$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/parser.xslt) - >|$(call quote,$@))
+       $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<?xml version="1.0"?><parsed xmlns="urn:fdc:ladys.computer:20231231:Shu1She4"><result><object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$<)" data="$(call datauri,$<)"/></result></parsed>) >|$(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(call serializexml,$<)) | $(XSLTPROC) --nonet --novalid --nomkdir --nowrite --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<))$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(abspath $(BUILDDIR)/parser.xslt)) - >|$(call quote,$@))
+
+# Extract the results from the parsed files.
+$(call parseresult,$(sourcefiles) $(sourceincludes)) : % : $$(call parsed,$$(call parsesource,$$@))
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(PRINTF) '%s\n' '<transform xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:s="urn:fdc:ladys.computer:20231231:Shu1She4" version="1.0"><template match="/"><copy-of select="s:parsed/s:result/node()"/></template></transform>' | $(XSLTPROC) --nonet --novalid --nomkdir --nowrite - $(call quote,$<) >|$(call quote,$@)
+
+# Generate R·D·F metadata for files.
+$(call metadata,$(sourcefiles) $(sourceincludes)) : % : $$(call datadata,$$@) $(THISDIR)/.metadata-format-changed-since
+       $(call inform,$(PRINTF) '%s\n' $(call quote,Generating metadata for `$<´…) >&2)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent){ if $(TEST) ! -f $(call quote,$(BUILDDIR)/.mtime); then $(PRINTF) '%b' '\n' >|$(call quote,$(BUILDDIR)/.mtime); fi; $(TOUCH) -r $(call quote,$<) $(call quote,$(BUILDDIR)/.mtime); $(DIFF) -u $(call quote,$(BUILDDIR)/.mtime) /dev/null | $(SED) '1!d;s/.*   \([^ ]*\) \([^ ]*\).*$$/\1T\2Z/'; $(CKSUM) $(call quote,$<) | $(SED) 's/[ ].*//'; } | $(xargsmultiquote) | $(XARGS) -E '' $(PRINTF) '<?xml version="1.0"?><书社vocab:$(if $(filter $<,$(sourceincludes)),IncludeFile,SourceFile) xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#" xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:" rdf:about="%s" 书社vocab:path="%s" nfo:fileUrl="%s"><nie:interpretedAs>$(if $(filter $<,$(assetfiles)),<nfo:InformationElement nie:mimeType="%s"/>,<nfo:PlainTextDocument nie:mimeType="%s"/>)</nie:interpretedAs><书社vocab:hasParsedFile nfo:fileUrl="%s"/><书社vocab:hasParsedFileWithMetadata nfo:fileUrl="%s"/><nfo:fileLastModified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">%s</nfo:fileLastModified><nfo:hasHash nfo:hashAlgorithm="CRC32" nfo:hashValue="%s"/></书社vocab:$(if $(filter $<,$(sourceincludes)),IncludeFile,SourceFile)>' $(call quote,$(call attresc,$(call localuri,$<))) $(call quote,$(call attresc,$(if $(filter $<,$(sourceincludes)),$(call includepath,$<),$(call sourcepath,$<)))) $(call quote,$(call attresc,$(call fileuri,$<))) $(call quote,$(call attresc,$(call typeoffile,$<))) $(call quote,$(call attresc,$(call fileuri,$(call parseresult,$<)))) $(call quote,$(call attresc,$(call fileuri,$(call parsed,$<)))) >|$(call quote,$@)
 
 # Collect the metadata into a single file, and generate the dependencies and destinations files as side·effects.
 #
 # Doing this all in one step reduces the number of calls to `xsltproc´ required, but requires that it be called from the build directory (necessitating a subshell).
 
 # Collect the metadata into a single file, and generate the dependencies and destinations files as side·effects.
 #
 # Doing this all in one step reduces the number of calls to `xsltproc´ required, but requires that it be called from the build directory (necessitating a subshell).
-$(BUILDDIR)/dependencies $(BUILDDIR)/destinations $(BUILDDIR)/metadata : $(call diffprereqs,metadatas,$(call metadata,$(sort $(sourcefiles) $(sourceincludes)))) $(call parsed,$(filter-out $(assetfiles),$(sourcefiles) $(sourceincludes))) $(THISDIR)/lib/expandmetadata.xslt
+$(BUILDDIR)/dependencies $(BUILDDIR)/destinations $(BUILDDIR)/metadata : $(call diffprereqs,metadatas,$(call metadata,$(sort $(sourcefiles) $(sourceincludes)))) $$(call parseresult,$(sourcefiles) $(sourceincludes)) $(THISDIR)/lib/expandmetadata.xslt
        $(call inform,$(PRINTF) '%s\n' 'Compiling metadata…' >&2)
        $(silent){ $(PRINTF) '<?xml version="1.0"?><rdf:RDF xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#" xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:"><书社vocab:BuildDirectory nfo:fileUrl="%s"/>' $(call quote,$(call attresc,$(call fileuri,$(BUILDDIR)))); {$(foreach meta,$(call metadata,$(sort $(sourcefiles) $(sourceincludes))), $(CAT) $(call quote,$(meta));) } | $(SED) 's/<?xml version="1.0"?>//g'; $(PRINTF) '%s\n' '</rdf:RDF>'; } | ( $(CD) $(call quote,$(BUILDDIR)); $(XSLTPROC) --nonet --novalid --nomkdir $(call quote,$(abspath $(THISDIR)/lib/expandmetadata.xslt)) - ) | $(XMLLINT) --nonet --nsclean - >|$(call quote,$(BUILDDIR)/metadata)
 
        $(call inform,$(PRINTF) '%s\n' 'Compiling metadata…' >&2)
        $(silent){ $(PRINTF) '<?xml version="1.0"?><rdf:RDF xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#" xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:"><书社vocab:BuildDirectory nfo:fileUrl="%s"/>' $(call quote,$(call attresc,$(call fileuri,$(BUILDDIR)))); {$(foreach meta,$(call metadata,$(sort $(sourcefiles) $(sourceincludes))), $(CAT) $(call quote,$(meta));) } | $(SED) 's/<?xml version="1.0"?>//g'; $(PRINTF) '%s\n' '</rdf:RDF>'; } | ( $(CD) $(call quote,$(BUILDDIR)); $(XSLTPROC) --nonet --novalid --nomkdir $(call quote,$(abspath $(THISDIR)/lib/expandmetadata.xslt)) - ) | $(XMLLINT) --nonet --nsclean - >|$(call quote,$(BUILDDIR)/metadata)
 
@@ -689,10 +711,10 @@ $(BUILDDIR)/transform.xslt : $(BUILDDIR)/transform.catalog $(BUILDDIR)/metadata
 # • When the metadata of ⹐source files they depend on⹑ change.
 #
 # This is to reduce the number of needless regenerations of files with no substantial change.
 # • When the metadata of ⹐source files they depend on⹑ change.
 #
 # This is to reduce the number of needless regenerations of files with no substantial change.
-$(call compiled,$(compilablefiles)) : $(BUILDDIR)/results/% : $$(call parsed,$$(call uncompiled,$$@)) $$(call parsed,$$(call dependencies,$$(call uncompiled,$$@))) $(BUILDDIR)/transform.catalog $(THISDIR)/lib/catalog2transform.xslt $(TRANSFORMLIBS) $$(call metadata,$$(call dependencies,$$(call uncompiled,$$@)))
+$(call compiled,$(compilablefiles)) : $(BUILDDIR)/results/% : $$(call parseresult,$$(call uncompiled,$$@)) $$(call parseresult,$$(call dependencies,$$(call uncompiled,$$@))) $(BUILDDIR)/transform.catalog $(THISDIR)/lib/catalog2transform.xslt $(TRANSFORMLIBS) $$(call metadata,$$(call dependencies,$$(call uncompiled,$$@)))
        $(call inform,$(PRINTF) '%s\n' $(call quote,Compiling </$*>…) >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(call inform,$(PRINTF) '%s\n' $(call quote,Compiling </$*>…) >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite --stringparam METADATA 'metadata' --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@)))$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<) >|$(call quote,$@)
+       $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite --stringparam METADATA 'metadata' --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@)))$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) --stringparam DESTINATION $(call quote,$*) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<) >|$(call quote,$@)
 
 # Create the final files from the compiled results (or error in the case of recursive ones).
 $(call built,$(compilablefiles)) : $(BUILDDIR)/public/% : $(BUILDDIR)/results/% $(THISDIR)/lib/archive2extractor.xslt
 
 # Create the final files from the compiled results (or error in the case of recursive ones).
 $(call built,$(compilablefiles)) : $(BUILDDIR)/public/% : $(BUILDDIR)/results/% $(THISDIR)/lib/archive2extractor.xslt
@@ -808,10 +830,10 @@ ifeq ($(twostep),)
 shusheopts := MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:default'
 else
 # (overridable) Options to use when calling ⛩📰 书社 the first time.
 shusheopts := MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:default'
 else
 # (overridable) Options to use when calling ⛩📰 书社 the first time.
-shushedataopts := INCLUDEDIR=$(call quote,$(DATADIR)) BUILDDIR=$(call quote,$(BUILDDIR)/data) FINDRULES=$(subst $$,$$$$,$(call quote,$(FINDRULES) -a '(' $(FINDDATARULES) ')')) FINDINCLUDERULES=$(subst $$,$$$$,$(call quote,$(FINDINCLUDERULES))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:default'
+shushedataopts := $(and $(DATAOPTS),$(DATAOPTS)$(space))INCLUDEDIR=$(call varquote,$(DATADIR)) BUILDDIR=$(call varquote,$(BUILDDIR)/data) FINDRULES=$(call varquote,$(FINDRULES) -a '(' $(FINDDATARULES) ')') FINDINCLUDERULES=$(call varquote,$(FINDINCLUDERULES)) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:default'
 
 # (overridable) Options to use when calling ⛩📰 书社 the second time.
 
 # (overridable) Options to use when calling ⛩📰 书社 the second time.
-shushesiteopts := INCLUDEDIR=$(call quote,$(INCLUDEDIR) $(BUILDDIR)/data/public) BUILDDIR=$(call quote,$(BUILDDIR)/site) FINDRULES=$(subst $$,$$$$,$(call quote,$(FINDRULES) -a '!' '(' $(FINDDATARULES) ')')) FINDINCLUDERULES=$(subst $$,$$$$,$(call quote,$(FINDINCLUDERULES))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:default'
+shushesiteopts := INCLUDEDIR=$(call varquote,$(INCLUDEDIR) $(BUILDDIR)/data/public) BUILDDIR=$(call varquote,$(BUILDDIR)/site) FINDRULES=$(call varquote,$(FINDRULES) -a '!' '(' $(FINDDATARULES) ')') FINDINCLUDERULES=$(call varquote,$(FINDINCLUDERULES)) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:default'
 endif
 
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 endif
 
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
index d4399e35a858c3b514e335e22a209150c60904b8..4671064e2238f8d323ca98ac44295464917ffa96 100644 (file)
@@ -188,6 +188,7 @@ This document uses a few name·space prefixes, with the following
 |    `exsl:` | `http://exslt.org/common`                     |
 | `exslstr:` | `http://exslt.org/strings`                    |
 |    `html:` | `http://www.w3.org/1999/xhtml`                |
 |    `exsl:` | `http://exslt.org/common`                     |
 | `exslstr:` | `http://exslt.org/strings`                    |
 |    `html:` | `http://www.w3.org/1999/xhtml`                |
+|     `rdf:` | `http://www.w3.org/1999/02/22-rdf-syntax-ns#` |
 |     `svg:` | `http://www.w3.org/2000/svg`                  |
 |   `xlink:` | `http://www.w3.org/1999/xlink`                |
 |    `xslt:` | `http://www.w3.org/1999/XSL/Transform`        |
 |     `svg:` | `http://www.w3.org/2000/svg`                  |
 |   `xlink:` | `http://www.w3.org/1999/xlink`                |
 |    `xslt:` | `http://www.w3.org/1999/XSL/Transform`        |
@@ -307,6 +308,12 @@ The following additional variables can be used to control the behaviour
     default, to enable additional rules without overriding the existing
     ones.
 
     default, to enable additional rules without overriding the existing
     ones.
 
+- **`DATAOPTS`:**
+  Additional options to use when calling Make during the first stage of a two‐stage build using `DATADIR`.
+
+  This can be used to override variables which are only applicable during the second stage.
+  Note that when supplying this variable on the shell, it will need to be double‐quoted.
+
 - **`DATAEXT`:**
   A list of file extensions which signify “data” files during a two‐stage build using `DATADIR`.
 
 - **`DATAEXT`:**
   A list of file extensions which signify “data” files during a two‐stage build using `DATADIR`.
 
@@ -541,6 +548,18 @@ These include :⁠—
 - A `@书社:media-type` attribute, giving the identified media type of
     the plaintext node.
 
 - A `@书社:media-type` attribute, giving the identified media type of
     the plaintext node.
 
+### Parsed metadata
+
+It is possible to extract metadata from a document at the same time as
+  it is being parsed.
+This is done by creating result elements in the `书社:about` mode;
+  these should be R·D·F property elements which apply to the conceptual
+  entity that is the document being parsed.
+
+During transformation, metadata for the file with identifier `$FILE`
+  can be read from the children of
+  `$书社:about//*[@rdf:about=$FILE]/nie:interpretedAs/*`.
+
 ## Output Redirection
 
 By default, ⛩📰 书社 installs files to the same location in `DESTDIR`
 ## Output Redirection
 
 By default, ⛩📰 书社 installs files to the same location in `DESTDIR`
@@ -550,6 +569,9 @@ This behaviour can be customized by setting the `@书社:destination`
 This attribute is read after parsing, but before transformation (where
   it is silently dropped).
 
 This attribute is read after parsing, but before transformation (where
   it is silently dropped).
 
+Multiple destinations can be provided if the same file should be output to multiple places.
+The file is retransformed each time, with the value of the `DESTINATION` global param set appropriately.
+
 ## Embedding
 
 Documents can be embedded in other documents using a `<书社:link>`
 ## Embedding
 
 Documents can be embedded in other documents using a `<书社:link>`
@@ -614,6 +636,9 @@ Transforms are used to convert X·M·L files into their final output,
   This conversion happens during the finalization phase, after the main
     transformation.
 
   This conversion happens during the finalization phase, after the main
     transformation.
 
+- **`transforms/expansion.xslt`:**
+  Performs embedding, as described above.
+
 - **`transforms/metadata.xslt`:**
   Provides basic `<html:head>` metadata.
   This metadata is generated from `<html:meta>` elements with one of
 - **`transforms/metadata.xslt`:**
   Provides basic `<html:head>` metadata.
   This metadata is generated from `<html:meta>` elements with one of
@@ -684,6 +709,28 @@ The following params are made available globally in parsers and
 - **`THISREV`:**
   The value of the `THISREV` variable (if present).
 
 - **`THISREV`:**
   The value of the `THISREV` variable (if present).
 
+In transforms, the following params are additionally available :⁠—
+
+- **`DESTINATION`:**
+  The destination being targeted by this transform.
+
+- **`书社:about`:**
+  R·D·F metadata about all of the documents ⛩📰 书社 knows about.
+  Use `$书社:about//*[@rdf:about=$IDENTIFIER]` to get the metadata for
+    the current document.
+
+- **`书社:source`:**
+  The parsed source document being transformed, prior to any expansion.
+
+- **`书社:expansion`:**
+  The document after the all embeds have been expanded.
+  Unavailable during the `书社:expand` stage.
+
+- **`书社:result`:**
+  The document after the main set of transformations have been applied.
+  Only available during the `书社:finalize` stage, where it is used to
+    apply output wrapping and other clean·up.
+
 ## Output Wrapping
 
 Provided at least one toplevel result element belongs to the H·T·M·L
 ## Output Wrapping
 
 Provided at least one toplevel result element belongs to the H·T·M·L
index a2eab127f482dd3915bec5b167a087f2cfd5ec0c..b24495c0ccb9ddbd910b92ecd7a48ade74832162 100644 (file)
@@ -1,24 +1,25 @@
 <?xml version="1.0"?>
 <!--
 <?xml version="1.0"?>
 <!--
-SPDX-FileCopyrightText: 2023, 2024 Lady <https://www.ladys.computer/about/#lady>
+SPDX-FileCopyrightText: 2023, 2024, 2025 Lady <https://www.ladys.computer/about/#lady>
 SPDX-License-Identifier: MPL-2.0
 -->
 <!--
 ⁌ ⛩📰 书社 ∷ lib/catalog2parser.xslt
 
 SPDX-License-Identifier: MPL-2.0
 -->
 <!--
 ⁌ ⛩📰 书社 ∷ lib/catalog2parser.xslt
 
-© 2023–2024 Lady [@ Ladys Computer].
+© 2023–2025 Lady [@ Ladys Computer].
 
 This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
 If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 -->
 
 This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
 If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 -->
+<!DOCTYPE transform [
+       <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+]>
 <transform
        xmlns="http://www.w3.org/1999/XSL/Transform"
        xmlns:catalog="urn:oasis:names:tc:entity:xmlns:xml:catalog"
        xmlns:exsl="http://exslt.org/common"
        xmlns:exslstr="http://exslt.org/strings"
        xmlns:html="http://www.w3.org/1999/xhtml"
 <transform
        xmlns="http://www.w3.org/1999/XSL/Transform"
        xmlns:catalog="urn:oasis:names:tc:entity:xmlns:xml:catalog"
        xmlns:exsl="http://exslt.org/common"
        xmlns:exslstr="http://exslt.org/strings"
        xmlns:html="http://www.w3.org/1999/xhtml"
-       xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#"
-       xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xslt="http://www.w3.org/1999/XSL/TransformAlias"
        xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xslt="http://www.w3.org/1999/XSL/TransformAlias"
        xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
@@ -122,28 +123,48 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                </xslt:for-each>
                        </xslt:template>
                        <xslt:template match="/">
                                </xslt:for-each>
                        </xslt:template>
                        <xslt:template match="/">
-                               <xslt:apply-templates select="node()" mode="书社:parse"/>
+                               <xslt:variable name="about">
+                                       <xslt:apply-templates select="node()" mode="书社:about"/>
+                               </xslt:variable>
+                               <xslt:variable name="result">
+                                       <xslt:apply-templates select="node()" mode="书社:parse"/>
+                               </xslt:variable>
+                               <xslt:element name="书社:parsed">
+                                       <xslt:element name="书社:result">
+                                               <xslt:copy-of select="$result"/>
+                                       </xslt:element>
+                                       <xslt:element name="书社:metadata">
+                                               <xslt:element name="rdf:RDF" namespace="&rdf;">
+                                                       <xslt:element name="rdf:Description" namespace="&rdf;">
+                                                               <xslt:copy-of select="$about"/>
+                                                       </xslt:element>
+                                               </xslt:element>
+                                       </xslt:element>
+                               </xslt:element>
                        </xslt:template>
                        <xslt:template match="@*|node()" priority="-1">
                                <xslt:copy>
                                        <xslt:apply-templates select="@*|node()" mode="书社:parse"/>
                                </xslt:copy>
                        </xslt:template>
                        </xslt:template>
                        <xslt:template match="@*|node()" priority="-1">
                                <xslt:copy>
                                        <xslt:apply-templates select="@*|node()" mode="书社:parse"/>
                                </xslt:copy>
                        </xslt:template>
+                       <xslt:template match="@*|node()" mode="书社:about" priority="-1">
+                               <xslt:apply-templates select="@*|node()" mode="书社:about"/>
+                       </xslt:template>
                        <xslt:template match="html:script[@type]" mode="书社:parse" priority="1">
                                <xslt:variable name="parserdiv" select="exsl:node-set($书社:parsers)//html:div[html:dd=current()/@type]"/>
                                <xslt:choose>
                                        <xslt:when test="$parserdiv">
                        <xslt:template match="html:script[@type]" mode="书社:parse" priority="1">
                                <xslt:variable name="parserdiv" select="exsl:node-set($书社:parsers)//html:div[html:dd=current()/@type]"/>
                                <xslt:choose>
                                        <xslt:when test="$parserdiv">
-                                               <xslt:variable name="result">
+                                               <xslt:variable name="result-fragment">
                                                        <xslt:apply-templates select="."/>
                                                </xslt:variable>
                                                        <xslt:apply-templates select="."/>
                                                </xslt:variable>
-                                               <xslt:variable name="reparsed-result">
-                                                       <xslt:apply-templates select="exsl:node-set($result)/node()" mode="书社:parse"/>
+                                               <xslt:variable name="applied-fragment">
+                                                       <xslt:call-template name="书社:apply-parsed-by">
+                                                               <xslt:with-param name="id" select="string($parserdiv/html:dt)"/>
+                                                               <xslt:with-param name="media-type" select="string(@type)"/>
+                                                               <xslt:with-param name="result" select="exsl:node-set($result-fragment)"/>
+                                                       </xslt:call-template>
                                                </xslt:variable>
                                                </xslt:variable>
-                                               <xslt:call-template name="书社:apply-parsed-by">
-                                                       <xslt:with-param name="id" select="string($parserdiv/html:dt)"/>
-                                                       <xslt:with-param name="media-type" select="string(@type)"/>
-                                                       <xslt:with-param name="result" select="exsl:node-set($reparsed-result)"/>
-                                               </xslt:call-template>
+                                               <xslt:apply-templates select="exsl:node-set($applied-fragment)/node()" mode="书社:parse"/>
                                        </xslt:when>
                                        <xslt:otherwise>
                                                <xslt:apply-templates select="."/>
                                        </xslt:when>
                                        <xslt:otherwise>
                                                <xslt:apply-templates select="."/>
index ce94067fa445d9b88b3fd63ba1f37836d62c40e4..747225b122f43cc31878f6e86c6fcdf3575f25ad 100644 (file)
@@ -23,7 +23,6 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
        xmlns:exslfunc="http://exslt.org/functions"
        xmlns:exslstr="http://exslt.org/strings"
        xmlns:html="&xhtml;"
        xmlns:exslfunc="http://exslt.org/functions"
        xmlns:exslstr="http://exslt.org/strings"
        xmlns:html="&xhtml;"
-       xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#"
        xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#"
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:svg="http://www.w3.org/2000/svg"
        xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#"
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:svg="http://www.w3.org/2000/svg"
@@ -53,8 +52,9 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                </if>
                        </for-each>
                </variable>
                                </if>
                        </for-each>
                </variable>
-               <xslt:transform exclude-result-prefixes="nie nfo" extension-element-prefixes="exsl exslfunc exslstr" version="1.0">
+               <xslt:transform exclude-result-prefixes="nfo 书社vocab" extension-element-prefixes="exsl exslfunc exslstr" version="1.0">
                        <xslt:param name="BUILDTIME" select="'1972-12-31T00:00:00Z'"/>
                        <xslt:param name="BUILDTIME" select="'1972-12-31T00:00:00Z'"/>
+                       <xslt:param name="DESTINATION" select="false()"/>
                        <xslt:param name="IDENTIFIER" select="false()"/>
                        <xslt:param name="SRCREV" select="false()"/>
                        <xslt:param name="THISREV" select="false()"/>
                        <xslt:param name="IDENTIFIER" select="false()"/>
                        <xslt:param name="SRCREV" select="false()"/>
                        <xslt:param name="THISREV" select="false()"/>
@@ -86,6 +86,13 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                </apply-templates>
                        </xslt:variable>
                        <xslt:variable name="书社:about" select="exsl:node-set($书社:about-fragment)"/>
                                </apply-templates>
                        </xslt:variable>
                        <xslt:variable name="书社:about" select="exsl:node-set($书社:about-fragment)"/>
+                       <for-each select="//catalog:uri">
+                               <xslt:include href="{@uri}">
+                                       <attribute name="书社:id">
+                                               <value-of select="@name"/>
+                                       </attribute>
+                               </xslt:include>
+                       </for-each>
                        <xslt:variable name="书社:expansion-fragment">
                                <xslt:apply-templates select="$书社:source/node()" mode="书社:expand"/>
                        </xslt:variable>
                        <xslt:variable name="书社:expansion-fragment">
                                <xslt:apply-templates select="$书社:source/node()" mode="书社:expand"/>
                        </xslt:variable>
@@ -100,13 +107,6 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                        </xslt:variable>
                        <xslt:variable name="书社:result" select="书社:document-with-attributes-applied(exsl:node-set($书社:result-fragment))"/>
                        <xslt:variable name="书社:destination" select="string($书社:about//*[@rdf:about=$IDENTIFIER]/@书社vocab:destination)"/>
                        </xslt:variable>
                        <xslt:variable name="书社:result" select="书社:document-with-attributes-applied(exsl:node-set($书社:result-fragment))"/>
                        <xslt:variable name="书社:destination" select="string($书社:about//*[@rdf:about=$IDENTIFIER]/@书社vocab:destination)"/>
-                       <for-each select="//catalog:uri">
-                               <xslt:include href="{@uri}">
-                                       <attribute name="书社:id">
-                                               <value-of select="@name"/>
-                                       </attribute>
-                               </xslt:include>
-                       </for-each>
                        <xslt:template name="书社:apply-attributes">
                                <xslt:param name="context-nodes" select="/.."/>
                                <xslt:param name="destination-nodes" select="/.."/>
                        <xslt:template name="书社:apply-attributes">
                                <xslt:param name="context-nodes" select="/.."/>
                                <xslt:param name="destination-nodes" select="/.."/>
@@ -319,132 +319,12 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                        <xslt:apply-templates select="@*|node()" mode="书社:apply"/>
                                </xslt:copy>
                        </xslt:template>
                                        <xslt:apply-templates select="@*|node()" mode="书社:apply"/>
                                </xslt:copy>
                        </xslt:template>
-                       <xslt:template match="书社:link[@xlink:show='embed' and (not(@xlink:actuate) or @xlink:actuate='none')]" mode="书社:expand" priority="1">
-                               <xslt:variable name="link" select="."/>
-                               <xslt:variable name="identifier" select="string(@xlink:href)"/>
-                               <xslt:variable name="is-dir" select="substring($identifier, string-length($identifier))='/'"/>
-                               <xslt:variable name="included" select="$书社:about//*[@rdf:about=$identifier or $is-dir and starts-with(@rdf:about, $identifier)]"/>
-                               <xslt:choose>
-                                       <xslt:when test="$included">
-                                               <xslt:for-each select="$included">
-                                                       <xslt:sort select="@rdf:about" data-type="text" lang="zxx" case-order="upper-first"/>
-                                                       <xslt:variable name="uri" select="书社vocab:hasParsedFile/@nfo:fileUrl"/>
-                                                       <xslt:variable name="expanded">
-                                                               <xslt:apply-templates select="document($uri)" mode="书社:expand">
-                                                                       <xslt:with-param name="identifier" select="string(@rdf:about)"/>
-                                                               </xslt:apply-templates>
-                                                       </xslt:variable>
-                                                       <xslt:for-each select="exsl:node-set($expanded)/node()">
-                                                               <xslt:copy>
-                                                                       <xslt:choose>
-                                                                               <xslt:when test="self::html:*">
-                                                                                       <xslt:variable name="existing-types" select="exslstr:tokenize(@itemtype)"/>
-                                                                                       <xslt:attribute name="itemscope">itemscope</xslt:attribute>
-                                                                                       <xslt:attribute name="itemtype">
-                                                                                               <xslt:for-each select="$existing-types/token[string()!='&书社;:document']">
-                                                                                                       <xslt:if test="position()!=1">
-                                                                                                               <xslt:text>
-                                                                                                                       <text> </text>
-                                                                                                               </xslt:text>
-                                                                                                       </xslt:if>
-                                                                                                       <xslt:value-of select="."/>
-                                                                                               </xslt:for-each>
-                                                                                               <xslt:if test="not($existing-types/token[string()='&书社;:embed'])">
-                                                                                                       <xslt:if test="$existing-types/token[string()!='&书社;:document']">
-                                                                                                               <xslt:text>
-                                                                                                                       <text> </text>
-                                                                                                               </xslt:text>
-                                                                                                       </xslt:if>
-                                                                                                       <xslt:text>
-                                                                                                               <text>&书社;:embed</text>
-                                                                                                       </xslt:text>
-                                                                                               </xslt:if>
-                                                                                       </xslt:attribute>
-                                                                                       <xslt:choose>
-                                                                                               <xslt:when test="$link/@书社:archived-as">
-                                                                                                       <xslt:copy-of select="$link/@书社:archived-as"/>
-                                                                                               </xslt:when>
-                                                                                               <xslt:when test="@书社:archived-as">
-                                                                                                       <xslt:copy-of select="@书社:archived-as"/>
-                                                                                               </xslt:when>
-                                                                                       </xslt:choose>
-                                                                                       <xslt:copy-of select="@*[not(namespace-uri()='' and (local-name()='itemscope' or local-name()='itemtype')) and not(namespace-uri()='&书社;' and local-name()='archived-as')]|node()"/>
-                                                                               </xslt:when>
-                                                                               <xslt:otherwise>
-                                                                                       <xslt:choose>
-                                                                                               <xslt:when test="self::* and $link/@书社:archived-as">
-                                                                                                       <xslt:copy-of select="$link/@书社:archived-as"/>
-                                                                                               </xslt:when>
-                                                                                               <xslt:when test="@书社:archived-as">
-                                                                                                       <xslt:copy-of select="@书社:archived-as"/>
-                                                                                               </xslt:when>
-                                                                                       </xslt:choose>
-                                                                                       <xslt:copy-of select="@*[not(namespace-uri()='&书社;' and local-name()='archived-as')]|node()"/>
-                                                                               </xslt:otherwise>
-                                                                       </xslt:choose>
-                                                               </xslt:copy>
-                                                       </xslt:for-each>
-                                               </xslt:for-each>
-                                       </xslt:when>
-                                       <xslt:otherwise>
-                                               <xslt:copy>
-                                                       <xslt:apply-templates select="@*|node()" mode="书社:expand"/>
-                                               </xslt:copy>
-                                       </xslt:otherwise>
-                               </xslt:choose>
-                       </xslt:template>
-                       <xslt:template match="/node()" mode="书社:expand" priority="0">
-                               <xslt:param name="identifier" select="$IDENTIFIER"/>
-                               <xslt:copy>
-                                       <xslt:if test="self::*">
-                                               <xslt:attribute name="书社:cksum">
-                                                       <xslt:value-of select="$书社:about//*[@rdf:about=$identifier]/nfo:hasHash[@nfo:hashAlgorithm='CRC32']/@nfo:hashValue"/>
-                                               </xslt:attribute>
-                                               <xslt:attribute name="书社:identifier">
-                                                       <xslt:value-of select="$identifier"/>
-                                               </xslt:attribute>
-                                               <xslt:attribute name="书社:mtime">
-                                                       <xslt:value-of select="$书社:about//*[@rdf:about=$identifier]/nfo:fileLastModified"/>
-                                               </xslt:attribute>
-                                       </xslt:if>
-                                       <xslt:choose>
-                                               <xslt:when test="self::html:*">
-                                                       <xslt:variable name="existing-types" select="exslstr:tokenize(@itemtype)"/>
-                                                       <xslt:attribute name="itemscope">itemscope</xslt:attribute>
-                                                       <xslt:attribute name="itemtype">
-                                                               <xslt:for-each select="$existing-types/token">
-                                                                       <xslt:if test="position()!=1">
-                                                                               <xslt:text>
-                                                                                       <text> </text>
-                                                                               </xslt:text>
-                                                                       </xslt:if>
-                                                                       <xslt:value-of select="."/>
-                                                               </xslt:for-each>
-                                                               <xslt:if test="not($existing-types/token[string()='&书社;:embed' or string()='&书社;:document'])">
-                                                                       <xslt:if test="$existing-types/token">
-                                                                               <xslt:text>
-                                                                                       <text> </text>
-                                                                               </xslt:text>
-                                                                       </xslt:if>
-                                                                       <xslt:text>
-                                                                               <text>&书社;:document</text>
-                                                                       </xslt:text>
-                                                               </xslt:if>
-                                                       </xslt:attribute>
-                                                       <xslt:apply-templates select="@*[not(namespace-uri()='' and (local-name()='itemscope' or local-name()='itemtype') or namespace-uri()='&书社;' and (local-name()='cksum' or local-name()='identifier' or local-name()='mtime'))]|node()" mode="书社:expand"/>
-                                               </xslt:when>
-                                               <xslt:otherwise>
-                                                       <xslt:apply-templates select="@*[not(namespace-uri()='&书社;' and (local-name()='cksum' or local-name()='identifier' or local-name()='mtime'))]|node()" mode="书社:expand"/>
-                                               </xslt:otherwise>
-                                       </xslt:choose>
-                               </xslt:copy>
-                       </xslt:template>
                        <xslt:template match="@*|node()" mode="书社:expand" priority="-1">
                                <xslt:copy>
                                        <xslt:apply-templates select="@*|node()" mode="书社:expand"/>
                                </xslt:copy>
                        </xslt:template>
                        <xslt:template match="@*|node()" mode="书社:expand" priority="-1">
                                <xslt:copy>
                                        <xslt:apply-templates select="@*|node()" mode="书社:expand"/>
                                </xslt:copy>
                        </xslt:template>
-                       <xslt:template match="text()" mode="书社:header"/>
+                       <xslt:template match="text()" mode="书社:header" priority="-1"/>
                        <xslt:template match="书社:archive" mode="书社:finalize" priority="1">
                                <xslt:copy>
                                        <xslt:apply-templates select="@*" mode="书社:finalize"/>
                        <xslt:template match="书社:archive" mode="书社:finalize" priority="1">
                                <xslt:copy>
                                        <xslt:apply-templates select="@*" mode="书社:finalize"/>
@@ -518,8 +398,8 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                        <xslt:apply-templates select="@*|node()" mode="书社:finalize"/>
                                </xslt:copy>
                        </xslt:template>
                                        <xslt:apply-templates select="@*|node()" mode="书社:finalize"/>
                                </xslt:copy>
                        </xslt:template>
-                       <xslt:template match="text()" mode="书社:footer"/>
-                       <xslt:template match="text()" mode="书社:metadata"/>
+                       <xslt:template match="text()" mode="书社:footer" priority="-1"/>
+                       <xslt:template match="text()" mode="书社:metadata" priority="-1"/>
                        <xslt:output method="xml" encoding="UTF-8" cdata-section-elements="html:script html:style html:textarea 书社:raw-output 书社:raw-text"/>
                </xslt:transform>
        </template>
                        <xslt:output method="xml" encoding="UTF-8" cdata-section-elements="html:script html:style html:textarea 书社:raw-output 书社:raw-text"/>
                </xslt:transform>
        </template>
index f2efd18209177db3a846d1053cf16955ed2a74f8..423924a3d35eb889c8ab4bd46e46a937e6d54c02 100644 (file)
@@ -1,12 +1,12 @@
 <?xml version="1.0"?>
 <!--
 <?xml version="1.0"?>
 <!--
-SPDX-FileCopyrightText: 2023, 2024 Lady <https://www.ladys.computer/about/#lady>
+SPDX-FileCopyrightText: 2023, 2024, 2025 Lady <https://www.ladys.computer/about/#lady>
 SPDX-License-Identifier: MPL-2.0
 -->
 <!--
 ⁌ ⛩📰 书社 ∷ lib/expandmetadata.xslt
 
 SPDX-License-Identifier: MPL-2.0
 -->
 <!--
 ⁌ ⛩📰 书社 ∷ lib/expandmetadata.xslt
 
-© 2023–2024 Lady [@ Ladys Computer].
+© 2023–2025 Lady [@ Ladys Computer].
 
 This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
 If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 
 This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
 If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
@@ -14,13 +14,14 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
 <transform
        xmlns="http://www.w3.org/1999/XSL/Transform"
        xmlns:exsl="http://exslt.org/common"
 <transform
        xmlns="http://www.w3.org/1999/XSL/Transform"
        xmlns:exsl="http://exslt.org/common"
+       xmlns:exslstr="http://exslt.org/strings"
        xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#"
        xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#"
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
        xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:"
        xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#"
        xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#"
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
        xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:"
-       extension-element-prefixes="exsl"
+       extension-element-prefixes="exsl exslstr"
        version="1.0"
 >
        <variable name="builddir" select="//书社vocab:BuildDirectory/@nfo:fileUrl"/>
        version="1.0"
 >
        <variable name="builddir" select="//书社vocab:BuildDirectory/@nfo:fileUrl"/>
@@ -78,37 +79,51 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                        </otherwise>
                </choose>
        </template>
                        </otherwise>
                </choose>
        </template>
+       <template match="nie:interpretedAs/*" priority="1">
+               <copy>
+                       <apply-templates select="@*|node()"/>
+                       <for-each select="../../书社vocab:hasParsedFileWithMetadata">
+                               <copy-of select="document(@nfo:fileUrl)/书社:parsed/书社:metadata/rdf:RDF/rdf:Description/node()"/>
+                       </for-each>
+               </copy>
+       </template>
        <template match="//书社vocab:SourceFile[not(nie:interpretedAs/nfo:PlainTextDocument)]" priority="1">
                <copy>
                        <apply-templates select="@*"/>
        <template match="//书社vocab:SourceFile[not(nie:interpretedAs/nfo:PlainTextDocument)]" priority="1">
                <copy>
                        <apply-templates select="@*"/>
-                       <attribute name="书社vocab:destination">
-                               <value-of select="@书社vocab:path"/>
-                       </attribute>
                        <apply-templates select="node()"/>
                        <apply-templates select="node()"/>
+                       <element name="书社vocab:destination">
+                               <value-of select="@书社vocab:path"/>
+                       </element>
                </copy>
        </template>
        <template match="//书社vocab:SourceFile[nie:interpretedAs/nfo:PlainTextDocument]" priority="1">
                <variable name="parsed" select="document(书社vocab:hasParsedFile/@nfo:fileUrl)"/>
                </copy>
        </template>
        <template match="//书社vocab:SourceFile[nie:interpretedAs/nfo:PlainTextDocument]" priority="1">
                <variable name="parsed" select="document(书社vocab:hasParsedFile/@nfo:fileUrl)"/>
-               <variable name="destination-delim" select="concat('/', $parsed/*/@书社:destination, '/')"/>
-               <variable name="destination">
-                       <choose>
-                               <when test="not(contains($destination-delim, '//') or contains($destination-delim, '/./') or contains($destination-delim, '/../'))">
-                                       <value-of select="$parsed/*/@书社:destination"/>
-                               </when>
-                               <otherwise>
-                                       <value-of select="@书社vocab:path"/>
-                               </otherwise>
-                       </choose>
+               <variable name="provided-destinations" select="normalize-space($parsed/*/@书社:destination)"/>
+               <variable name="destinations-fragment">
+                       <if test="$provided-destinations!=''">
+                               <for-each select="exslstr:tokenize($provided-destinations)">
+                                       <element name="书社vocab:destination">
+                                               <value-of select="."/>
+                                       </element>
+                               </for-each>
+                       </if>
                </variable>
                <variable name="dependencies-fragment">
                        <apply-templates select="." mode="书社:dependencies"/>
                </variable>
                <variable name="dependencies" select="exsl:node-set($dependencies-fragment)"/>
                </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">
+                               <variable name="destination-delim" select="concat('/', ., '/')"/>
+                               <if test="contains($destination-delim, '//') or contains($destination-delim, '/./') or contains($destination-delim, '/../')">
+                                       <copy-of select="."/>
+                               </if>
+                       </for-each>
+               </variable>
+               <variable name="bad-destinations" select="exsl:node-set($bad-destinations-fragment)/node()"/>
                <copy>
                        <apply-templates select="@*"/>
                <copy>
                        <apply-templates select="@*"/>
-                       <attribute name="书社vocab:destination">
-                               <value-of select="$destination"/>
-                       </attribute>
                        <apply-templates select="node()"/>
                        <for-each select="$dependencies/书社:dependency">
                                <书社vocab:hasDependencyOn rdf:resource="{.}"/>
                        <apply-templates select="node()"/>
                        <for-each select="$dependencies/书社:dependency">
                                <书社vocab:hasDependencyOn rdf:resource="{.}"/>
@@ -116,6 +131,36 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                        <for-each select="$dependencies/书社:recursive-dependency">
                                <书社vocab:hasRecursiveDependencyOn rdf:resource="{.}"/>
                        </for-each>
                        <for-each select="$dependencies/书社:recursive-dependency">
                                <书社vocab:hasRecursiveDependencyOn rdf:resource="{.}"/>
                        </for-each>
+                       <choose>
+                               <when test="not($destinations)">
+                                       <element name="书社vocab:destination">
+                                               <value-of select="@书社vocab:path"/>
+                                       </element>
+                               </when>
+                               <when test="$bad-destinations">
+                                       <message terminate="no">
+                                               <text>Bad destinations: </text>
+                                               <for-each select="$bad-destinations">
+                                                       <if test="position()>1">
+                                                               <text> </text>
+                                                       </if>
+                                                       <text>&lt;</text>
+                                                       <value-of select="."/>
+                                                       <text>></text>
+                                               </for-each>
+                                       </message>
+                                       <element name="书社vocab:destination">
+                                               <value-of select="@书社vocab:path"/>
+                                       </element>
+                               </when>
+                               <otherwise>
+                                       <for-each select="$destinations">
+                                               <element name="书社vocab:destination">
+                                                       <value-of select="."/>
+                                               </element>
+                                       </for-each>
+                               </otherwise>
+                       </choose>
                </copy>
        </template>
        <template match="//书社vocab:IncludeFile[nie:interpretedAs/nfo:PlainTextDocument]" priority="1">
                </copy>
        </template>
        <template match="//书社vocab:IncludeFile[nie:interpretedAs/nfo:PlainTextDocument]" priority="1">
@@ -133,6 +178,7 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                        </for-each>
                </copy>
        </template>
                        </for-each>
                </copy>
        </template>
+       <template match="书社vocab:hasParsedFileWithMetadata" priority="1"/>
        <template match="/">
                <variable name="result-fragment">
                        <apply-templates/>
        <template match="/">
                <variable name="result-fragment">
                        <apply-templates/>
@@ -160,7 +206,12 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                        <for-each select="$result//书社vocab:SourceFile">
                                <value-of select="@rdf:about"/>
                                <text>|</text>
                        <for-each select="$result//书社vocab:SourceFile">
                                <value-of select="@rdf:about"/>
                                <text>|</text>
-                               <value-of select="@书社vocab:destination"/>
+                               <for-each select="书社vocab:destination">
+                                       <if test="position()>1">
+                                               <text>;</text>
+                                       </if>
+                                       <value-of select="."/>
+                               </for-each>
                                <text>&#xA;</text>
                        </for-each>
                </exsl:document>
                                <text>&#xA;</text>
                        </for-each>
                </exsl:document>
index 90e156e28c776c3b51bf74b557c1e35a687e5396..235cfec75b4e03b8fa43708c2187af8507f6e976 100644 (file)
@@ -1,12 +1,12 @@
 <?xml version="1.0"?>
 <!--
 <?xml version="1.0"?>
 <!--
-SPDX-FileCopyrightText: 2023, 2024 Lady <https://www.ladys.computer/about/#lady>
+SPDX-FileCopyrightText: 2023, 2024, 2025 Lady <https://www.ladys.computer/about/#lady>
 SPDX-License-Identifier: MPL-2.0
 -->
 <!--
 ⁌ ⛩📰 书社 ∷ parsers/tsv.xslt
 
 SPDX-License-Identifier: MPL-2.0
 -->
 <!--
 ⁌ ⛩📰 书社 ∷ parsers/tsv.xslt
 
-© 2023–2024 Lady [@ Ladys Computer].
+© 2023–2025 Lady [@ Ladys Computer].
 
 This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
 If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 
 This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
 If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
@@ -83,7 +83,11 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                                                        </element>
                                                                </for-each>
                                                                <for-each select="exsl:node-set($headcols)/*[position()>count(exsl:node-set($cols)/*)]">
                                                                        </element>
                                                                </for-each>
                                                                <for-each select="exsl:node-set($headcols)/*[position()>count(exsl:node-set($cols)/*)]">
-                                                                       <element name="td" namespace="&xhtml;"/>
+                                                                       <element name="td" namespace="&xhtml;">
+                                                                               <attribute name="data-tsv-header">
+                                                                                       <value-of select="."/>
+                                                                               </attribute>
+                                                                       </element>
                                                                </for-each>
                                                        </element>
                                                </otherwise>
                                                                </for-each>
                                                        </element>
                                                </otherwise>
diff --git a/transforms/expansion.xslt b/transforms/expansion.xslt
new file mode 100644 (file)
index 0000000..8c0dd69
--- /dev/null
@@ -0,0 +1,140 @@
+<?xml version="1.0"?>
+<!--
+SPDX-FileCopyrightText: 2023, 2024, 2025 Lady <https://www.ladys.computer/about/#lady>
+SPDX-License-Identifier: MPL-2.0
+-->
+<!--
+⁌ ⛩📰 书社 ∷ transforms/expansion.xslt
+
+© 2023–2025 Lady [@ Ladys Computer].
+
+This Source Code Form is subject to the terms of the Mozilla Public License, v 2.0.
+If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+-->
+<!DOCTYPE transform [
+       <!ENTITY 书社 'urn:fdc:ladys.computer:20231231:Shu1She4'>
+]>
+<transform
+       xmlns="http://www.w3.org/1999/XSL/Transform"
+       xmlns:exsl="http://exslt.org/common"
+       xmlns:exslstr="http://exslt.org/strings"
+       xmlns:html="http://www.w3.org/1999/xhtml"
+       xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#"
+       xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+       xmlns:xlink="http://www.w3.org/1999/xlink"
+       xmlns:书社="&书社;"
+       xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:"
+       exclude-result-prefixes="nfo 书社vocab"
+       extension-element-prefixes="exsl exslstr"
+       version="1.0"
+>
+       <书社:id>urn:fdc:ladys.computer:20231231:Shu1She4:expansion.xslt</书社:id>
+       <template match="书社:link[@xlink:show='embed' and (not(@xlink:actuate) or @xlink:actuate='none')]" mode="书社:expand" priority="1">
+               <variable name="link" select="."/>
+               <variable name="identifier" select="string(@xlink:href)"/>
+               <variable name="is-dir" select="substring($identifier, string-length($identifier))='/'"/>
+               <variable name="included" select="$书社:about//*[@rdf:about=$identifier or $is-dir and starts-with(@rdf:about, $identifier)]"/>
+               <choose>
+                       <when test="$included">
+                               <for-each select="$included">
+                                       <sort select="@rdf:about" data-type="text" lang="zxx" case-order="upper-first"/>
+                                       <variable name="uri" select="书社vocab:hasParsedFile/@nfo:fileUrl"/>
+                                       <variable name="expanded">
+                                               <apply-templates select="document($uri)" mode="书社:expand">
+                                                       <with-param name="identifier" select="string(@rdf:about)"/>
+                                               </apply-templates>
+                                       </variable>
+                                       <for-each select="exsl:node-set($expanded)/node()">
+                                               <copy>
+                                                       <choose>
+                                                               <when test="self::html:*">
+                                                                       <variable name="existing-types" select="exslstr:tokenize(@itemtype)"/>
+                                                                       <attribute name="itemscope">itemscope</attribute>
+                                                                       <attribute name="itemtype">
+                                                                               <for-each select="$existing-types/token[string()!='&书社;:document']">
+                                                                                       <if test="position()!=1">
+                                                                                               <text> </text>
+                                                                                       </if>
+                                                                                       <value-of select="."/>
+                                                                               </for-each>
+                                                                               <if test="not($existing-types/token[string()='&书社;:embed'])">
+                                                                                       <if test="$existing-types/token[string()!='&书社;:document']">
+                                                                                               <text> </text>
+                                                                                       </if>
+                                                                                       <text>&书社;:embed</text>
+                                                                               </if>
+                                                                       </attribute>
+                                                                       <choose>
+                                                                               <when test="$link/@书社:archived-as">
+                                                                                       <copy-of select="$link/@书社:archived-as"/>
+                                                                               </when>
+                                                                               <when test="@书社:archived-as">
+                                                                                       <copy-of select="@书社:archived-as"/>
+                                                                               </when>
+                                                                       </choose>
+                                                                       <copy-of select="@*[not(namespace-uri()='' and (local-name()='itemscope' or local-name()='itemtype')) and not(namespace-uri()='&书社;' and local-name()='archived-as')]|node()"/>
+                                                               </when>
+                                                               <otherwise>
+                                                                       <choose>
+                                                                               <when test="self::* and $link/@书社:archived-as">
+                                                                                       <copy-of select="$link/@书社:archived-as"/>
+                                                                               </when>
+                                                                               <when test="@书社:archived-as">
+                                                                                       <copy-of select="@书社:archived-as"/>
+                                                                               </when>
+                                                                       </choose>
+                                                                       <copy-of select="@*[not(namespace-uri()='&书社;' and local-name()='archived-as')]|node()"/>
+                                                               </otherwise>
+                                                       </choose>
+                                               </copy>
+                                       </for-each>
+                               </for-each>
+                       </when>
+                       <otherwise>
+                               <copy>
+                                       <apply-templates select="@*|node()" mode="书社:expand"/>
+                               </copy>
+                       </otherwise>
+               </choose>
+       </template>
+       <template match="/node()" mode="书社:expand" priority="0">
+               <param name="identifier" select="$IDENTIFIER"/>
+               <copy>
+                       <if test="self::*">
+                               <attribute name="书社:cksum">
+                                       <value-of select="$书社:about//*[@rdf:about=$identifier]/nfo:hasHash[@nfo:hashAlgorithm='CRC32']/@nfo:hashValue"/>
+                               </attribute>
+                               <attribute name="书社:identifier">
+                                       <value-of select="$identifier"/>
+                               </attribute>
+                               <attribute name="书社:mtime">
+                                       <value-of select="$书社:about//*[@rdf:about=$identifier]/nfo:fileLastModified"/>
+                               </attribute>
+                       </if>
+                       <choose>
+                               <when test="self::html:*">
+                                       <variable name="existing-types" select="exslstr:tokenize(@itemtype)"/>
+                                       <attribute name="itemscope">itemscope</attribute>
+                                       <attribute name="itemtype">
+                                               <for-each select="$existing-types/token">
+                                                       <if test="position()!=1">
+                                                               <text> </text>
+                                                       </if>
+                                                       <value-of select="."/>
+                                               </for-each>
+                                               <if test="not($existing-types/token[string()='&书社;:embed' or string()='&书社;:document'])">
+                                                       <if test="$existing-types/token">
+                                                               <text> </text>
+                                                       </if>
+                                                       <text>&书社;:document</text>
+                                               </if>
+                                       </attribute>
+                                       <apply-templates select="@*[not(namespace-uri()='' and (local-name()='itemscope' or local-name()='itemtype') or namespace-uri()='&书社;' and (local-name()='cksum' or local-name()='identifier' or local-name()='mtime'))]|node()" mode="书社:expand"/>
+                               </when>
+                               <otherwise>
+                                       <apply-templates select="@*[not(namespace-uri()='&书社;' and (local-name()='cksum' or local-name()='identifier' or local-name()='mtime'))]|node()" mode="书社:expand"/>
+                               </otherwise>
+                       </choose>
+               </copy>
+       </template>
+</transform>
This page took 0.166986 seconds and 4 git commands to generate.