]> Lady’s Gitweb - Shushe/commitdiff
Support pagination 0.8.0
authorLady <redacted>
Tue, 30 Apr 2024 07:53:58 +0000 (03:53 -0400)
committerLady <redacted>
Thu, 2 May 2024 02:31:47 +0000 (22:31 -0400)
It’s not clear to me that this is actually a good idea, and this
functionality may be reverted later. It adds a lot of complexity
despite still having significant drawbacks, and the alternative pattern
of just generating archives and later expanding them is a much safer
and more versatile solution.

However, the pattern of e·g needing a paginated feed of all the posts
in one’s blog suggests that something along these lines (backed by this
method or archiving~expanding) *should* be supported by default in
⛩️📰 书社. One alternative might be to add (e·g) a `@书社:expand`
attribute to <书社:archive> elements, tho how exactly this would be
tracked on the resulting archives is unclear, and it would be
restricted to producing folders (with exclusively archive contents)
that could not easily be mixed with other files.

GNUmakefile
README.markdown
lib/archive2extractor.xslt
lib/catalog2destinations.xslt
lib/catalog2transform.xslt
lib/paged2extractor.xslt [new file with mode: 0644]

index 90b769f39fcdaf71057caf6d2dcf2146d82830b4..2cb311f3ce7e09bc7ecd177f546311f97351ccb1 100644 (file)
@@ -28,6 +28,7 @@ override define makefileinfo
 ║│ • grep                                                     │║
 ║│ • git (optional)                                           │║
 ║│ • ln                                                       │║
+║│ • ls                                                       │║
 ║│ • mkdir (requires support for `-p´)                        │║
 ║│ • mv                                                       │║
 ║│ • od (requires support for `-t x1´)                        │║
@@ -109,6 +110,7 @@ FIND := find
 GIT := git
 GREP := grep
 LN := ln
+LS := ls
 MKDIR := mkdir
 MV := mv
 OD := od
@@ -173,7 +175,7 @@ THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 # By default, `find´ will ignore files which begin with a period and those which are likely to cause problems for `make´.
 EXTRAFINDRULES :=
 EXTRAFINDINCLUDERULES :=
-FINDRULES := ! '(' '(' -name '[.-]*' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a $(EXTRAFINDRULES),)
+FINDRULES := ! '(' '(' -name '[.-]*' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*"{*' -o -name '*}"*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a $(EXTRAFINDRULES),)
 FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a $(EXTRAFINDINCLUDERULES),)
 
 # The list of magic files to use when determining media types.
@@ -219,6 +221,9 @@ endif
 #
 # • ‹ urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive ›:
 #   Generates archive files from parse results.
+#
+# • ‹ urn:fdc:ladys.computer:20231231:Shu1She4:mode:paged ›:
+#   Generates paginated files from parse results.
 MODE := urn:fdc:ladys.computer:20231231:Shu1She4:mode:default
 
 # Set to a non·empty value to print all commands as they run.
@@ -270,8 +275,14 @@ override xpath = $(XMLLINT) --xpath $(call quote,$1) $(call quote,$2) > /dev/nul
 # (callable) Extract the value of the text nodes in the provided X·M·L document and print them to `stdout´.
 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 - $(call quote,$1)
 
+# (callable) List the files in the provided directory which are associated with the provided filename, one per line.
+override associatedfiles = $(LS) -1 $(call quote,$1) | $(SED) '/.*"{.*}".*/!d;s/^\(.*\)"{.*}"\(.*\)$$/\1\2|&/' | $(GREP) -F -e $(call quote,$2|) | $(SED) 's/^.*|//'
+
+# (callable) Remove files associated with the provided file.
+override removeassociatedfiles = ASSOCIATED="$$($(call associatedfiles,$(dir $1),$(notdir $1)) | $(TR) '\n' ' ')"; if $(TEST) -n "$$ASSOCIATED"; then cd $(call quote,$(dir $1)) && $(PRINTF) '%s\n' "$$ASSOCIATED" | $(TR) ' ' '\n' | $(SED) $(call quote,/^$$/d;s/'/'"'"'/g;s/^/'/;s/$$/'/) | $(TR) '\n' ' ' | $(XARGS) $(RM); fi
+
 # (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 $(RM) -f $(call quote,$2); $(call extracttext,$1) > $(call quote,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(RM) -f $(call quote,$2); $(call extracttext,$1) | $(TR) -d '\t\n\f\r ' | $(XARGS) -0 $(PRINTF) 'begin-base64 644 -\n%s\n====\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 $(RM) -f $(call quote,$2); $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) $(call quote,$2) 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'; else $(RM) -f $(call quote,$2); $(XMLLINT) --nsclean $(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); $(call removeassociatedfiles,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(call extracttext,$1) | $(TR) -d '\t\n\f\r ' | $(XARGS) -0 $(PRINTF) 'begin-base64 644 -\n%s\n====\n' | $(UUDECODE) -o /dev/stdout > $(call quote,$2); $(call removeassociatedfiles,$2); elif $(call xpath,/*[local-name()="archive" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) $(call quote,$2) 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 removeassociatedfiles,$2); elif $(call xpath,//*[local-name()="page" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) $(call quote,$2) NAME=$(call quote,$3) SRC=$(call quote,$1) BUILDDIR=$(call quote,$(BUILDDIR)/paged/$3) DESTDIR=$(call quote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:paged'; else $(XMLLINT) --nsclean $(call quote,$1) > $(call quote,$2); $(call removeassociatedfiles,$2);  fi
 
 # ━ § BEGIN DEFAULT MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
@@ -634,6 +645,7 @@ $(call installed,$(recursivefiles) $(installablefiles)) : $(DESTDIR)/% : $(BUILD
        @$(PRINTF) '%s\n' $(call quote,Installing </$*>…)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)$(CP) $(call quote,$<) $(call quote,$@)
+       $(silent)for associated in $$($(call associatedfiles,$(dir $<),$(notdir $<))); do $(PRINTF) '%s\n' "$$associated" | $(SED) 's/^\(.*\)"{\(.*\)}"\(.*\)$$/\1\2\3/' | $(XARGS) -0 $(PRINTF) '%s%s\n' $(call quote,$(dir $@)) | $(XARGS) -0 $(CP) $(call quote,$(dir $<))"$$associated"; done
 
 # ━ § BEGIN ARCHIVE MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
@@ -689,6 +701,61 @@ $(DESTDIR)/% : $(foreach file,$(archivefiles),$(BUILDDIR)/files/$(file))
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)cd $(call quote,$(BUILDDIR)/files); $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -w > $(call quote,$(abspath $@))
 
+# ━ § BEGIN PAGED MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+else ifeq ($(MODE),urn:fdc:ladys.computer:20231231:Shu1She4:mode:paged)
+
+# ─ ¶ Non‐Recipe Variable Definitions ─────────────────────────────────
+
+# Get the list of pages.
+ifneq ($(wildcard $(BUILDDIR)/index),)
+override pagefiles := $(patsubst ./pages/%,%,$(shell $(CAT) $(call quote,$(BUILDDIR)/index)))
+endif
+
+# ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
+
+# ─ ¶ Phony Targets ───────────────────────────────────────────────────
+
+# ─ ¶ Special Targets ─────────────────────────────────────────────────
+
+# Reload this make·file if the pages have changed.
+$(THISDIR)/GNUmakefile : $(BUILDDIR)/index
+       $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
+       @$(PRINTF) '%b\n' $(call quote,\0033[1mPages for </$(NAME)> updated. Restarting…\0033[22m)
+
+# ─ ¶ Build Targets ───────────────────────────────────────────────────
+
+# Build the extractor transform for extracting the pages of the paged source file.
+$(BUILDDIR)/extractor.xslt : $(SRC) $(THISDIR)/lib/paged2extractor.xslt
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam NAME $(call quote,$(call notdir,$<)) $(call quote,$(THISDIR)/lib/paged2extractor.xslt) $(call quote,$<)
+
+# Use the extractor transform to extract the paged source file out into its pages.
+#
+# This target sleeps for 1 second to ensure the resulting index will always be newer than this make·file.
+$(BUILDDIR)/index : $(BUILDDIR)/extractor.xslt $(SRC)
+       @$(PRINTF) '%s\n' $(call quote,Extracting pages for </$(NAME)>…)
+       $(silent)$(SLEEP) 1
+       $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --writesubtree $(call quote,$(dir $@)) $(call quote,$<) $(call quote,$(SRC))
+
+# All other pages are extracted alongside the base.
+$(foreach file,$(pagefiles),$(BUILDDIR)/pages/$(file)) : $(BUILDDIR)/index ;
+
+# Process each page into its final form.
+$(foreach file,$(pagefiles),$(BUILDDIR)/public/$(file)) : $(BUILDDIR)/public/% : $(BUILDDIR)/pages/%
+       @$(PRINTF) '%s\n' $(call quote,Building page `$(subst }",,$(subst "{,,$*))´ of </$(NAME)>…)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(call processresultto,$<,$@,$*)
+
+# Archive all components in the file to the destination.
+#
+# This is a match‐anything target, with the assumption that this make·file is being called recursively from the default mode.
+$(DESTDIR)/% : $(foreach file,$(pagefiles),$(BUILDDIR)/public/$(file))
+       @$(PRINTF) '%s\n' $(call quote,Collecting pages for </$(NAME)>…)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(call removeassociatedfiles,$@)
+       $(silent)cp $(foreach file,$(pagefiles),$(call quote,$(BUILDDIR)/public/$(file))) $(DESTDIR)
+
 # ━ § END DEFINED MAKE·FILE MODES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
 else
index f6874eaf462c9e275226568fea09f06fd7f1de42..9523a8a1ae61b8a7090efd7472a17527345cfc1f 100644 (file)
@@ -135,6 +135,7 @@ In every case, you may supply your own implementation by overriding the
 - `git` (optional; set `GIT=` to disable)
 - `grep`
 - `ln`
+- `ls`
 - `mkdir`
 - `mv`
 - `od`
@@ -281,12 +282,14 @@ Source files whose media type does not have an associated X·S·L·T
   contain Ascii white·space, colons (`:`), semis (`;`), pipes (`|`),
   bucks (`$`), percents (`%`), hashes (`#`), asterisks (`*`), brackets
   (`[` or `]`), erotemes (`?`), backslashes (`\`), or control
-  characters, must not begin with a hyphen‐minus (`-`), and must not
-  end with a cloparen (`)`).**
+  characters, must not begin with a hyphen‐minus (`-`), must not end
+  with a cloparen (`)`), and must not contain quoted braces (`"{` or
+  `}"`).**
 The former characters have the potential to conflict with make syntax,
-  a leading hyphen‐minus is confusable for a command‐line argument, and
-  a trailing cloparen [activates a bug in G·N·U Make
-  3.81](https://stackoverflow.com/questions/17148468/capturing-filenames-including-parentheses-with-gnu-makes-wildcard-function#comment24825307_17148894).
+  a leading hyphen‐minus is confusable for a command‐line argument, a
+  trailing cloparen [activates a bug in G·N·U Make
+  3.81](https://stackoverflow.com/questions/17148468/capturing-filenames-including-parentheses-with-gnu-makes-wildcard-function#comment24825307_17148894),
+  and quoted braces are used internally by the program.
 
 ## Parsers
 
@@ -622,6 +625,29 @@ They are :⁠—
   A plaintext (U·T·F‐8) file will be produced from the text nodes in
     the transformation result.
 
+## Pagination
+
+It is possible to have a single source file produce multiple output
+  files via `<书社:page>` elements, whose `@name` gives the name of the
+  page.
+If a parsed document has a `@书社:destination` which contains `%s`,
+  the `%s` will be replaced with the `@name` for each `<书社:page>` (and
+  removed for the main output).
+Otherwise, the `@name` is inserted before the first period of the
+  filename (or at the end of the filename for those with no period).
+If `<书社:page>`s do not have a `@name`, they are numbered
+  sequentially.
+The destination of pages must be in the same directory as their parent.
+
+Pagination essentially forms a limited convenience for the more
+  sophisticated technique of creating an archive with ⛩️📰 书社 and
+  then unarchiving it.
+Pages are, from Make’s point of view, untracked side·effects of
+  installing the main output, meaning they cannot be targeted directly
+  and will not appear in `make list` or `make listout`.
+They are intended solely for the like of indices and feeds, for which
+  convenience and necessity outweigh their flaws.
+
 ## License
 
 This repository conforms to [REUSE][].
index d43be68573892f016ca11998c03b6caacd3caf2b..8ff59e7a81a491830f70afcbe64640dd17d11e76 100644 (file)
@@ -13,17 +13,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"
        xmlns:xslt="http://www.w3.org/1999/XSL/TransformAlias"
        xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
        version="1.0"
 >
        <namespace-alias stylesheet-prefix="xslt" result-prefix="#default"/>
        <template match="/">
-               <xslt:transform
-                       xmlns:exsl="http://exslt.org/common"
-                       extension-element-prefixes="exsl"
-                       version="1.0"
-               >
+               <xslt:transform extension-element-prefixes="exsl" version="1.0">
                        <xslt:template match="/">
                                <for-each select="书社:archive/*[@书社:archived-as and not(starts-with(@书社:archived-as, '../') or starts-with(@书社:archived-as, '/') or contains(@书社:archived-as, '/../'))]">
                                        <variable name="href">
index 6cad19814429a1f15a32a1e23ca9160aa98b1fcb..ae1ea29cfd455621e40b57b9d54b68dac42d6898 100644 (file)
@@ -14,7 +14,9 @@ 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:catalog="urn:oasis:names:tc:entity:xmlns:xml:catalog"
+       xmlns:exslstr="http://exslt.org/strings"
        xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
+       extension-element-prefixes="exslstr"
        version="1.0"
 >
        <template match="/">
@@ -26,7 +28,23 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                        <text>|</text>
                                        <choose>
                                                <when test="$destination">
-                                                       <value-of select="$destination"/>
+                                                       <variable name="dir">
+                                                               <for-each select="exslstr:tokenize($destination, '/')[not(position()=last())]">
+                                                                       <value-of select="."/>
+                                                                       <text>/</text>
+                                                               </for-each>
+                                                       </variable>
+                                                       <variable name="name" select="string(exslstr:tokenize($destination, '/')[last()])"/>
+                                                       <value-of select="$dir"/>
+                                                       <choose>
+                                                               <when test="contains($name, '%s')">
+                                                                       <value-of select="substring-before($name, '%s')"/>
+                                                                       <value-of select="substring-after($name, '%s')"/>
+                                                               </when>
+                                                               <otherwise>
+                                                                       <value-of select="$name"/>
+                                                               </otherwise>
+                                                       </choose>
                                                </when>
                                                <otherwise>
                                                        <value-of select="substring-after(@name, 'about:shushe?source=')"/>
index 04c38f97885247858d7bc0f887aa77193a09b9c0..3fb4c33172c5152f873f9f2e2745bd6d39d6b271 100644 (file)
@@ -45,6 +45,43 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                        <xslt:variable name="书社:result">
                                <xslt:apply-templates select="exsl:node-set($书社:expansion)/node()"/>
                        </xslt:variable>
+                       <xslt:variable name="书社:destination">
+                               <xslt:choose>
+                                       <xslt:when test="string($书社:source/@书社:destination)!=''">
+                                               <xslt:value-of select="$书社:source/@书社:destination"/>
+                                       </xslt:when>
+                                       <xslt:when test="starts-with($PATH, '/')">
+                                               <xslt:value-of select="substring-after($PATH, '/')"/>
+                                       </xslt:when>
+                                       <xslt:otherwise>
+                                               <xslt:value-of select="$PATH"/>
+                                       </xslt:otherwise>
+                               </xslt:choose>
+                       </xslt:variable>
+                       <xslt:variable name="书社:pagedestination">
+                               <xslt:variable name="dir">
+                                       <xslt:for-each select="exslstr:tokenize($书社:destination, '/')[not(position()=last())]">
+                                               <xslt:value-of select="."/>
+                                               <xslt:text>/</xslt:text>
+                                       </xslt:for-each>
+                               </xslt:variable>
+                               <xslt:variable name="name" select="string(exslstr:tokenize($书社:destination, '/')[last()])"/>
+                               <xslt:value-of select="$dir"/>
+                               <xslt:choose>
+                                       <xslt:when test="contains($name, '%s')">
+                                               <xslt:value-of select="$name"/>
+                                       </xslt:when>
+                                       <xslt:when test="contains($name, '.')">
+                                               <xslt:value-of select="substring-before($name, '.')"/>
+                                               <xslt:text>%s.</xslt:text>
+                                               <xslt:value-of select="substring-after($name, '.')"/>
+                                       </xslt:when>
+                                       <xslt:otherwise>
+                                               <xslt:value-of select="$name"/>
+                                               <xslt:text>%s</xslt:text>
+                                       </xslt:otherwise>
+                               </xslt:choose>
+                       </xslt:variable>
                        <for-each select="//catalog:uri">
                                <xslt:include href="{@uri}">
                                        <if test="contains(@name, ':')">
@@ -271,10 +308,34 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                        <xslt:apply-templates select="@*|node()" mode="书社:application"/>
                                </xslt:copy>
                        </xslt:template>
-                       <xslt:template match="@书社:destination|@书社:disable-output-wrapping|@书社:archived-as[../ancestor::*[not(self::书社:apply-attributes-to-root or self::书社:apply-attributes)]]" mode="书社:application" priority="1"/>
-                       <xslt:template match="书社:archive" mode="书社:application" priority="1">
+                       <xslt:template match="@书社:destination[not(../self::书社:page)]|@书社:disable-output-wrapping|@书社:archived-as[../ancestor::*[not(self::书社:apply-attributes-to-root or self::书社:apply-attributes)]]" mode="书社:application" priority="1"/>
+                       <xslt:template match="书社:archive|书社:page" mode="书社:application" priority="1">
                                <xslt:copy>
-                                       <xslt:for-each select="@*|node()">
+                                       <xslt:for-each select="@*">
+                                               <xslt:choose>
+                                                       <xslt:when test="../self::书社:archive and local-name()='archived-as' and namespace-uri()='&书社;' and ../ancestor::*[not(self::书社:apply-attributes-to-root or self::书社:apply-attributes)]"/>
+                                                       <xslt:otherwise>
+                                                               <xslt:apply-templates select="." mode="书社:application"/>
+                                                       </xslt:otherwise>
+                                               </xslt:choose>
+                                       </xslt:for-each>
+                                       <xslt:if test="self::书社:page and not(@书社:destination)">
+                                               <xslt:attribute name="书社:destination">
+                                                       <xslt:value-of select="substring-before($书社:pagedestination, '%s')"/>
+                                                       <xslt:text>%22%7B</xslt:text>
+                                                       <xslt:choose>
+                                                               <xslt:when test="@name">
+                                                                       <xslt:value-of select="@name"/>
+                                                               </xslt:when>
+                                                               <xslt:otherwise>
+                                                                       <xslt:value-of select="count(ancestor::书社:page|preceding::书社:page)+1"/>
+                                                               </xslt:otherwise>
+                                                       </xslt:choose>
+                                                       <xslt:text>%7D%22</xslt:text>
+                                                       <xslt:value-of select="substring-after($书社:pagedestination, '%s')"/>
+                                               </xslt:attribute>
+                                       </xslt:if>
+                                       <xslt:for-each select="node()">
                                                <xslt:choose>
                                                        <xslt:when test="self::*">
                                                                <xslt:variable name="component">
@@ -291,7 +352,6 @@ If a copy of the M·P·L was not distributed with this file, You can obtain one
                                                                </xslt:variable>
                                                                <xslt:apply-templates select="exsl:node-set($component)/node()" mode="书社:application"/>
                                                        </xslt:when>
-                                                       <xslt:when test="../ancestor::*[not(self::书社:apply-attributes-to-root or self::书社:apply-attributes)] and local-name()='archived-as' and namespace-uri()='&书社;'"/>
                                                        <xslt:otherwise>
                                                                <xslt:apply-templates select="." mode="书社:application"/>
                                                        </xslt:otherwise>
diff --git a/lib/paged2extractor.xslt b/lib/paged2extractor.xslt
new file mode 100644 (file)
index 0000000..5d1a155
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0"?>
+<!--
+SPDX-FileCopyrightText: 2024 Lady <https://www.ladys.computer/about/#lady>
+SPDX-License-Identifier: MPL-2.0
+-->
+<!--
+⁌ ⛩️📰 书社 ∷ lib/paged2extractor.xslt
+
+© 2024 Lady [@ Lady’s 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/>.
+-->
+<transform
+       xmlns="http://www.w3.org/1999/XSL/Transform"
+       xmlns:exsl="http://exslt.org/common"
+       xmlns:exslstr="http://exslt.org/strings"
+       xmlns:xslt="http://www.w3.org/1999/XSL/TransformAlias"
+       xmlns:书社="urn:fdc:ladys.computer:20231231:Shu1She4"
+       version="1.0"
+>
+       <namespace-alias stylesheet-prefix="xslt" result-prefix="#default"/>
+       <param name="NAME"/>
+       <template match="/">
+               <xslt:transform extension-element-prefixes="exsl exslstr" version="1.0">
+                       <xslt:template match="@*|node()">
+                               <xslt:param name="destination" select="''"/>
+                               <xslt:choose>
+                                       <xslt:when test="self::书社:page">
+                                               <xslt:apply-templates>
+                                                       <xslt:with-param name="destination" select="$destination"/>
+                                               </xslt:apply-templates>
+                                       </xslt:when>
+                                       <xslt:when test="$destination='' and not(ancestor::书社:page) or string(ancestor::书社:page[1]/@书社:destination)=$destination">
+                                               <xslt:copy>
+                                                       <xslt:apply-templates>
+                                                               <xslt:with-param name="destination" select="$destination"/>
+                                                       </xslt:apply-templates>
+                                               </xslt:copy>
+                                       </xslt:when>
+                                       <xslt:otherwise>
+                                               <xslt:apply-templates>
+                                                       <xslt:with-param name="destination" select="$destination"/>
+                                               </xslt:apply-templates>
+                                       </xslt:otherwise>
+                               </xslt:choose>
+                       </xslt:template>
+                       <xslt:template match="/" priority="1">
+                               <exsl:document href="./pages/{$NAME}" method="xml" encoding="UTF-8">
+                                       <xslt:apply-templates/>
+                               </exsl:document>
+                               <xslt:text>
+                                       <text>./pages/</text>
+                                       <value-of select="$NAME"/>
+                                       <text>&#xA;</text>
+                               </xslt:text>
+                               <for-each select="//书社:page[@书社:destination]">
+                                       <if test="not(ancestor::书社:page[@书社:destination=current()/@书社:destination] or preceding::书社:page[@书社:destination=current()/@书社:destination])">
+                                               <variable name="href">
+                                                       <text>./pages/</text>
+                                                       <value-of select="exslstr:tokenize(@书社:destination, '/')[last()]"/>
+                                               </variable>
+                                               <exsl:document href="{$href}" method="xml" encoding="UTF-8">
+                                                       <xslt:apply-templates>
+                                                               <xslt:with-param name="destination">
+                                                                       <value-of select="@书社:destination"/>
+                                                               </xslt:with-param>
+                                                       </xslt:apply-templates>
+                                               </exsl:document>
+                                               <xslt:text>
+                                                       <choose>
+                                                               <when test="contains($href, '%22%7B')">
+                                                                       <value-of select="substring-before($href, '%22%7B')"/>
+                                                                       <text>&quot;{</text>
+                                                                       <value-of select="substring-before(substring-after($href, '%22%7B'), '%7D%22')"/>
+                                                                       <text>}&quot;</text>
+                                                                       <value-of select="substring-after(substring-after($href, '%22%7B'), '%7D%22')"/>
+                                                               </when>
+                                                               <otherwise>
+                                                                       <value-of select="$href"/>
+                                                               </otherwise>
+                                                       </choose>
+                                                       <text>&#xA;</text>
+                                               </xslt:text>
+                                       </if>
+                               </for-each>
+                       </xslt:template>
+                       <xslt:output method="text" encoding="UTF-8"/>
+               </xslt:transform>
+       </template>
+       <output method="xml" encoding="UTF-8"/>
+</transform>
This page took 0.05269 seconds and 4 git commands to generate.