diff --git a/public/_headers b/public/_headers index 8cad0829..31988d95 100644 --- a/public/_headers +++ b/public/_headers @@ -149,11 +149,6 @@ Content-Type: application/xml; charset=utf-8 Cache-Control: public, max-age=3600, stale-if-error=86400 -# Sitemap XSL stylesheet — styles the XML when viewed in a browser -/sitemap.xsl - Content-Type: application/xslt+xml; charset=utf-8 - Cache-Control: public, max-age=3600 - # RFC 9727 — Publishing Organisation API Information /.well-known/api-catalog Content-Type: application/linkset+json; charset=utf-8 diff --git a/public/_routes.json b/public/_routes.json index 9c6ff3e6..011ca2dc 100644 --- a/public/_routes.json +++ b/public/_routes.json @@ -19,7 +19,6 @@ "/search-overlay.js", "/spec-toc.js", "/admin-stats.js", - "/sitemap.xsl", "/okf/*", "/okf.tar.gz" ] diff --git a/public/sitemap.xsl b/public/sitemap.xsl deleted file mode 100644 index bea959c3..00000000 --- a/public/sitemap.xsl +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - - - - - - - - XML sitemap – The Website Specification - - - -
-
- The Website Specification - / - XML sitemap -
-
-
- -
-
-
- Styled view of an XML sitemap. - Crawlers read the underlying XML directly — view source to see it. -
-
- - -
- - -

Sitemap index

-

- This index lists every child sitemap on specification.website. - One sitemap per spec category, plus sitemap-pages.xml for the - homepage and marketing pages. Defined by - sitemaps.org. -

-
- child sitemaps -
- - - - - - - - - - - - - - - - - -
#Sitemap URLLast modified
- - - - - -
-
- - -

URL sitemap

-

- A list of canonical URLs in one section of specification.website, - with the last date each URL changed. Defined by - sitemaps.org. -

- -
- URLs -
- - - - - - - - - - - - - - - - - -
#URLLast modified
- - - - - -
-
- - - - - - - - - UTC - - - - -
diff --git a/src/content/changelog/2026-09-10-xslt-sitemap-stylesheets.md b/src/content/changelog/2026-09-10-xslt-sitemap-stylesheets.md new file mode 100644 index 00000000..6712abe9 --- /dev/null +++ b/src/content/changelog/2026-09-10-xslt-sitemap-stylesheets.md @@ -0,0 +1,8 @@ +--- +title: "XSL sitemap stylesheets are out" +date: "2026-09-10" +type: changed +relatedSlugs: [xml-sitemaps] +--- + +[XML sitemaps](/spec/seo/xml-sitemaps/) used to recommend an `` processing instruction so a browser would render the sitemap as a readable table. The HTML Standard now tells authors to avoid client-side XSLT altogether — Chrome schedules its removal for version 158 with temporary exceptions, and Firefox and WebKit also support removal — so the page recommends an ordinary HTML index instead, and this site has dropped the processing instruction from its own sitemaps. diff --git a/src/content/spec/seo/xml-sitemaps.md b/src/content/spec/seo/xml-sitemaps.md index 9db230ae..49a778e8 100644 --- a/src/content/spec/seo/xml-sitemaps.md +++ b/src/content/spec/seo/xml-sitemaps.md @@ -7,7 +7,7 @@ status: recommended order: 20 appliesTo: [all] relatedSlugs: [sitemap-index, image-sitemaps, robots-txt, canonical-url, schemamap] -updated: "2026-07-09T00:00:00.000Z" +updated: "2026-09-10T00:00:00.000Z" sources: - title: "Sitemaps XML format" url: "https://www.sitemaps.org/protocol.html" @@ -15,12 +15,12 @@ sources: - title: "Build and submit a sitemap" url: "https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap" publisher: "Google Search Central" - - title: "XSL Transformations (XSLT) Version 1.0" - url: "https://www.w3.org/TR/xslt-10/" - publisher: "W3C" - - title: "XML sitemaps: the most important SEO tool" - url: "https://yoast.com/what-is-an-xml-sitemap-and-why-should-you-have-one/" - publisher: "Yoast" + - title: "HTML Standard — Interactions with XPath and XSLT" + url: "https://html.spec.whatwg.org/multipage/infrastructure.html#interactions-with-xpath-and-xslt" + publisher: "WHATWG" + - title: "Removing XSLT for a more secure browser" + url: "https://developer.chrome.com/docs/web-platform/deprecating-xslt" + publisher: "Chrome for Developers" --- ## What it is @@ -65,23 +65,17 @@ Generate sitemaps dynamically from your content source, not by crawling your own **This site ships it.** `specification.website` generates [`/sitemap-index.xml`](/sitemap-index.xml) at build time from the content collection, and sets each `` from the entry's `updated` front matter — the same field the [RSS feed](/rss.xml) uses — rather than the build timestamp, so the date only moves when the content actually changes. -## A stylesheet for human readers +## Do not attach an XSL stylesheet -Browsers parse XML, but the raw view is hostile to anyone who is not a crawler. An [XSL stylesheet](https://www.w3.org/TR/xslt-10/) referenced from the sitemap transforms it into HTML in the browser, so a person who opens the URL sees a readable page with clickable links. Crawlers ignore the stylesheet and parse the underlying XML directly. +A sitemap opened in a browser shows raw XML, which is hostile to anyone who is not a crawler. The long-standing fix was an `` processing instruction pointing at an XSLT stylesheet, which the browser applied to render the sitemap as a readable HTML table. That advice has expired. -Reference the stylesheet with an `` processing instruction immediately after the XML declaration, before the `` (or ``) root element: +Since August 2026 the [HTML Standard](https://html.spec.whatwg.org/multipage/infrastructure.html#interactions-with-xpath-and-xslt) tells authors to avoid client-side XSLT outright: browser XSLT implementations are, in its words, highly susceptible to memory-safety vulnerabilities, and the feature is being removed from the web platform. Chrome plans to disable native XSLT in version 158, scheduled for 17 November 2026, with temporary exceptions for origin-trial and enterprise-policy participants until Chrome 176, scheduled for 17 August 2027. Firefox and WebKit have also signalled removal intent; they do not share Chrome's published timetable. -```xml - - - - ... - -``` +The failure is worth understanding precisely, because it is milder than it sounds and that is exactly why it gets left in place too long. Crawlers never read the stylesheet; they parse the XML underneath it, and an `` instruction a parser cannot process is ignored rather than fatal. So nothing about discovery or indexing breaks. What breaks is the human view: a URL that rendered a tidy table starts rendering the browser's raw-XML fallback, and nobody notices until someone opens the sitemap and reports it as a bug. -The same stylesheet can render both `` and `` documents by matching on the root element. Serve the `.xsl` file as `application/xslt+xml` from the same origin as the sitemap; cross-origin XSL is blocked by browsers. XSLT 1.0 is supported by current Chrome, Firefox, and Safari with no client-side dependencies. +XML itself and XML styled with CSS remain supported; this removal concerns native XSLT transformations. If you want a page a person can read, write one in HTML and link it. It costs no more than the stylesheet did, it is crawlable and linkable in its own right, and it does not depend on a feature three engines are deleting. -**This site ships it.** Open [`/sitemap-index.xml`](/sitemap-index.xml) or any per-category sitemap in a browser to see the transformed view. The stylesheet lives at [`/sitemap.xsl`](/sitemap.xsl). +**This site no longer does it.** `specification.website` pointed its sitemaps at a `/sitemap.xsl` until this page changed; the processing instruction has been dropped rather than left to break. ## Common mistakes diff --git a/src/lib/sitemap.ts b/src/lib/sitemap.ts index 5df73487..da4f16b8 100644 --- a/src/lib/sitemap.ts +++ b/src/lib/sitemap.ts @@ -37,10 +37,9 @@ export function clampLastmod(d: string | undefined): string | undefined { } const XML_DECL = ''; -const STYLESHEET_PI = ''; export function renderUrlset(entries: SitemapEntry[]): string { - const lines: string[] = [XML_DECL, STYLESHEET_PI]; + const lines: string[] = [XML_DECL]; lines.push(''); for (const e of entries) { lines.push(" "); @@ -54,7 +53,7 @@ export function renderUrlset(entries: SitemapEntry[]): string { } export function renderSitemapIndex(entries: SitemapEntry[]): string { - const lines: string[] = [XML_DECL, STYLESHEET_PI]; + const lines: string[] = [XML_DECL]; lines.push( '', );