3

I am trying to style XML fragment from a server response with a Greasemonkey script.

Example XML fragment from w3schools.com:

<note>
  <to> Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>

(It has no declaration on top like <?xml version="1.0" encoding="UTF-8"?>)

Firefox reports:

This XML file does not appear to have any style information associated with it. The document tree is shown below.

How can I style the display?
Can I convert it to proper HTML? How?

N.B. I can grab and parse the data using XHR but I am trying to avoid XHR and use the browser to display the data (since it is a GET method). All I need is to format it to a more readable format.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
erosman
  • 7,094
  • 7
  • 27
  • 46

1 Answers1

4

You "style" XML using Extensible Stylesheet Language Transformations (XSLT). XSLT parses XML into HTML using stylesheets. You can then use standard CSS to format the display of the resulting HTML.

For the sample XML you cited, this stylesheet:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"/>
    <xsl:template match="/">
        <html>
            <body>
                <xsl:for-each select="note">
                    <p> <xsl:value-of select="body"/> </p>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

would give you a properly formed HTML document that just listed the note body. EG: Don't forget me this weekend! from your example.


Use XSLTProcessor() to run XSLT in a Greasemonkey script, like so:

// ==UserScript==
// @name        _XML renderer / styler
// @description stylesheet for xml results
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*.xml
// @include     http://www.w3schools.com/xml/note.xml
// @grant       none
// ==/UserScript==

//-- Warning, multiline str is new in JS. Only Firefox supports at the moment.
var xsl_str = `<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"/>
    <xsl:template match="/">
        <html>
            <head>
                <title>My super new note format!</title>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
                <style type="text/css">
                    body { padding: 0 2em; }
                    .noteCtr {
                        border: 1px solid gray;
                        border-radius: 1ex;
                        padding: 0;
                        background: #FAFAFA;
                    }
                    .messPeople { font-size: 1em; margin: 1ex 1em; }
                    .messHeading { background: lightcyan; margin: 0 1.6ex; }
                    .messHeading::after { content: ":"; }
                    .noteCtr > p {
                        background: white;
                        padding: 1em;
                        margin: 0 1em 1.5ex 1em;
                    }
                </style>
            </head>
            <body>
                <xsl:for-each select="note">
                    <div class="noteCtr">
                        <h3 class="messPeople">
                            <xsl:value-of select="from"/>
                            --&gt;
                            <xsl:value-of select="to"/>
                        </h3>
                        <h3 class="messHeading"> <xsl:value-of select="heading"/> </h3>
                        <p> <xsl:value-of select="body"/> </p>
                    </div>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>
`;

var processor   = new XSLTProcessor ();
var dataXSL     = new DOMParser ().parseFromString (xsl_str, "text/xml");

processor.importStylesheet (dataXSL);

var newDoc      = processor.transformToDocument (document);

//-- These next lines swap the new, processed doc in for the old one...
window.content  = newDoc;

document.replaceChild (
    document.importNode (newDoc.documentElement, true),
    document.documentElement
);


Here I stored the stylesheet in the xsl_str variable. For more involved operations, you may find it better to fetch the stylesheet via a @resource directive.

Install that script and then visit your example XML.

You will see it transform that document...

From:

Before XSLT

To:

After XSLT

Community
  • 1
  • 1
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • you don't actually need to use XSLT to style XML, you can also apply a CSS stylesheet by using a xml stylesheet processing node, see http://www.w3.org/Style/styling-XML.en.html – the8472 Mar 28 '15 at 15:19
  • This doesn't seem to work in Chrome (not because of missing `\`` support, but because the `body` in `newContent` isn't populated), while the code works in Firefox, I can't get this loaded when using ViolentMonkey – Treviño Jul 29 '19 at 12:41
  • As follow-up, in webkit browers this seems related to the XML pretty printer (see https://stackoverflow.com/questions/16729263/get-xml-document-in-chrome-via-js) and so instead of `document` something like the result of `new DOMParser().parseFromString(document.getElementById('webkit-xml-viewer-source-xml').innerHTML, 'text/xml');` should be used – Treviño Jul 29 '19 at 13:40
  • @Treviño, a lot has changed in 4.5 years and the [greasemonkey] tag implies Firefox-only (as apposed to the [tampermonkey] or [userscripts] tags). Open a new question if you need to. – Brock Adams Jul 29 '19 at 14:17
  • FYI, Tampermonkey works fine (in firefox at least). – Treviño Jul 29 '19 at 14:26
  • @Treviño, so you say that on Firefox, the script works on Tampermonkey but not Violentmonkey? If so, that may be due to Violentmonkey's `@inject-into` setting. But I don't have time to look into this right now. – Brock Adams Jul 29 '19 at 14:31