{"id":15478,"date":"2025-09-02T13:48:49","date_gmt":"2025-09-02T13:48:49","guid":{"rendered":"http:\/\/localhost\/?p=15478"},"modified":"2025-09-02T13:48:49","modified_gmt":"2025-09-02T13:48:49","slug":"making-xml-human-readable-without-xslt","status":"publish","type":"post","link":"https:\/\/zero.redgem.net\/?p=15478","title":{"rendered":"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C"},"content":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2025-09-02T17:54:11&#8243;,&#8221;description&#8221;:&#8221;Ok. This one is niche. But heh, you might enjoy a dive into this esoteric corner of the web \u2013 I certainly did.\\n\\n## XSLT and browser support\\n\\nI want to get to the technical-fun bits quickly, so here&#8217;s a quick rundown:\\n\\n  * XSLT is an XML language for transforming XML, including transforming it into non-XML formats, such as HTML.\\n  * Browsers currently support a ~25 year old version of XSLT natively (examples coming up later).\\n  * This feature is barely used. Usage is lower than features that were subsequently removed from browsers, such as mutation events and Flash.\\n  * The feature is often the source of significant security issues.\\n\\n\\n\\nThis leaves browsers with a choice: Take development time away from features that have significant usage and developer demand, and instead use those resources to improve (probably rewrite) XSLT processing in browsers. Or, remove XSLT from browser engines.\\n\\nCurrently, Chrome, Safari, and Firefox support removing XSLT.\\n\\nIf you want to know more of the process \\u0026 history here, I recommend Eric Meyer&#8217;s blog post.\\n\\nRight, let&#8217;s take a look at XSLT and the alternatives.\\n\\n## How XSLT works\\n\\nTake some XML like this:\\n    \\n    \\n    \\u003c?xml version=\\&#8221;1.0\\&#8221; encoding=\\&#8221;UTF-8\\&#8221;?\\u003e\\n    \\u003c?xml-stylesheet type=\\&#8221;text\/xsl\\&#8221; href=\\&#8221;books.xsl\\&#8221;?\\u003e\\n    \\u003cauthors\\u003e\\n      \\u003cauthor\\u003e\\n        \\u003cname\\u003eDouglas Adams\\u003c\/name\\u003e\\n        \\u003cbook\\u003e\\n          \\u003ctitle\\u003eThe Hitchhiker&#8217;s Guide to the Galaxy\\u003c\/title\\u003e\\n          \\u003cgenre\\u003eScience Fiction Comedy\\u003c\/genre\\u003e\\n          \\u003ccover\\u003ehttps:\/\/covers.openlibrary.org\/b\/isbn\/0330258648-L.jpg\\u003c\/cover\\u003e\\n        \\u003c\/book\\u003e\\n        \\u003cbook\\u003e\\n          \u2026\\n        \\u003c\/book\\u003e\\n        \u2026\\n      \\u003c\/author\\u003e\\n      \\u003cauthor\\u003e\\n        \\u003cname\\u003eGeorge Orwell\\u003c\/name\\u003e\\n        \\u003cbook\\u003e\\n          \u2026\\n        \\u003c\/book\\u003e\\n      \\u003c\/author\\u003e\\n      \u2026\\n    \\u003c\/authors\\u003e\\n\\nIf you visit that document, you&#8217;ll (for now, at least), see a grid of books, with formatting and images, and that&#8217;s all down to:\\n    \\n    \\n    \\u003c?xml-stylesheet type=\\&#8221;text\/xsl\\&#8221; href=\\&#8221;books.xsl\\&#8221;?\\u003e\\n\\n\u2026which tells the browser to transform the XML using XSLT.\\n\\nHere&#8217;s the full source if you&#8217;re interested, but here&#8217;s the snippet that renders each book:\\n    \\n    \\n    \\u003cxsl:template name=\\&#8221;book\\&#8221;\\u003e\\n      \\u003cdiv class=\\&#8221;book\\&#8221;\\u003e\\n        \\u003cimg class=\\&#8221;cover\\&#8221;\\u003e\\n          \\u003cxsl:attribute name=\\&#8221;src\\&#8221;\\u003e\\n            \\u003cxsl:value-of select=\\&#8221;cover\\&#8221; \/\\u003e\\n          \\u003c\/xsl:attribute\\u003e\\n          \\u003cxsl:attribute name=\\&#8221;alt\\&#8221; \/\\u003e\\n        \\u003c\/img\\u003e\\n        \\u003cdiv class=\\&#8221;book-info\\&#8221;\\u003e\\n          \\u003cdiv\\u003e\\n            \\u003cspan class=\\&#8221;title\\&#8221;\\u003e\\u003cxsl:value-of select=\\&#8221;title\\&#8221; \/\\u003e\\u003c\/span\\u003e\\n            -\\n            \\u003cspan class=\\&#8221;author\\&#8221;\\u003e\\u003cxsl:value-of select=\\&#8221;..\/name\\&#8221; \/\\u003e\\u003c\/span\\u003e\\n          \\u003c\/div\\u003e\\n          \\u003cdiv\\u003e\\n            \\u003cspan class=\\&#8221;genre\\&#8221;\\u003e\\u003cxsl:value-of select=\\&#8221;genre\\&#8221; \/\\u003e\\u003c\/span\\u003e\\n          \\u003c\/div\\u003e\\n        \\u003c\/div\\u003e\\n      \\u003c\/div\\u003e\\n    \\u003c\/xsl:template\\u003e\\n\\nThis template maps a `\\u003cbook\\u003e` into a `\\u003cdiv class=\\&#8221;book\\&#8221;\\u003e`, although it reaches up into the parent `\\u003cauthor\\u003e` to get the author name.\\n\\nI used to write XSLT as part of my first job ~20 years ago. Making this demo felt _deeply weird_. I kinda love\/hate how you need to add _children_ to the usually-empty `\\u003cimg\\u003e` to set attributes.\\n\\nAnyway, assuming the above will stop working someday, what are the alternatives?\\n\\n## Styling XML\\n\\nIn some cases, you might get away with just styling XML, which you can do using:\\n    \\n    \\n    \\u003c?xml-stylesheet type=\\&#8221;text\/css\\&#8221; href=\\&#8221;styles.css\\&#8221;?\\u003e\\n\\nNow you can style your XML document using regular CSS. Just make sure your document is served with `Content-Type: text\/xml` (rather than, e.g. a more specific RSS content type), otherwise the browser won&#8217;t use the styles.\\n\\nWhat you can do here is pretty limited. In the XSLT example, I take the text content of the `\\u003ccover\\u003e` element, and make it the `src` of an image. I also repeat the author&#8217;s `\\u003cname\\u003e` for each book. Neither of these is possible with CSS alone.\\n\\nAlso, the document will have the semantics of the XML document, which likely means \\&#8221;no semantics\\&#8221;, so the result will have poor accessibility. For example, even if your XML contains `\\u003ch1\\u003e`, unless you&#8217;ve told it to be an HTML element, the browser won&#8217;t recognise it as a heading.\\n\\nThat said, if you just want to catch users that mistakenly land on some XML, you can get away with something like this:\\n    \\n    \\n    :root {\\n      \\u0026 \\u003e * {\\n        display: none;\\n      }\\n    \\n      \\u0026::before {\\n        content: &#8216;Hi there! This is my RSS feed. &#8216;\\n          \\&#8221;It isn&#8217;t meant to be human-readable\u2026\\&#8221;;\\n      }\\n    }\\n\\nWhich is what I&#8217;ve done with my RSS feed.\\n\\nFor anything more complex, you need to do some kind of transformation of the source data.\\n\\n## Wait, do you really want to do this client-side?\\n\\nIn almost all cases, the best thing to do is convert your data to HTML on the server, or as part of a build process. When you do that:\\n\\n  * The HTML form of your data is more likely to be seen by crawlers and scrapers.\\n  * The browser can render the page in a streaming way, meaning a faster experience for users.\\n  * You can use whatever tools you like to do the transformation \u2013 you aren&#8217;t limited to things the browser supports natively.\\n\\n\\n\\nThis might mean you end up with two published files, one for humans (as HTML), and one for machines (as XML or whatever). This is fine. My blog posts and my RSS feed are different resources, even though they have data in common. All my posts have this in the head:\\n    \\n    \\n    \\u003clink\\n      rel=\\&#8221;alternate\\&#8221;\\n      type=\\&#8221;application\/rss+xml\\&#8221;\\n      title=\\&#8221;Jake Archibald&#8217;s Blog\\&#8221;\\n      href=\\&#8221;https:\/\/jakearchibald.com\/posts.rss\\&#8221;\\n    \/\\u003e\\n\\n\u2026meaning feed readers can find the RSS feed from any post.\\n\\nBut if you really need to, here&#8217;s how to do the transformation on the client, without XSLT:\\n\\n## Transforming XML client-side without XSLT\\n\\nIf you just want to make some existing XSLT work in browsers that don&#8217;t support it, check out Mason&#8217;s XSLT polyfill. But if you don&#8217;t need to use XSLT, JavaScript is, in my opinion, a better option.\\n\\nHere&#8217;s a demo that produces the same result as the XSLT demo, but this time using JS. Here&#8217;s how it works\u2026\\n\\nIn the XML, instead of including XSLT, I include a script as the first child of the root:\\n    \\n    \\n    \\u003cauthors\\u003e\\n      \\u003cscript\\n        xmlns=\\&#8221;http:\/\/www.w3.org\/1999\/xhtml\\&#8221;\\n        src=\\&#8221;script.js\\&#8221;\\n        defer=\\&#8221;\\&#8221;\\n      \/\\u003e\\n      \u2026\\n\\nThe `xmlns` attribute is important, as it tells the browser this is an HTML script element, rather than some other kind of XML element.\\n\\nTechnically, this is changing the data structure. Validating parsers would see a `\\u003cscript\\u003e` they weren&#8217;t expecting, and throw an error. However, most parsers are not validating, as they want to allow for extensions to whatever format they&#8217;re reading.\\n\\nThen, in that script:\\n    \\n    \\n    \/\/ Get the XML data\\n    const data = document.documentElement;\\n    \/\/ Create an HTML root element\\n    const htmlEl = document.createElementNS(\\n      &#8216;http:\/\/www.w3.org\/1999\/xhtml&#8217;,\\n      &#8216;html&#8217;,\\n    );\\n    \/\/ Swap the two over\\n    data.replaceWith(htmlEl);\\n\\nNow all I had to do was populate that `html` element. I created a simple templating function. For example, here&#8217;s the snippet that renders each book:\\n    \\n    \\n    const bookHTML = (bookEl) =\\u003e html`\\n      \\u003cdiv class=\\&#8221;book\\&#8221;\\u003e\\n        \\u003cimg\\n          class=\\&#8221;cover\\&#8221;\\n          src=\\&#8221;${bookEl.querySelector(&#8216;:scope \\u003e cover&#8217;).textContent}\\&#8221;\\n          alt=\\&#8221;\\&#8221;\\n        \/\\u003e\\n        \\u003cdiv class=\\&#8221;book-info\\&#8221;\\u003e\\n          \\u003cdiv\\u003e\\n            \\u003cspan class=\\&#8221;title\\&#8221;\\u003e\\n              ${bookEl.querySelector(&#8216;:scope \\u003e title&#8217;).textContent}\\n            \\u003c\/span\\u003e\\n            -\\n            \\u003cspan class=\\&#8221;author\\&#8221;\\u003e\\n              ${bookEl.parentNode.querySelector(&#8216;:scope \\u003e name&#8217;).textContent}\\n            \\u003c\/span\\u003e\\n          \\u003c\/div\\u003e\\n          \\u003cdiv\\u003e\\n            \\u003cspan class=\\&#8221;genre\\&#8221;\\u003e\\n              ${bookEl.querySelector(&#8216;:scope \\u003e genre&#8217;).textContent}\\n            \\u003c\/span\\u003e\\n          \\u003c\/div\\u003e\\n        \\u003c\/div\\u003e\\n      \\u003c\/div\\u003e\\n    `;\\n\\nIt&#8217;s very similar to the XSLT equivalent, _and_ it can be debugged using regular JavaScript tooling.\\n\\n### Ensure you&#8217;re creating _HTML_ elements\\n\\nOne gotcha when creating HTML in an XML document is it&#8217;s easy to accidentally create XML elements rather than HTML elements. If you want proper semantics, accessibility, and behaviour, you want real HTML elements.\\n\\nFor example:\\n    \\n    \\n    \/\/ In an XML document this will not create an HTML element:\\n    const xmlElement = document.createElement(&#8216;h1&#8217;);\\n    \/\/ Instead, you need to use:\\n    const htmlElement = document.createElementNS(\\n      &#8216;http:\/\/www.w3.org\/1999\/xhtml&#8217;,\\n      &#8216;h1&#8217;,\\n    );\\n\\nIf you&#8217;re using a framework to create the elements, check that it&#8217;s creating real HTML elements \u2013 `el.namespaceURI` should be `\\&#8221;http:\/\/www.w3.org\/1999\/xhtml\\&#8221;`.\\n\\nThe `xmlns` attribute we used earlier only works via the parser, so this _doesn&#8217;t_ create an HTML element in an XML document:\\n    \\n    \\n    const h1 = document.createElement(&#8216;h1&#8217;);\\n    h1.setAttribute(&#8216;xmlns&#8217;, &#8216;http:\/\/www.w3.org\/1999\/xhtml&#8217;);\\n\\nHowever, `innerHTML` and `setHTMLUnsafe` will assume the content is HTML, which is what I used:\\n    \\n    \\n    htmlEl.setHTMLUnsafe(html`\\n      \\u003chead\\u003e\\n        \\u003ctitle\\u003eSome books\\u003c\/title\\u003e\\n        \\u003cmeta name=\\&#8221;viewport\\&#8221; content=\\&#8221;width=device-width, initial-scale=1\\&#8221; \/\\u003e\\n      \\u003c\/head\\u003e\\n      \\u003cbody\\u003e\\n        \\u003ch1\\u003eSome books\\u003c\/h1\\u003e\\n        \\u003cul class=\\&#8221;book-list\\&#8221;\\u003e\\n          ${[&#8230;data.querySelectorAll(&#8216;book&#8217;)].map(\\n            (book) =\\u003e html`\\u003cli\\u003e${bookHTML(book)}\\u003c\/li\\u003e`,\\n          )}\\n        \\u003c\/ul\\u003e\\n      \\u003c\/body\\u003e\\n    `);\\n\\nHere&#8217;s the full working demo, and the source. And that&#8217;s it! Wow you made it to the end. Huh. I didn&#8217;t think anyone would.&#8221;,&#8221;published&#8221;:&#8221;2025-09-02T01:00:00&#8243;,&#8221;modified&#8221;:&#8221;2025-09-02T01:00:00&#8243;,&#8221;type&#8221;:&#8221;jakearchibald&#8221;,&#8221;title&#8221;:&#8221;Making XML human-readable without XSLT&#8221;,&#8221;source&#8221;:&#8221;&#8221;,&#8221;references&#8221;:&#8221;&#8221;,&#8221;id&#8221;:&#8221;JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C&#8221;,&#8221;bulletinFamily&#8221;:&#8221;blog&#8221;,&#8221;cwe&#8221;:null,&#8221;cvelist&#8221;:[],&#8221;sourceData&#8221;:&#8221;&#8221;,&#8221;sourceHref&#8221;:&#8221;&#8221;,&#8221;cvss&#8221;:{&#8220;score&#8221;:0,&#8221;severity&#8221;:&#8221;NONE&#8221;,&#8221;vector&#8221;:&#8221;NONE&#8221;,&#8221;version&#8221;:&#8221;NONE&#8221;},&#8221;cvss2&#8243;:{},&#8221;cvss3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;,&#8221;cvssV3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;}},&#8221;href&#8221;:&#8221;https:\/\/jakearchibald.com\/2025\/making-xml-human-readable-without-xslt\/&#8221;,&#8221;category_name&#8221;:&#8221;News&#8221;,&#8221;post_link&#8221;:&#8221;&#8221;,&#8221;product&#8221;:&#8221;&#8221;,&#8221;version&#8221;:&#8221;&#8221;,&#8221;vendor&#8221;:&#8221;&#8221;,&#8221;ai_description&#8221;:&#8221;&#8221;,&#8221;ai_severity&#8221;:&#8221;&#8221;,&#8221;ai_vendor&#8221;:&#8221;&#8221;,&#8221;ai_product&#8221;:&#8221;&#8221;,&#8221;ai_version&#8221;:&#8221;&#8221;,&#8221;ai_score&#8221;:0}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2025-09-02T17:54:11&#8243;,&#8221;description&#8221;:&#8221;Ok. This one is niche. But heh, you might enjoy a dive into this esoteric corner of the web \u2013 I certainly did.\\n\\n## XSLT and&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[6,8,12,161,13,33,7,11,5],"class_list":["post-15478","post","type-post","status-publish","format-standard","hentry","category-category_news","tag-cve","tag-cvss","tag-exploit","tag-jakearchibald","tag-news","tag-none","tag-security","tag-tapic","tag-vulnerability"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C - zero redgem<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zero.redgem.net\/?p=15478\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C - zero redgem\" \/>\n<meta property=\"og:description\" content=\"{&#8220;lastseen&#8221;:&#8221;2025-09-02T17:54:11&#8243;,&#8221;description&#8221;:&#8221;Ok. This one is niche. But heh, you might enjoy a dive into this esoteric corner of the web \u2013 I certainly did.nn## XSLT and...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zero.redgem.net\/?p=15478\" \/>\n<meta property=\"og:site_name\" content=\"zero redgem\" \/>\n<meta property=\"article:published_time\" content=\"2025-09-02T13:48:49+00:00\" \/>\n<meta name=\"author\" content=\"invoker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"invoker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=15478#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=15478\"},\"author\":{\"name\":\"invoker\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\"},\"headline\":\"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C\",\"datePublished\":\"2025-09-02T13:48:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=15478\"},\"wordCount\":2006,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"keywords\":[\"CVE\",\"CVSS\",\"exploit\",\"jakearchibald\",\"news\",\"NONE\",\"Security\",\"tapic\",\"Vulnerability\"],\"articleSection\":[\"category_news\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=15478#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=15478\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?p=15478\",\"name\":\"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C - zero redgem\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\"},\"datePublished\":\"2025-09-02T13:48:49+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=15478#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=15478\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=15478#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/zero.redgem.net\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"name\":\"zero redgem\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/zero.redgem.net\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\",\"name\":\"zero redgem\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"\",\"contentUrl\":\"\",\"width\":191,\"height\":188,\"caption\":\"zero redgem\"},\"image\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\",\"name\":\"invoker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"caption\":\"invoker\"},\"sameAs\":[\"https:\\\/\\\/zero.redgem.net\"],\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C - zero redgem","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zero.redgem.net\/?p=15478","og_locale":"en_US","og_type":"article","og_title":"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C - zero redgem","og_description":"{&#8220;lastseen&#8221;:&#8221;2025-09-02T17:54:11&#8243;,&#8221;description&#8221;:&#8221;Ok. This one is niche. But heh, you might enjoy a dive into this esoteric corner of the web \u2013 I certainly did.nn## XSLT and...","og_url":"https:\/\/zero.redgem.net\/?p=15478","og_site_name":"zero redgem","article_published_time":"2025-09-02T13:48:49+00:00","author":"invoker","twitter_card":"summary_large_image","twitter_misc":{"Written by":"invoker","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zero.redgem.net\/?p=15478#article","isPartOf":{"@id":"https:\/\/zero.redgem.net\/?p=15478"},"author":{"name":"invoker","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca"},"headline":"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C","datePublished":"2025-09-02T13:48:49+00:00","mainEntityOfPage":{"@id":"https:\/\/zero.redgem.net\/?p=15478"},"wordCount":2006,"commentCount":0,"publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"keywords":["CVE","CVSS","exploit","jakearchibald","news","NONE","Security","tapic","Vulnerability"],"articleSection":["category_news"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zero.redgem.net\/?p=15478#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zero.redgem.net\/?p=15478","url":"https:\/\/zero.redgem.net\/?p=15478","name":"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C - zero redgem","isPartOf":{"@id":"https:\/\/zero.redgem.net\/#website"},"datePublished":"2025-09-02T13:48:49+00:00","breadcrumb":{"@id":"https:\/\/zero.redgem.net\/?p=15478#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zero.redgem.net\/?p=15478"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/zero.redgem.net\/?p=15478#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zero.redgem.net\/"},{"@type":"ListItem","position":2,"name":"Making XML human-readable without XSLT_JAKEARCHIBALD:C64062E9787AB9C7165631FA89940F0C"}]},{"@type":"WebSite","@id":"https:\/\/zero.redgem.net\/#website","url":"https:\/\/zero.redgem.net\/","name":"zero redgem","description":"","publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zero.redgem.net\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/zero.redgem.net\/#organization","name":"zero redgem","url":"https:\/\/zero.redgem.net\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/","url":"","contentUrl":"","width":191,"height":188,"caption":"zero redgem"},"image":{"@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca","name":"invoker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","caption":"invoker"},"sameAs":["https:\/\/zero.redgem.net"],"url":"https:\/\/zero.redgem.net\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/15478","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=15478"}],"version-history":[{"count":0,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/15478\/revisions"}],"wp:attachment":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=15478"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=15478"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=15478"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}