Sitemap XSL not working? Use a CSS stylesheet
Your sitemap looked like a table and now it is a wall of XML, or it will be soon. A CSS file brings back a readable page and keeps working in every browser.
Last updated: · What changed: Added an accuracy table, coverage statement and Chrome 158 sourcing, and a new operator section on the About page.
The line to put in your XML file
Replace the xml-stylesheet line that points to your .xsl file with this one, and upload the CSS file to the address in href.
Why the page turned into raw XML
Many sitemaps start with a line such as <?xml-stylesheet type="text/xsl" href="/main-sitemap.xsl"?>. The browser downloads that XSL file and uses it to draw a table. When the browser no longer runs XSLT, it skips the step and shows the XML tree. Your sitemap data is untouched; search engines still read it the same way.
How to swap the line
- Choose Sitemap (or Sitemap index if your file starts with
<sitemapindex>) in the generator above. - Download the CSS and upload it to your site, for example as
/sitemap.css. - Replace the line that mentions your .xsl file with the line the generator shows. Paste the first lines of your file into the box and it does the swap for you.
- Reload the sitemap and run it through the checker: it should read “Safe (CSS stylesheet)”.
If a WordPress plugin writes the file, it will overwrite your edit on the next update. Use the plugin's own setting or filter instead; the checker names the plugin and the steps when it recognises it.
What CSS cannot do
CSS can restyle the tags it finds, add labels like “Last modified” and hide fields. It cannot turn rows into a real table, sort, count or compute anything. If you need that, render an HTML page at build time; see how to migrate from XSLT.
Other fixes
- Delete the stylesheet line. The sitemap then shows as plain XML, which is fine for search engines.
- Keep the XSL and add the polyfill script line to the file.
Keep the transformation at build time
For sorting, computed values or clickable HTML links, render an HTML file during your build. Install xslt-processor in your Node project, save this as render.mjs and pass your XML and XSL paths. Keep the original XML endpoint for search engines.
// render.mjs -> node render.mjs sitemap.xml sitemap.xsl > sitemap.html
import { readFileSync } from 'node:fs';
import { Xslt, XmlParser } from 'xslt-processor';
const [xmlFile, xslFile] = process.argv.slice(2);
const parser = new XmlParser();
const html = await new Xslt().xsltProcess(
parser.xmlParse(readFileSync(xmlFile, 'utf8')),
parser.xmlParse(readFileSync(xslFile, 'utf8')),
);
process.stdout.write(html);Test your sitemap stylesheet against the chosen Node engine; implementations differ. For an existing XSLT 1.0 page, you can instead self-host the polyfill and add this element inside the XML root:
<script src="/xslt-polyfill.min.js" xmlns="http://www.w3.org/1999/xhtml"></script>For installation details, read the self-hosting instructions and limitations, or compare migration routes.
Questions
Why is my sitemap showing raw XML?
The browser could not apply the stylesheet named in the first lines of the file. After Chrome removes XSLT on Nov 17, 2026, every sitemap that relies on an XSL file will show as raw XML in it. Replace the line with a CSS stylesheet, or delete it.
Will this hurt my search rankings?
No. Search engines read the URLs and dates in the XML and ignore how it looks in a browser.
Does Chrome still support CSS on XML?
Yes. The official page says the processing instruction stays supported when used with CSS; only XSLT is removed.
Can I use the same CSS file for several sitemaps?
Yes. Point every file at the same CSS address. Use the sitemap-index version for a file that starts with sitemapindex and the sitemap version for urlset.
My plugin keeps adding the XSL line back. What now?
Look for a setting or a filter in the plugin that controls the stylesheet and turn it off; the checker lists steps for common plugins. Editing the generated file by hand does not last, because the plugin rewrites it.