xsl:include and xsl:param at Google Chrome, with j

2019-04-22 20:35发布

I've been trying to use XSL with Google Chrome, but with no success.
I read that Chrome have some bugs with XSLT, and one of them is that it doesn't support xsl:include. Bug can be checked here: http://code.google.com/p/chromium/issues/detail?id=8441.
After some research I found a new version of the transform plugin by Daer System, and it makes xsl:include work at Chrome.

jQuery Transform plugin can be found from http://plugins.jquery.com/project/Transform

Now my problem is:
I use a default include in some xsl templates, and this include uses a parameter that is passed to the top level one.

So its like i have the top.xsl template that declares a [xsl:param name="param" /], and i use this param with the included.xsl, that is called by the 1st one with [xsl:include href="included.xsl"] . This works both on Firefox and Internet Explorer, but not on Chrome. I saw a question here on stackoverflow where some guy re-write the webkit fix function from the plugin, but it doesn't work with xsl:param this way.

Does anyone know some way to use [xsl:param] like this in Google Chrome?

3条回答
趁早两清
2楼-- · 2019-04-22 20:53

It's a pain, but you can also work around this using a client-side shim that preloads any xsl:import/xsl:includes in the browser.

The following is TypeScript (basically statically typed JavaScript that compiles to JavaScript) and has a few references to interfaces that..uh, I didn't bother removing, but it seems to work in Chrome (not sure about other browsers) and should be enough to get anyone started on a solution.

module DD.Render.DOM.XSLT {

export class StandardXSLTDOMTransformerFactory implements IXSLTDOMTransformerFactory {

    constructor(private _domParser:DOMParser, private _document:Document) {
    }

    createTransformerFromPath<T>(xslPath: string, xmlTransformer: IStringTransformer<T>, onSuccess: (transformer: IParameterizedDOMTransformer<T>) => void, onFailure: (e: any) => void): void {
        DD.Util.readXML(
            xslPath,
            (node: Node) => {

                // look up any xsl:import or xsl:includes and pull those in too!
                var onIncludesPreloaded = () => {
                    console.log(node);
                    var transformer = this.createTransformerFromNode(node, xmlTransformer);
                    onSuccess(transformer);
                };
                this.rewriteIncludes(xslPath, node, {}, onIncludesPreloaded, onFailure);
            }, function (e: any) {
                onFailure(e);
            }
        );
    }

    rewriteIncludes(path:string, node: Node, imported: { [_: string]: boolean }, onRewritten:()=>void, onFailure:(e:any)=>void): void {
        var result;
        var element = <Element>node;
        var importNodes = element.querySelectorAll("import,include");
        if (importNodes.length == 0) {
            onRewritten();
            result = false;
        } else {
            var rewrittenNodes = 0;
            // load imports
            for (var i = 0; i < importNodes.length; i++) {
                var importElement = <Element>importNodes.item(i);
                var href = importElement.getAttribute("href");
                // TODO work out relative path
                var relativePath = DD.Util.appendRelativePath(path, href);
                console.log("importing " + href +" + "+path+" -> "+relativePath);
                if (!imported[relativePath]) {
                    var e = importElement;
                    imported[relativePath] = true;
                    DD.Util.readXML(relativePath, (importedStylesheet: Node) => {
                        this.rewriteIncludes(relativePath, importedStylesheet, imported, function () {
                            // replace the import with this node (minus stylesheet container)
                            for (var j = 0; j < importedStylesheet.firstChild.childNodes.length; j++) {
                                var templateNode = importedStylesheet.firstChild.childNodes.item(j);
                                if (templateNode.nodeName.indexOf("template") >= 0) {
                                    e.parentNode.insertBefore(templateNode, e);
                                }
                            }
                            e.parentNode.removeChild(e);
                            rewrittenNodes++;
                            if (rewrittenNodes == importNodes.length) {
                                if (onRewritten) {
                                    onRewritten();
                                }
                            }
                        }, onFailure);
                    }, onFailure);
                } else {
                    importElement.parentNode.removeChild(importElement);
                }
            }
            result = true;
        }
        return result;
    }

    createTransformerFromNode<T>(xsl: Node, xmlTransformer: IStringTransformer<T>): IParameterizedDOMTransformer<T> {
        var nodeTransformer = new DOMParserDOMTransformer(this._domParser, xmlTransformer);
        var xsltProcessor = new XSLTProcessor();
        xsltProcessor.importStylesheet(xsl);
        return new StandardXSLTDOMTransformer<T>(xsltProcessor, nodeTransformer, this._document);
    }

}

} 

module DD.Util {

export function readXML(path: string, onSuccess: (node: Node) => void, onFailure: (e: any) => void) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        onSuccess(xhr.responseXML);
    };
    xhr.onerror = function (e: ErrorEvent) {
        onFailure(e);
    };
    xhr.open("GET", path, true);
    xhr.send(null);
}

export function appendRelativePath(originalPath: string, relativePath: string, originalPathIsDirectory?: boolean) {
    if (originalPathIsDirectory == null) {
        originalPathIsDirectory = originalPath.charAt(originalPath.length - 1) == '/';
    }
    if (!originalPathIsDirectory) {
        // remove file imediately
        var lastSlash = originalPath.lastIndexOf('/');
        if (lastSlash >= 0) {
            originalPath = originalPath.substring(0, lastSlash + 1);
        } else {
            originalPath = "";
        }
    }
    var slashIndex = relativePath.indexOf('/');
    if (slashIndex >= 0) {
        var relativeDirectory = relativePath.substring(0, slashIndex + 1);
        var relativeRemainder = relativePath.substring(slashIndex + 1);
        if (relativeDirectory == "../") {
            // trim off a directory on the original path
            if (originalPath.charAt(originalPath.length - 1) == '/') {
                originalPath = originalPath.substring(0, originalPath.length - 1);
            }
            var dirIndex = originalPath.lastIndexOf('/');
            if (dirIndex >= 0) {
                originalPath = originalPath.substring(0, dirIndex + 1);
            } else {
                originalPath = "";
            }
        } else {
            // append to the original path
            if (originalPath.charAt(originalPath.length - 1) != '/') {
                originalPath += '/';
            }
            originalPath += relativeDirectory;
        }
        appendRelativePath(originalPath, relativeRemainder, true);
    } else {
        // append and be done
        if (originalPath.charAt(originalPath.length - 1) != '/') {
            originalPath += '/';
        }            
        return originalPath + relativePath;
    }
}

}
查看更多
smile是对你的礼貌
3楼-- · 2019-04-22 21:11

Your problem here is that Google Chrome (=Chromium) does not support xsl:include

The lack of this feature is well noted in the Chromium project as raised in "Issue 8441: XSLTProcessor in JS does not permit xsl:include for http". It seems that the problem is caused by some architectural problem in WebKit (the rendering engine used in Chrome). Since this problem originates to WebKit, the bug is marked as WontFix -- the fix will be provided (hopefully) in the future as the original problem in the WebKit is getting resolved.

I see three possible alternatives of how this problem could be resolved for you:

  1. Wait until WebKit/Chrome gets a patch that fixes this problem (potentially takes a long time...)
  2. Create/find a hack that works around this problem for instance by emulating somehow xsl:include for Chrome/Webkit (potentially requires a lot of work / developing a hack)
  3. Try to find a way writing your software in a way that you don't require this specific XSL feature (alternatively run XSL transformation in server-side)

My recommendation: avoid using xsl:include with xsl:param on client side unless you are willing to give up on cross-browser compatibility

查看更多
我命由我不由天
4楼-- · 2019-04-22 21:11

Old topic I know, but checked back here to see if the issue has been resolved.

I tested again and it has, at least in version 47 of Chrome. At last you can use xsl:include.

查看更多
登录 后发表回答