]> Lady’s Gitweb - Shrine-XSLT/blob - transform.xslt
Move slotted elements to end of <head>
[Shrine-XSLT] / transform.xslt
1 <!--
2 This is an extremely simple XSLT transform which simply reads in a
3 `template.xml` and :—
4
5 • Replaces the `<html:shrine-content>` element with the content of the document it is being applied to,
6
7 • If the root element of the document it is being applied to has a `@data-shrine-header` attribute, replaces the `<html:shrine-header>` with the contents of the corresponding header file (`⸺-header.xml`), and
8
9 • If the root element of the document it is being applied to has a `@data-shrine-footer` attribute, replaces the `<html:shrine-footer>` with the contents of the corresponding footer file (`⸺-footer.xml`), and
10
11 • Copies any remaining `@lang` or `@data-*` attributes from the root element of the document it is being applied to over to the root element of the template.
12
13 The intent is that this file is used in conjunction with a Makefile to quickly automate inserting header and footer content into documents.
14 The exact feature·set might be somewhat more expansive than the description above; for a lengthier overview of what this file does, see `README.markdown`.
15
16 Feel free to add additional templates and features to suit your needs!
17
18 ___
19
20 © 2022 Lady [@ Lady’s Computer]
21
22 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
23 If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
24 -->
25 <xslt:transform
26 xmlns="http://www.w3.org/1999/xhtml"
27 xmlns:exslt="http://exslt.org/common"
28 xmlns:html="http://www.w3.org/1999/xhtml"
29 xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
30 version="1.0"
31 >
32 <xslt:variable name="source" select="current()"/>
33 <xslt:variable name="template" select="document('./template.xml')"/>
34
35 <!--
36 Instead of actually processing the root node, process the template in `template` mode.
37 -->
38 <xslt:template match="/">
39 <xslt:apply-templates select="exslt:node-set($template)" mode="template"/>
40 </xslt:template>
41
42 <!--
43 Process non‐template elements.
44 By default, just copy the element, but remove any `@data-shrine-*` attribuets or `@slot` attributes with a value that begins with `shrine-`.
45 Some elements may have special treatment.
46 -->
47 <xslt:template match="*|text()" mode="content">
48 <xslt:copy>
49 <xslt:for-each select="@*[not(starts-with(name(), 'data-shrine-')) and not(name()='slot' and starts-with(., 'shrine-'))]">
50 <xslt:copy/>
51 </xslt:for-each>
52 <xslt:for-each select="*|text()">
53 <xslt:choose>
54 <xslt:when test="@slot[starts-with(., 'shrine-')]">
55 <xslt:comment>
56 <text> placeholder for slotted element </text>
57 </xslt:comment>
58 </xslt:when>
59 <xslt:otherwise>
60 <xslt:apply-templates select="." mode="content"/>
61 </xslt:otherwise>
62 </xslt:choose>
63 </xslt:for-each>
64 </xslt:copy>
65 </xslt:template>
66
67 <!--
68 Process template elements.
69 By default, just copy the element.
70 This behaviour will be overridden for certain elements to insert the page content.
71 -->
72 <xslt:template match="*|text()" mode="template">
73 <xslt:copy>
74 <xslt:for-each select="@*">
75 <xslt:copy/>
76 </xslt:for-each>
77 <xslt:apply-templates mode="template"/>
78 </xslt:copy>
79 </xslt:template>
80
81 <!--
82 Process the template `<html>` elements.
83 This copies over `@lang` and non‐shrine `@data-*` attributes from the root node.
84 -->
85 <xslt:template match="html:html" mode="template">
86 <xslt:copy>
87 <xslt:for-each select="@*">
88 <xslt:copy/>
89 </xslt:for-each>
90 <xslt:for-each select="exslt:node-set($source)/*/@*[name()='lang' or name()='xml:lang' or starts-with(name(), 'data-') and not(starts-with(name(), 'data-shrine-'))]">
91 <xslt:if test="not(exslt:node-set($template)/*/@*[name()=name(current())])">
92 <xslt:copy/>
93 </xslt:if>
94 </xslt:for-each>
95 <xslt:apply-templates mode="template"/>
96 </xslt:copy>
97 </xslt:template>
98
99 <!--
100 Process the template `<head>` elements.
101 This inserts appropriate metadata based on the document.
102 -->
103 <xslt:template match="html:head" mode="template">
104 <xslt:copy>
105 <xslt:for-each select="@*">
106 <xslt:copy/>
107 </xslt:for-each>
108 <xslt:if test="not(exslt:node-set($source)//html:title[@slot='shrine-head'])">
109 <xslt:text>&#x0A;</xslt:text>
110 <title>
111 <xslt:apply-templates select="exslt:node-set($source)//html:h1" mode="text"/>
112 </title>
113 </xslt:if>
114 <xslt:apply-templates mode="template"/>
115 <xslt:for-each select="exslt:node-set($source)//*[@slot='shrine-head']">
116 <xslt:text>&#x0A;</xslt:text>
117 <xslt:apply-templates select="." mode="content"/>
118 </xslt:for-each>
119 </xslt:copy>
120 </xslt:template>
121
122 <!--
123 Process the template header.
124 Read the `@data-header` attribute of the root element, append `"-header.xml"` to the end of it, and process the resulting document.
125 If no `@data-header` attribute is provided, no header is rendered.
126 -->
127 <xslt:template match="html:shrine-header" mode="template">
128 <xslt:for-each select="exslt:node-set($source)/*/@data-shrine-header">
129 <xslt:apply-templates select="document(concat('./', ., '-header.xml'), $template)/*" mode="content"/>
130 </xslt:for-each>
131 </xslt:template>
132
133 <!--
134 Process the template footer.
135 Read the `@data-footer` attribute of the root element, append `"-footer.xml"` to the end of it, and process the resulting document.
136 If no `@data-footer` attribute is provided, no footer is rendered.
137 -->
138 <xslt:template match="html:shrine-footer" mode="template">
139 <xslt:for-each select="exslt:node-set($source)/*/@data-shrine-footer">
140 <xslt:apply-templates select="document(concat('./', ., '-footer.xml'), $template)/*" mode="content"/>
141 </xslt:for-each>
142 </xslt:template>
143
144 <!--
145 Process the content.
146 -->
147 <xslt:template match="html:shrine-content" mode="template">
148 <xslt:apply-templates select="exslt:node-set($source)/*" mode="content"/>
149 </xslt:template>
150
151 <!--
152 Provide the complete text content of the provided element.
153 -->
154 <xslt:template match="*|text()" mode="text">
155 <xslt:choose>
156 <xslt:when test="self::*">
157 <xslt:apply-templates mode="text"/>
158 </xslt:when>
159 <xslt:when test="self::text()">
160 <xslt:copy/>
161 </xslt:when>
162 </xslt:choose>
163 </xslt:template>
164 </xslt:transform>
This page took 0.060988 seconds and 5 git commands to generate.