|
1 | 1 | <?xml version="1.0" encoding="utf-8" ?> |
2 | 2 | <!-- |
3 | 3 | ## XSLTLint.xslt |
4 | | - |
| 4 | +
|
5 | 5 | Tests an XSLT file for some common (and frankly, embarrassing) errors. |
6 | 6 | --> |
7 | 7 | <!DOCTYPE xsl:stylesheet [ |
|
37 | 37 | </xsl:variable> |
38 | 38 | <xsl:variable name="ns-prefixes" select="make:node-set($ns-prefixes-RTF)/ns" /> |
39 | 39 | <xsl:variable name="no-go-chars" select="concat($apos, $quot, '/(;)=&<>$#€%!?+^`´@*\')" /> |
40 | | - |
| 40 | + |
41 | 41 | <xsl:variable name="selectAttrs" select="//xsl:*/@select" /> |
42 | 42 | <xsl:variable name="testAttrs" select="//xsl:*/@test" /> |
43 | 43 | <xsl:variable name="exprAttrs" select="$selectAttrs | $testAttrs" /> |
44 | | - |
| 44 | + |
45 | 45 | <!-- Grab any includes/imports --> |
46 | 46 | <xsl:variable name="includes" select="/xsl:stylesheet/*[self::xsl:include or self::xsl:import]" /> |
47 | | - |
| 47 | + |
48 | 48 | <xsl:template match="/"> |
49 | 49 | <!-- |
50 | 50 | Start by testing some special cases |
51 | 51 | --> |
52 | | - |
| 52 | + |
53 | 53 | <!-- Undeclared namespaces --> |
54 | 54 | <xsl:apply-templates select="$selectAttrs[substring-before(., ':')][not(substring-before(., '::'))]" mode="undeclared-ns-prefix" /> |
55 | 55 |
|
56 | 56 | <!-- Grab a reference inside this doc --> |
57 | 57 | <xsl:variable name="excluded-prefixes" select="xsl:stylesheet/@exclude-result-prefixes" /> |
58 | | - |
| 58 | + |
59 | 59 | <!-- Missing prefixes in `exclude-result-prefixes` attribute --> |
60 | 60 | <xsl:for-each select="$ns-prefixes"> |
61 | 61 | <xsl:variable name="prefix" select="@prefix" /> |
|
65 | 65 | </xsl:call-template> |
66 | 66 | </xsl:if> |
67 | 67 | </xsl:for-each> |
68 | | - |
| 68 | + |
69 | 69 | <!-- Undeclared variables/params --> |
70 | 70 | <xsl:apply-templates select="$exprAttrs[starts-with(., '$')]" mode="undeclared-variable" /> |
71 | | - |
| 71 | + |
72 | 72 | <!-- Undeclared keys --> |
73 | 73 | <xsl:apply-templates select="$exprAttrs[contains(., &KEY_BEGIN;)]" mode="undeclared-key" /> |
74 | | - |
| 74 | + |
75 | 75 | <!-- Illegal AVTs --> |
76 | 76 | <xsl:apply-templates select="$selectAttrs[contains(., '{') and contains(., '}')]" mode="illegal-avt" /> |
77 | | - |
| 77 | + |
78 | 78 | <!-- Now process the various elements in the stylesheet --> |
79 | 79 | <xsl:apply-templates select="*" /> |
80 | | - |
| 80 | + |
81 | 81 | </xsl:template> |
82 | | - |
| 82 | + |
83 | 83 | <xsl:template match="*"> |
84 | 84 | <xsl:apply-templates select="*" /> |
85 | 85 | </xsl:template> |
86 | | - |
| 86 | + |
87 | 87 | <!-- |
88 | 88 | Checks for variable declarations including the dollar-sign (it happens) |
89 | 89 | --> |
|
118 | 118 | </xsl:otherwise> |
119 | 119 | </xsl:choose> |
120 | 120 | </xsl:if> |
121 | | - |
| 121 | + |
122 | 122 | <xsl:if test="key('matchTemplatesIndex', $template)"> |
123 | 123 | <xsl:call-template name="error"> |
124 | 124 | <xsl:with-param name="message" select="'There is however, a *match template* defined with this name, so looks like a #snippetfail'" /> |
125 | 125 | <xsl:with-param name="linefeed" select="false()" /> |
126 | 126 | </xsl:call-template> |
127 | 127 | </xsl:if> |
128 | | - |
| 128 | + |
129 | 129 | <!-- Check for misplaced `<xsl:param>` (where it should have been `<xsl:with-param>`) --> |
130 | 130 | <xsl:if test="xsl:param"> |
131 | 131 | <xsl:call-template name="error"> |
132 | 132 | <xsl:with-param name="message" select="concat('A call to "', $template, '" contains misplaced `<xsl:param>` (you probably mean `<xsl:with-param>`).')" /> |
133 | 133 | </xsl:call-template> |
134 | 134 | </xsl:if> |
135 | 135 | </xsl:template> |
136 | | - |
| 136 | + |
137 | 137 | <!-- |
138 | 138 | Test if we accidentally forgot to add a mode to a template |
139 | 139 | --> |
140 | 140 | <xsl:template match="xsl:apply-templates"> |
141 | 141 | <xsl:variable name="mode" select="@mode" /> |
142 | | - |
| 142 | + |
143 | 143 | <xsl:if test="normalize-space($mode) and not(key('modedTemplatesIndex', $mode))"> |
144 | 144 | <xsl:variable name="message" select="concat('An <xsl:apply-templates /> instruction use the mode ', $apos, $mode, $apos, ' but no templates are defined in that mode. Did you forget to add it?')" /> |
145 | 145 | <xsl:choose> |
|
158 | 158 | </xsl:choose> |
159 | 159 | </xsl:if> |
160 | 160 | </xsl:template> |
161 | | - |
| 161 | + |
162 | 162 | <!-- |
163 | 163 | Check for namespace-prefixes that haven't been declared |
164 | 164 | --> |
165 | 165 | <xsl:template match="@select" mode="undeclared-ns-prefix"> |
166 | 166 | <xsl:variable name="prefix" select="substring-before(., ':')" /> |
167 | | - |
| 167 | + |
168 | 168 | <!-- |
169 | 169 | Ideally, this should obviously be "properly" parsed, but we can eliminate a lot of false positives |
170 | 170 | just by doing a little filtering - throw away all characters that shouldn't be used in a prefix |
171 | | - and check if the string is still (probably) the same... |
| 171 | + and check if the string is still (probably) the same... |
172 | 172 | --> |
173 | 173 | <xsl:if test="string-length($prefix) = string-length(translate($prefix, $no-go-chars, ''))"> |
174 | 174 | <!-- Go through the declared prefixes to find a match --> |
|
178 | 178 | </xsl:call-template> |
179 | 179 | </xsl:if> |
180 | 180 | </xsl:if> |
181 | | - |
| 181 | + |
182 | 182 | </xsl:template> |
183 | | - |
| 183 | + |
184 | 184 | <!-- |
185 | 185 | Check for undeclared variables |
186 | 186 | --> |
|
194 | 194 | </xsl:if> |
195 | 195 | </xsl:if> |
196 | 196 | </xsl:template> |
197 | | - |
| 197 | + |
198 | 198 | <!-- |
199 | 199 | Check for missing `xsl:key` declaration |
200 | 200 | --> |
201 | 201 | <xsl:template match="@select | @test" mode="undeclared-key"> |
202 | 202 | <xsl:variable name="keyName" select="substring-before(substring(substring-after(., &KEY_BEGIN;), 2), $apos)" /> |
203 | 203 | <xsl:variable name="message" select="concat('A `key()` function used an undeclared key name (', $keyName, ').')" /> |
204 | | - <xsl:if test="not(key('keyNamesIndex', $keyName))"> |
| 204 | + <xsl:if test="normalize-space($keyName) and not(key('keyNamesIndex', $keyName))"> |
205 | 205 | <xsl:choose> |
206 | 206 | <xsl:when test="$includes"> |
207 | 207 | <xsl:if test="not(document($includes/@href, /)//xsl:key[@name = $keyName])"> |
|
224 | 224 | <xsl:with-param name="message" select="concat('An AVT (Attribute Value Template) was used in a `@select` attribute (', $quot, ., $quot, ').')" /> |
225 | 225 | </xsl:call-template> |
226 | 226 | </xsl:template> |
227 | | - |
| 227 | + |
228 | 228 | <!-- |
229 | 229 | Output template for generating the error messages |
230 | 230 | --> |
|
234 | 234 | <xsl:if test="$linefeed"><xsl:value-of select="$LF" /></xsl:if> |
235 | 235 | <xsl:value-of select="$message" /> |
236 | 236 | </xsl:template> |
237 | | - |
| 237 | + |
238 | 238 | </xsl:stylesheet> |
0 commit comments