Chrome i Safari XSLT za pomocą JavaScript

Mam następujący kod, który stosuje styl XSLT

Test.Xml.xslTransform = function(xml, xsl) {
    try {
        // code for IE
        if (window.ActiveXObject) {
            ex = xml.transformNode(xsl);
            return ex;
        }
        // code for Mozilla, Firefox, Opera, etc.
        else if (document.implementation && document.implementation.createDocument) {
            xsltProcessor = new XSLTProcessor();
            xsltProcessor.importStylesheet(xsl);
            resultDocument = xsltProcessor.transformToFragment(xml, document);
            return resultDocument;
        }
    } catch (exception) {
        if (typeof (exception) == "object") {
            if (exception.message) {
                alert(exception.message);
            }
        } else {
            alert(exception);
        }
    }

Kod działa w IE i Firefoksie, ale nie w Chrome i Safari. Jakieś pomysły dlaczego?

Update

ResultDocument = xsltProcessor.transformToFragment(xml, document);

Powyższa linia zwraca null. Żaden błąd nie jest wyrzucany.

Update

Kod nie działa, ponieważ plik XSLT zawiera xsl: include. Trzeba znaleźć sposób, aby włączyć działa będę wklej postęp tutaj

Update

Zalecono, że używam http://plugins.jquery.com/project/Transform / plugin. Staram się wykorzystać libary po stronie klienta jako przykład prac include ( http://daersystems.com/jquery/transform/).

Kod działa w IE, ale nadal nie w chrome.

Test.Xml.xslTransform = function(xml, xsl) {
        try {
                $("body").append("<div id='test' style='display:none;'></div>");
                var a = $("#test").transform({ xmlobj: xml, xslobj: xsl });
                return a.html();
        }
        catch (exception) {
            if (typeof (exception) == "object") {
                if (exception.message) {
                    alert(exception.message);
                }
            } else {
                alert(exception);
            }

        }
    }

Xml i xsl są obiektami przekazywanymi.

Update

Próbowałem zmienić plik XSL na coś bardzo proste bez include I Chrome nadal nie stosuje arkusza stylów i IE jest. XSL, który jest wprowadzany jako obiekt to:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:rs="urn:schemas-microsoft-com:rowset"
    xmlns:z="#RowsetSchema"
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:spsoap="http://schemas.microsoft.com/sharepoint/soap/"
    >
    <xsl:output method="html"/>
    <xsl:template match="/">
        <h1>test</h1>
    </xsl:template>

</xsl:stylesheet>

Update

Pożądany efekt końcowy to zastosowanie XSL do pliku xml. Plik xsl zawiera w sobie includes. Chcę, aby trasnfer miał miejsce na kliencie.

Aktualizacja Rupert mógłbyś zaktualizować pytanie za pomocą xml i jak nazywasz Test.Xml.xslTransform ?

I Pobierz xml używając ie8

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><SearchListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/"><SearchListItemsResult><listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
                    <rs:data ItemCount="1">
                        <z:row ows_Title="Test" ows_FirstName="Test 4" ows_UniqueId="74;#{1A16CF3E-524D-4DEF-BE36-68A964CC24DF}" ows_FSObjType="74;#0" ows_MetaInfo="74;#" ows_ID="74" ows_owshiddenversion="10" ows_Created="2009-12-29 12:21:01" ows_FileRef="74;#Lists/My List Name/74_.000" ReadOnly="False" VerificationRequired="0"/>
                    </rs:data>
                </listitems></SearchListItemsResult></SearchListItemsResponse></soap:Body></soap:Envelope>

Kod jest wywoływany w następujący sposób:

xsl = Test.Xml.loadXMLDoc("/_layouts/xsl/xsl.xslt");
var doc = Test.Xml.xslTransform(xData.responseXML, xsl);

XData to xml zwracany przez usługę internetową.

Author: Rupert, 2010-01-11

2 answers

Jeśli twój XSLT używa xsl:include możesz otrzymać dziwne niewytłumaczalne błędy, ale zawsze z tym samym rezultatem końcowym: twoja transformacja zawodzi.

Zobacz ten raport o błędzie chromium i wesprzyj go! http://code.google.com/p/chromium/issues/detail?id=8441

Błąd jest rzeczywiście w webkit choć. Aby uzyskać więcej informacji Oto kolejny link, który idzie bardziej szczegółowo, dlaczego to nie działa.

Jedynym sposobem obejścia tego problemu jest wstępne przetworzenie arkusza stylów tak, że wstrzykuje dołączone arkusze stylów. Czyli to, co biblioteka XSLT crossbrowser jak Sarissa zrobi dla ciebie automatycznie.

Jeśli szukasz rozwiązania jQuery:
http://plugins.jquery.com/project/Transform/ jest wtyczką cross browser xsl. Z powodzeniem wykorzystałem to, aby pracować w przeszłości bez większych kłopotów. Nie musisz przepisywać swojego xsl ta wtyczka wstępnie przetworzy je za Ciebie. Zdecydowanie warto się przyjrzeć, ponieważ jest bardziej lekki niż Sarissa.

UPDATE:

<html>
<head>
<script language="javascript" src="jquery-1.3.2.min.js"></script> 
<script language="javascript" src="jquery.transform.js"></script>  
<script type="text/javascript">
function loadXML(file)
{
    var xmlDoc = null;
    try //Internet Explorer
    {
        xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async=false;
        xmlDoc.load(file);
    }
    catch(e)
    {
        try //Firefox, Mozilla, Opera, etc.
        {
            xmlDoc=document.implementation.createDocument("","",null);
            xmlDoc.async=false;
            xmlDoc.load(file);
        }
        catch(e)
        {
            try //Google Chrome
            {
                var xmlhttp = new window.XMLHttpRequest();
                xmlhttp.open("GET",file,false);
                xmlhttp.send(null);
                xmlDoc = xmlhttp.responseXML.documentElement;
            }
            catch(e)
            {
            error=e.message;
            }
        }
    }
    return xmlDoc;
}
function xslTransform(xmlObject, xslObject)
{
    try 
    {
        $("body").append("<div id='test'></div>");
        var a = $("#test").transform({ xmlobj: xmlObject, xslobj: xslObject });
    }
    catch (exception) 
    {
        if (typeof (exception) == "object" && exception.message) 
            alert(exception.message);
        else alert(exception);
    }
}
var xmlObject = loadXML("input.xml");
var xslObject = loadXML("transform.xsl");
$(document).ready(function()  
{
    xslTransform(xmlObject, xslObject);
});
</script>
</head>
<body>

</body>
</html>

Ta testowa strona html działa zarówno w Chrome / FireFox / IE.

Input.xml jest tylko prostym plikiem xml zawierającym <root /> transformacja.xsl to rozebrany xsl, który opublikowałeś.

EDIT

Wydaje się jednak, że $.transform ma problemy z importowaniem arkuszy stylów z dołączonych plików:

Oto Jak to naprawić:

Zlokalizuj

var safariimportincludefix = function(xObj,rootConfig) {

W jquery.transform.js i zastąp całą funkcję to:

var safariimportincludefix = function(xObj,rootConfig) {
    var vals = $.merge($.makeArray(xObj.getElementsByTagName("import")),$.makeArray(xObj.getElementsByTagName("include")));

    for(var x=0;x<vals.length;x++) {
        var node = vals[x];
        $.ajax({
            passData : { node : node, xObj : xObj, rootConfig : rootConfig},
            dataType : "xml",
            async : false,
            url : replaceref(node.getAttribute("href"),rootConfig),
            success : function(xhr) {
                try {
                    var _ = this.passData;
                    xhr = safariimportincludefix(xhr,_.rootConfig);

                    var imports = $.merge(childNodes(xhr.getElementsByTagName("stylesheet")[0],"param"),childNodes(xhr.getElementsByTagName("stylesheet")[0],"template"));
                    var excistingNodes = [];
                    try 
                    {
                        var sheet = _.xObj;
                        var params = childNodes(sheet,"param");
                        var stylesheets = childNodes(sheet,"template");
                        existingNodes = $.merge(params,stylesheets);
                    }
                    catch(exception) 
                    {
                        var x = exception;
                    }
                    var existingNames = [];
                    var existingMatches = [];
                    for(var a=0;a<existingNodes.length;a++) {
                        if(existingNodes[a].getAttribute("name")) {
                            existingNames[existingNodes[a].getAttribute("name")] = true;
                        } else {
                            existingMatches[existingNodes[a].getAttribute("match")] = true;
                        }
                    }

                    var pn = _.node.parentNode;
                    for(var y=0;y<imports.length;y++) {
                        if(!existingNames[imports[y].getAttribute("name")] && !existingMatches[imports[y].getAttribute("match")]) {
                            var clonednode = _.xObj.ownerDocument.importNode(imports[y],true);
                            //pn.insertBefore(clonednode,_.xObj);
                            pn.insertBefore(clonednode,childNodes(_.xObj,"template")[0]);
                        }
                    }
                    pn.removeChild(_.node);
                } catch(ex) { 

                }
            }
        });
    }

    return xObj;
};

Teraz używając wcześniej wklejonego indeksu testu.html użyj tego dla transform.xsl:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >
        <xsl:include href="include.xsl" />
    <xsl:output method="html"/>
    <xsl:template match="/">
            <xsl:call-template name="giveMeAnIncludedHeader" />
    </xsl:template>
</xsl:stylesheet>

I to dla include.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template name="giveMeAnIncludedHeader">
        <h1>Test</h1>
    </xsl:template>
</xsl:stylesheet>

Z wcześniej opublikowaną poprawką w {[8] } to teraz wstawi dołączoną <h1>Test</h1> we wszystkich przeglądarkach.

Możesz zobaczyć go w akcji tutaj: http://www.mpdreamz.nl/xsltest

 14
Author: Martijn Laarman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-20 21:21:31

To nie jest odpowiedź na pierwotne pytanie, ale podczas moich poszukiwań w Internecie szukając przykładowej transformacji xslt, która działa na chrome znalazłem linki do tego wątku wiele razy. Szukałem rozwiązania, które nie używa żadnych open-source lub innych bibliotek / wtyczek i działa dobrze z silverlight.

Problemem chrome i safari jest ograniczenie uniemożliwiające bezpośrednie ładowanie plików xml. Sugerowane obejście w http://www.mindlence.com/WP/?p=308 {[6] } jest załadowanie pliku xml dowolną inną metodą i przekazanie go jako ciąg znaków procesorowi xslt.

Dzięki takiemu podejściu udało mi się wykonać transformacje xsl w javascript i przekazać wynik do aplikacji silverlight poprzez HTML Bridge.

 5
Author: moonlightdock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-23 03:54:44