How to transform an XML file with XSLT, using a Greasemonkey script?

元气小坏坏 提交于 2020-01-11 07:04:11

问题


I have a search server that provides a test page where I can input a query and it returns the results in XML. I want to be able to go through the results in a more user friendly way so I started playing around with XSLT and I have a simple style-sheet now that turns a somehow bloated XML into a simple table showing just some of the data. This works fine when I do it locally - that is, adding the XSL declaration to the XML and then opening the XML in a browser like Firefox.

What I want to do though is to apply this transformation live in the browser, as soon as I fetch the results from the server through that test page. I investigated a bit and found that it's possible to do this with javascript.

Then I thought about Greasemonkey userscripts that can inject javascript into a page dynamically. I would just need a script that would kick in when I get the XML results from the test page. However, I'm stuck there because it seems like Greasemonkey isn't allowing scripts to run on XML files (at least in Firefox).

I found very few examples and tried to use them as inspiration but couldn't make them work. (Here's one, for example.)

Here's a simplified example of the XML I'm getting:

<?xml version="1.0" encoding="utf-8"?>
<Results>
    <Result>
        <Listings total="2">
            <Res>
                <Result index="0">
                    <id>123456</id>
                    <name>My Business</name>
                    <category>Restaurants</category>
                    <phone>9872365</phone>
                </Result>
            </Res>
            <Res>
                <Result index="1">
                    <id>876553</id>
                    <name>Some Other Business</name>
                    <category>Restaurants</category>
                    <phone>9834756</phone>
                </Result>
            </Res>
        </Listings>
    </Result>
</Results>

Here's the script I'm loading in Greasemonkey - where nothing's happening:

// ==UserScript==
// @name test xml renderer
// @namespace http://sample.com
// @description stylesheet for xml results
// @include *
// ==/UserScript==

(function () {
    var xsl_str = '<?xml version="1.0" encoding="utf-8"?>\n\
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">\n\
    <xsl:output method="html"/>\n\
    <xsl:template match="/">\n\
        <html>\n\
            <head></head>\n\
            <body>\n\
                <table id="results" border="1" cellspacing="0" cellpadding="0">\n\
                    <thead>\n\
                        <tr>\n\
                            <th class="name">id</th>\n\
                            <th class="name">category ID</th>\n\
                            <th class="name">name</th>\n\
                            <th class="name">phone</th>\n\
                        </tr>\n\
                    </thead>\n\
                    <tbody>\n\
                        <xsl:for-each select="Results/Result/Listings/Res">\n\
                            <tr>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/id"/>\n\
                                </td>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/category"/>\n\
                                </td>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/name"/>\n\
                                </td>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/phone"/>\n\
                                </td>\n\
                            </tr>\n\
                        </xsl:for-each>\n\
                    </tbody>\n\
                </table>\n\
            </body>\n\
        </html>\n\
    </xsl:template>\n\
</xsl:stylesheet>\n\
';

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

    processor.importStylesheet(dataXSL);
    dataXML = document;
    var ownerDocument = document.implementation.createDocument("", "", null);
    var newFragment = processor.transformToFragment(dataXML, ownerDocument);
    dataXML.documentElement.replaceChild(newFragment, dataXML.documentElement.firstChild);
})();

When I enable this script in Greasemonkey then all pages are successfully replaced with the HTML above in the XSL template. However it doesn't seem to apply to a local XML file or any XML coming from my server.(I know that to make Greasemonkey work with local files a setting needs to be changed in about:config in Firefox - extensions.greasemonkey.fileIsGreaseable).

I don't have any experience with javascript so most likely I'm just making a very basic mistake. In in case, all the help is really appreciated.


回答1:


That script is nuking or adding to document.head. You want to replace the whole document with transformed content. You could do that by changing location.href to an appropriately constructed data: URL. But a neater approach is to replace the whole document.documentElement.

This script works on your test/sample XML file:

// ==UserScript==
// @name        _Test XML Renderer
// @description stylesheet for xml results
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*.xml
// @grant       none
// ==/UserScript==

var xsl_str = '<?xml version="1.0" encoding="utf-8"?>\n\
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">\n\
    <xsl:output method="html"/>\n\
    <xsl:template match="/">\n\
        <html>\n\
            <head></head>\n\
            <body>\n\
                <table id="results" border="1" cellspacing="0" cellpadding="0">\n\
                    <thead>\n\
                        <tr>\n\
                            <th class="name">id</th>\n\
                            <th class="name">category ID</th>\n\
                            <th class="name">name</th>\n\
                            <th class="name">phone</th>\n\
                        </tr>\n\
                    </thead>\n\
                    <tbody>\n\
                        <xsl:for-each select="Results/Result/Listings/Res">\n\
                            <tr>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/id"/>\n\
                                </td>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/category"/>\n\
                                </td>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/name"/>\n\
                                </td>\n\
                                <td class="small" width="120">\n\
                                    <xsl:value-of select="Result/phone"/>\n\
                                </td>\n\
                            </tr>\n\
                        </xsl:for-each>\n\
                    </tbody>\n\
                </table>\n\
            </body>\n\
        </html>\n\
    </xsl:template>\n\
</xsl:stylesheet>\n\
';

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
);



回答2:


I would have added this in a comment, but I don't have the relevant reputation. There are two things that I would check. Especially if this is working on a string, and not a file from the server like you said

  1. Make sure that what you are getting from the server is a string, and not an object
  2. Make sure the xml you are getting from the server is correct.

If you aren't getting a string, you can do an ajax request to get the text from the xml. And then load that as your new xml var.

And if you really just wanted to make your xml user friendly, I would suggest checking out
http://code.google.com/p/vkbeautify
and
http://google-code-prettify.googlecode.com/svn/trunk/README.html

Those should maintain the xml format while stylizing it to make it easy to read. Plus, you won't have to mess with greasemonkey, and can instead just use javascript.



来源:https://stackoverflow.com/questions/17998446/how-to-transform-an-xml-file-with-xslt-using-a-greasemonkey-script

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!