Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > JavaScript: Общие вопросы > XSLT Трансформация


Автор: t77 14.7.2010, 18:48
Доброе время суток.
Необходимо сделать трансформацию в ЙС следующим путем:
1. Загрузить ХМЛ документ
2. Загрузить ХСЛ документ
3. Сделать трансформацию
4. Закинуть результат в элемент DIV.

Дело в том, что код для IE работает, а для Firefox-а нет! smile 
Поэтому привожу вашему вниманию код для Firefox-а:
Код

//stepObj       is DOM Object that contain xml data.
    xslLocation = "http://server:12005/APP";   
    function XSLTTransformation(stepObj)
    {
        // only for FIREFOX
        if (document.implementation.createDocument)
        {
            //create xmlDOM
            var xmldoc = document.implementation.createDocument("", "", null);                
            xmldoc = stepObj.ownerDocument;
            
            //xsl name
            var xslName = xslLocation + "myXSLFile.xsl";
            
            // load the xslt file, myXSLFile.xsl
            var myXMLHTTPRequest = new XMLHttpRequest(); 
            myXMLHTTPRequest.open("GET", xslName, false);
            myXMLHTTPRequest.send(null);
            var xslStylesheet = myXMLHTTPRequest.responseXML;
                            
            //Create the XSLT processor
            var xsltProcessor = new XSLTProcessor(); 
            xsltProcessor.importStylesheet(xslStylesheet);
            
            //Set the parameters
            xsltProcessor.setParameter("urlLocation", urlLocation, "");
            xsltProcessor.setParameter("sysDirection", "left", "");           
            xsltProcessor.setParameter("stepObj", stepObj, "");
                                                        
            var tempDiv = document.createElement("DIV");

            // transformation...            
            tempDiv.innerHTML = xsltProcessor.transformToFragment(xmldoc, document);
                                     
        }
    }
 
Мозила ругается на строку 33
Почему не получается сделать трансформацию?
Что я делаю не так?
Пожалуйста помогите!

Автор: Amphiluke 14.7.2010, 19:11
Код

 tempDiv.appendChild(xsltProcessor.transformToFragment(xmldoc, document));


??

Автор: t77 14.7.2010, 22:47
Amphiluke, я проделал следующую вещь:
Код

var test = xsltProcessor.transformToFragment(xmldoc, document);
tempDiv.innerHTML = test;


уже в первой строке вылетает и ругается срашным матом. smile 

Автор: Amphiluke 14.7.2010, 23:20
Нет возможности проверить, что там за ругань, но на первый взгляд хз, где спрятался баг. Вы смотрели консоль? Али там невнятно написано (что, правда мат?  smile )

Только все же почему вы присваиваете результат, возвращаемый методом transformToFragment свойству innerHTML? Это же, вообще говоря, разные вещи. innerHTML имеет строковый тип, а transformToFragment возвращает объект DocumentFragment. Поэтому нужно (вроде как) пользоваться методами типа appendChild, а не пихать результат в innerHTML. Впрочем, проверьте, я могу ошибаться.

Добавлено через 11 минут и 20 секунд
И еще немного неясен смысл этих манипуляций:
Цитата(t77 @  14.7.2010,  22:48 Найти цитируемый пост)

Код

var xmldoc = document.implementation.createDocument("", "", null);
xmldoc = stepObj.ownerDocument;

создали XML-документ и тут же забыли про него, перезаписав переменную. Зачем создавали?

Автор: t77 14.7.2010, 23:57
Цитата

Только все же почему вы присваиваете результат, возвращаемый методом transformToFragment свойству innerHTML? Это же, вообще говоря, разные вещи.

Ну вообщето мне необходимо результат трансформации закинуть в мой Div.
Дело в том, что именно так делается для браузера Internet Explorer. Представте себе там это работает!

Цитата

И еще немного неясен смысл этих манипуляций:

Цитата(t77 @  14.7.2010,  22:48 ) 

код Javascript 
1:
2:

 var xmldoc = document.implementation.createDocument("", "", null);
xmldoc = stepObj.ownerDocument;

создали XML-документ и тут же забыли про него, перезаписав переменную. Зачем создавали? 


Объект - stepObj я получаю как параметр из функции- XSLTTransformation.
А про него не забыли! Как раз в той строке, где  пытаюсь сделать трансформацию, именно этот объект я передаю.


Автор: sir_nuf_nuf 15.7.2010, 09:38
В свое время испытал много проблем с XSLT в браузерах.. Кривая это технология.
Что бы хоть как - то уменьшить проблем с переносимостью, советую использовать какую-либо JS обертку, например http://dev.abiss.gr/sarissa/

Автор: Amphiluke 15.7.2010, 09:48
Цитата(t77 @  15.7.2010,  03:57 Найти цитируемый пост)
Дело в том, что именно так делается для браузера Internet Explorer. Представте себе там это работает!

В первом посте вы сами заявили: говорим о FF.
Сейчас проверил еще раз: да, здесь нельзя использовать innerHTML, как в IE, а нужно добавлять содержимое методами insertBefore, appendChild или подобными. Если вы присвоете результат, возвращенный методом transformToFragment, свойству innerHTML, то и получите в своем div'е одну строку: [object DocumentFragment].


Цитата(t77 @  15.7.2010,  03:57 Найти цитируемый пост)
А про него не забыли! Как раз в той строке, где  пытаюсь сделать трансформацию, именно этот объект я передаю.

Ну да, как же. Я говорю, что бессмысленно было писать эту строку:

Цитата(t77 @  14.7.2010,  22:48 Найти цитируемый пост)
Код

var xmldoc = document.implementation.createDocument("", "", null);

если в следующей строке вы просто-напросто перезаписываете заново переменную xmldoc, забывая результат, возвращенный методом createDocument.

Автор: t77 15.7.2010, 11:11
Мозги закипают  smile  smile  smile 
Привожу вашему вниманию два варианта одного и того же кода. Первый для ИЕ а второй для Firefox. Где первый вариант работает а второй вариант, тот, что для Firefox-а нет! 
Код

//stepObj       is DOM Object that contain xml data.
    xslLocation = "http://server:12005/APP/";   
    
    function XSLTTransformation(stepObj)
    {
        // code for IE
        if(window.ActiveXObject)
        {
            //create xmlDOM
            xmldoc = new ActiveXObject("Microsoft.XMLDOM");
            xmldoc.async = false;
            xmldoc.loadXML(stepObj.xml);
                     
            var xslt = new ActiveXObject("Msxml2.XSLTemplate.3.0");
         
            // load the xsl
            var xslObj = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.3.0");
            xslObj.async = false;        
            var xslName = "myXSLFile.xsl";
            xslObj.load(xslLocation + xslName);

            xslt.stylesheet = xslObj;
         
            //Create the XSLT processor
            xslProc = xslt.createProcessor();
            
            //Set the parameters
            xslProc.addParameter("urlLocation", urlLocation);
            xslProc.addParameter("sysDirection", "left");
            xslProc.addParameter("stepObj", stepObj);            
          
            xslProc.input = xmldoc;

            // transformation...  
            xslProc.transform();

            var tempDiv = document.createElement("DIV");
            tempDiv.innerHTML = xslProc.output;
            var createdDiv = tempDiv.getElementsByTagName("DIV")[0];
        }
    
        // code for FIREFOX
        else if (document.implementation.createDocument)
        {
            //create xmlDOM
            var xmldoc = document.implementation.createDocument("", "", null);                
            xmldoc = stepObj.ownerDocument;
            
            //xsl name
            var xslName = xslLocation + "myXSLFile.xsl";
            
            // load the xslt file, myXSLFile.xsl
            var myXMLHTTPRequest = new XMLHttpRequest(); 
            myXMLHTTPRequest.open("GET", xslName, false);
            myXMLHTTPRequest.send(null);
            var xslStylesheet = myXMLHTTPRequest.responseXML;
                            
            //Create the XSLT processor
            var xsltProcessor = new XSLTProcessor(); 
            xsltProcessor.importStylesheet(xslStylesheet);
            
            //Set the parameters
            xsltProcessor.setParameter("urlLocation", urlLocation, "");
            xsltProcessor.setParameter("sysDirection", "left", "");           
            xsltProcessor.setParameter("stepObj", stepObj, "");
                                                        
            var tempDiv = document.createElement("DIV");

            // transformation...            
            tempDiv.innerHTML = xsltProcessor.transformToFragment(xmldoc, document);
                                     
        }
        
        return createdDiv;        
    }

Помогите мне пожалуйста сделать то же самое, чтобы работало и в Firefox.
Не хочет работать!
Как мне это сделать ?

Автор: Amphiluke 15.7.2010, 12:27
Блин.  smile  smile 
Вот пример, адаптированный из учебника для вашего кода. Я так и не добился от вас, что за ошибка вызывает «страшный мат» у FF. Поэтому проверьте просто, будет ли работать у вас хотя бы это. У меня работает! Если у вас — нет, то хз.

myXSLFile.xsl
Код

<?xml version="1.0"?><!-- это XML-документ -->
<!-- объявить пространство имен xsl, чтобы отличать xsl-теги от html-тегов -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<!-- Когда будет найден корневой элемент, вывести каркас HTML-таблицы -->
<xsl:template match="/">
<table>
<tr><th>Имя</th><th>Электронная почта</th></tr>
<xsl:apply-templates/> <!-- и рекурсия по другим шаблонам -->
</table>
</xsl:template>
<!-- Когда встретится элемент <contact>... -->
<xsl:template match="contact">
<tr> <!-- Начать новую строку таблицы -->
<!-- Использовать атрибут name тега contact как первый столбец -->
<td><xsl:value-of select="@name"/></td>
<xsl:apply-templates/> <!-- и рекурсия по другим шаблонам -->
</tr>
</xsl:template>
<!--
Когда встретится элемент <email>, вывести его содержимое в другую ячейку
-->
<xsl:template match="email">
<td><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>


myXMLFile.xml
Код

<?xml version="1.0" encoding="utf-8"?>
<contacts>
<contact name="Able Baker"><email>able@example.com</email></contact>
<contact name="Careful Dodger"><email>dodger@example.com</email></contact>
<contact name="Eager Framer" personal="true">
<email>framer@example.com</email></contact>
</contacts>


Главная (оставил только код для FF, раз с IE проблем нет)
Код

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript">
//stepObj       is DOM Object that contain xml data.
   xslLocation = ""; urlLocation = "";
    
    function XSLTTransformation(stepObj)
    {
        if (document.implementation.createDocument)
        {
            //create xmlDOM
            var myXMLHTTPRequest = new XMLHttpRequest(); 
            myXMLHTTPRequest.open("GET", "myXMLFile.xml", false);
            myXMLHTTPRequest.send(null);
            xmldoc = myXMLHTTPRequest.responseXML;
            
            //xsl name
            var xslName = xslLocation + "myXSLFile.xsl";
            
            // load the xslt file, myXSLFile.xsl
            myXMLHTTPRequest = new XMLHttpRequest(); 
            myXMLHTTPRequest.open("GET", xslName, false);
            myXMLHTTPRequest.send(null);
            var xslStylesheet = myXMLHTTPRequest.responseXML;

                            
            //Create the XSLT processor
            var xsltProcessor = new XSLTProcessor(); 
            xsltProcessor.importStylesheet(xslStylesheet);
            //Set the parameters
            xsltProcessor.setParameter("urlLocation", urlLocation, "");
            xsltProcessor.setParameter("sysDirection", "left", "");           
            xsltProcessor.setParameter("stepObj", stepObj, "");
                                                        
            var tempDiv = document.createElement("DIV");

            // transformation...            
            tempDiv.appendChild(xsltProcessor.transformToFragment(xmldoc, document));
                                     
        }
    return tempDiv;
    }
</script>
</head>

<body>
    <p><a href="#" onclick="document.body.appendChild(XSLTTransformation());">XSLTTransformation</a></p>
</body>
</html>

Автор: t77 15.7.2010, 15:02
ваш код у меня работает с условием, что xml файл находится в отдельном файле. Тоесть создав три файла как вы здесь показываете все работает!!!

Но у меня в коде, в аппликации, где я получаю xml документ из объекта xslObj, не работает!
Может я неправильно считываю xml из объекта??
Скажите пожалуйста как заменить строки:

Код

 function XSLTTransformation(stepObj)
{
xmldoc = new ActiveXObject("Microsoft.XMLDOM");
xmldoc.async = false;
xmldoc.loadXML(stepObj.xml);
....
....
....
}

для браузера Firefox ??

P.S.
Даже не знаю, что и думать...
А может быть, что для Файрфокса имеется другой синтакс ХСЛ ??  smile

Добавлено через 10 минут и 57 секунд
Что же касается ошибки, которую я получаю при трансформации:
Код

[Exception... "Component returned failure code: 0x80600008 [nsIXSLTProcessor.transformToFragment]"  nsresult: "0x80600008 (<unknown>)"  location: "JS frame :: http://localhost/doc/Scenario/viewRectangles.js :: createStepDiv :: line 208"  data: no]

Автор: Amphiluke 15.7.2010, 17:05
Цитата(t77 @  15.7.2010,  19:02 Найти цитируемый пост)
Скажите пожалуйста как заменить строки:

Ну вы же сами, вроде, где-то в каких-то темах недавних уже писали это.
Код

var xmldoc = (new DOMParser()).parseFromString((new XMLSerializer()).serializeToString(stepObj), "application/xml");




Цитата(t77 @  15.7.2010,  19:02 Найти цитируемый пост)
Но у меня в коде, в аппликации, где я получаю xml документ из объекта xslObj, не работает!

Что-то вот этого я не понял. Какие-то слова незнакомые. smile  У вас XML-документ встроен в HTML-страницу с помощью тега <xml>? А объект stepObj это он и есть?
Так что-ль?
Код

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript">
//stepObj       is DOM Object that contain xml data.
   xslLocation = ""; urlLocation = "";
    
    function XSLTTransformation(stepObj)
    {
        if (document.implementation.createDocument)
        {
            //create xmlDOM
            var docElem = stepObj.firstChild;
            while (docElem) {
                if (docElem.nodeType == 1) break;
                docElem = docElem.nextSibling;
            }
            var xmldoc = document.implementation.createDocument("", "", null);
            if (docElem) xmldoc.appendChild(xmldoc.importNode(docElem, true));
            
            //xsl name
            var xslName = xslLocation + "myXSLFile.xsl";
            
            // load the xslt file, myXSLFile.xsl
            myXMLHTTPRequest = new XMLHttpRequest(); 
            myXMLHTTPRequest.open("GET", xslName, false);
            myXMLHTTPRequest.send(null);
            var xslStylesheet = myXMLHTTPRequest.responseXML;

                            
            //Create the XSLT processor
            var xsltProcessor = new XSLTProcessor(); 
            xsltProcessor.importStylesheet(xslStylesheet);
            //Set the parameters
            xsltProcessor.setParameter("urlLocation", urlLocation, "");
            xsltProcessor.setParameter("sysDirection", "left", "");           
            xsltProcessor.setParameter("stepObj", stepObj, "");
                                                        
            var tempDiv = document.createElement("DIV");

            // transformation...            
            tempDiv.appendChild(xsltProcessor.transformToFragment(xmldoc, document));
                                     
        }
    return tempDiv;
    }
</script>
</head>

<body>
    <p><a href="#" onclick="document.body.appendChild(XSLTTransformation(document.getElementById('x')));">XSLTTransformation</a></p>
    <xml style="display:none;" id="x">
        <contacts>
            <contact name="Able Baker"><email>able@example.com</email></contact>
            <contact name="Careful Dodger"><email>dodger@example.com</email></contact>
            <contact name="Eager Framer" personal="true">
            <email>framer@example.com</email></contact>
        </contacts>
    </xml>
</body>
</html>

Автор: t77 15.7.2010, 19:04

Цитата

Что-то вот этого я не понял. Какие-то слова незнакомые.   У вас XML-документ встроен в HTML-страницу с помощью тега <xml>? А объект stepObj это он и есть?


Нет, нет, никакого встроеного в HTML-страницу xml-а нет.
Объект stepObj.xml ,является XML документом, с помощью которго проделывается трансформация.

Цитата

Так что-ль?

Нет, не работает все равно.  smile 
Получаю то же самое исключение, что и раньше
Код

[Exception... "Component returned failure code: 0x80600008 [nsIXSLTProcessor.transformToFragment]"  nsresult: "0x80600008 (<unknown>)"  location: "JS frame :: http://localhost/doc/Scenario/viewRectangles.js :: createStepDiv :: line 208"  data: no]

Автор: Amphiluke 15.7.2010, 19:12
Цитата(t77 @  15.7.2010,  23:04 Найти цитируемый пост)
Объект stepObj.xml ,является XML документом, с помощью которго проделывается трансформация.

А откуда он берется?

Добавлено через 1 минуту и 5 секунд
Вот я вижу, он приходит как параметр ф-ции XSLTTransformation. А откуда и как — не ясно.

Автор: t77 15.7.2010, 19:31
Цитата

Вот я вижу, он приходит как параметр ф-ции XSLTTransformation. А откуда и как — не ясно. 

Amphiluke, да действительно он передается функции XSLTTransformation как параметр.
Данную функцию заряжает объектом stepObj, другая функция и так далее.
Тот же объект как вы видите из вышеприведенного мною примера используется в коде для IE. 
И без каких либо проблем проделовается трансформация и все красиво работает. Исходя из этого не думаю, что проблема в данном объекте. 
Проверяю содержание объекта в обоих случаях, и при запуске кода в ИЕ и при запуске ФФ. Содержание и структура объекта stepObj идентичны.
 smile 

Автор: Amphiluke 15.7.2010, 19:44
t77, если не сложно, выполните, please, перед вызовом метода transformToFragment этот alert:

Код

alert(xmldoc);


и покажите здесь, что написалось.

Автор: t77 15.7.2010, 20:26
Код

[object XMLDocument]


Добавлено через 3 минуты и 58 секунд
а вот что получаем в Internet Explorer:
Код

[object]

Автор: Amphiluke 15.7.2010, 20:35
Ясно. Стало быть, ваш объект stepObj не документ XML, а какая-то его нода?

Меня просто заинтересовала эта строчка:
Цитата(t77 @  15.7.2010,  15:11 Найти цитируемый пост)
Код

xmldoc = stepObj.ownerDocument;

и ее сакраментальный смысл. smile

Автор: t77 15.7.2010, 20:38
Amphiluke,
ну..., и что это значит ? smile 

Автор: Amphiluke 15.7.2010, 20:44
Ничего. smile 

Я по вашим словам сначала понял, что stepObj — это непосредственно сам документ XML. Однако свойство ownerDocument таких объектов (Document) равно null. Если бы это было так, то происхождение ошибки при вызове transformToFragment сразу стало бы очевидным. А так... все в порядке. smile

Автор: t77 15.7.2010, 21:13
У меня такое ощущение, что где то я запорол в синтаксисе а где не могу понять.
Исходя из того, что код для IE работает, думаю по строчке разобрать его и перенести его в код для FF.
Первый этап это загрузка xml в объект
код для IE:
Код

xmldoc = new ActiveXObject("Microsoft.XMLDOM");
xmldoc.async = false;
xmldoc.loadXML(stepObj.xml);

код для FF:
Код

var docElem = stepObj.firstChild;
        
        while(docElem) 
        {
            if (docElem.nodeType == 1) 
                break;
                
            docElem = docElem.nextSibling;
        }
        
        var xmldoc = document.implementation.createDocument("", "", null);
        
        if (docElem) 
            xmldoc.appendChild(xmldoc.importNode(docElem, true));

Второй этап создание объекта xsl и загрузка xsl
код для IE:
Код

var xslt = new ActiveXObject("Msxml2.XSLTemplate.3.0");
        
        // load the xsl
        var xslObj = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.3.0");
        xslObj.async = false;        
        var xslName = "clientXSL.xsl";
        xslObj.load(xslLocation + xslName);

        xslt.stylesheet = xslObj;

код для FF:
Код

//xsl name
        var xslName = xslLocation +"clientXSL.xsl";        
        // load the xslt file
        var myXMLHTTPRequest = new XMLHttpRequest(); 
        myXMLHTTPRequest.open("GET", xslName, false);
        myXMLHTTPRequest.send(null);
        var xslStylesheet = myXMLHTTPRequest.responseXML;
                        
        //Create the XSLT processor
        var xsltProcessor = new XSLTProcessor(); 
        xsltProcessor.importStylesheet(xslStylesheet);

Третий этап добавляем параметры и трансформация
код для IE:
Код

xslProc = xslt.createProcessor();
xslProc.addParameter("urlLocation", urlLocation);
xslProc.addParameter("sysDirection", "left");
xslProc.input = xmldoc;
        
xslProc.transform();
var tempDiv = document.createElement("DIV");
tempDiv.innerHTML = xslProc.output;

код для FF:
Код

xsltProcessor.setParameter("urlLocation", urlLocation, "");
xsltProcessor.setParameter("sysDirection", "left", "");

var tempDiv = document.createElement("DIV");
tempDiv.appendChild(xsltProcessor.transformToFragment(xmldoc, document));

Что то мне не очень нравятся первые два этапа... Посмотрите пожалуйста, все ли сделано правильно для FF. 
Имеются ли альтернативные методы для реализации первых двух этапов??

Автор: Amphiluke 15.7.2010, 21:35
t77, что-то вы меня запутали. Какой код вы реально используете для создания xmldoc? Тот, который вы привели сейчас, я написал в предположении внедренного ХML. Вы сказали, что это не так, поэтому использовать этот код надо с осторожностью. Вы рискуете потерять documentElement. Ведь у вас изначально был код 
Код

xmldoc = stepObj.ownerDocument;

Сейчас вы его выбросили?


По поводу этапов два и три, уже проверял. У меня работает нормально. smile

Автор: t77 15.7.2010, 23:20
Я сам немного запутался smile 
Вы правы изначально я использовал в первом этапе код:
Код

xmldoc = stepObj.ownerDocument;


Затем, после разных попыток оставил, предложенный вами вариант:
Код

var docElem = stepObj.firstChild;
        
        while(docElem) 
        {
            if (docElem.nodeType == 1) 
                break;
                
            docElem = docElem.nextSibling;
        }
        
        var xmldoc = document.implementation.createDocument("", "", null);
        
        if (docElem) 
            xmldoc.appendChild(xmldoc.importNode(docElem, true));



Как вы думаете, что правильней использовать и почему?
И еще, скажите пожалуйста вас не смущает во втором и третьем этапах создание и загрузка xsltProcessor-а ?
Как видно из примеров для кода IE сначала загружается xsl и лишь на третьем этапе создается xsltProcessor, для добавления параметров.
А для кода FF, немного другая последовательность действий.
Как вы думаете, может проблема именно в этом ??

Автор: t77 19.7.2010, 22:46
Проблема решена!  smile 
Тема закрыта.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)