В прошлой статье я описал как реализовать инклудинг и кеширование при обработке xsl-темплейтов на стороне клиента. Сегодня я раскажу с помощью каких инструментов можно проводить отладку xslt-преобразований на стороне клиента и о работе конструкции <xsl:value-of select=«xxx» disable-output-escaping=«yes»/> в firefox.
Во время обработки xsl-документов в браузере могут происходить различные ошибки:
1) сетевые ошибки — когда xml или xsl данные не были получены;
2) ошибки обработки шаблонов.
Для контроля сетевых ошибок можно использовать отладочные средства браузеров. Все отладочные средства firebug (firefox), dragonfly (opera) и devtools (chrome) могут показать какие ресурсы были загружены из сети непосредственно ассинхронным запросом. Например, если мы обрабатываем данные in_data.xml с помощью шаблона first.xsl, то загрузку этих данных мы сможем проконтролировать
— раздел «net» в firebug
— раздел «net» в dragonfly
— раздел «resources» в devtools.
Иначе дело обстоит если для успешной обработки нужно подгрузить дополнительный xsl-файл (инклуд). В этом случае firebug (firefox) не покажет, что что-то было загружено.
А интегрированные среды дебагинга dragonfly (opera) и devtools (chrome) покажут какие дополнительные xsl файлы были подгружены.
Если во время обработки шаблона произошла ошибка, то её можно отловить и вывести в удобном для вас виде. Мне удобно во время разработки скидывать такие сообщения в консоль firebug'а
В этом случае вывод ошибки будет примерно таким:
Событие «error» будет вызвано в случае возникновения ошибки. В функцию события будет передано несколько параметров, основной из которых — error — собстенно описание ошибки.
В некоторых случаях в xml-данных могут приходить целые куски отформатированного html, в этих случаях эти куски нужно вставлять в конечный документ без изменений, то есть «как есть». Например это могут быть данные, содержащие результаты поиска, в которых искомое слово выделенно жирным («мы <b>искали</b> все возможные решения»). Сделать простую замену текста средствами xslt можно, но того не стоит (попробуйте как-нибудь на досуге заняться этим). Поэтому проще передавать уже отформатированный текст. Опытный программист придумает ещё массу примеров. Для вставки данных без экранирования в xslt есть специальный атрибут disable-output-escaping, который необходимо установить в «yes». Выглядит это так
Но в firefox, начиная самой первой версией и заканчивая всей третьей веткой (в firefox 4 не тестировал), не полная реализация xsl-процессора. Их xsl-процессор, который индентифицирует себя как «Transformiix», не обрабатывает disable-output-escaping=«yes». Этой ошибке уже много лет https://bugzilla.mozilla.org/show_bug.cgi?id=98168 и недавно мы «отмечали» 9-летие этой баги. Там же по ссылке написаны оправдания команды firefox, которые можно свести к одному — там много работы, если хотите правьте сами.
Существует такое решение проблемы — использовать вместо конструкции <xsl:value-of select=«xxx» disable-output-escaping=«yes»/> вызов <xsl:copy-of select=«xxx»/>. Но в этом случае мы не можем передать в узле xxx данные в виде
а придётся передавать данные так
то есть это будет уже не совсем верный xml-файл. И тогда мы получаем проблему в остальных браузерах, где такое решение работать уже не будет.
Я решил использовать другой подход. Использовать специальный фикс, написанный на javascript.
1. Вместо привычного
Где темплейт inc_disable_output_escaping выглядит так:
В этом темплейте по имени xsl-процессора (xsl:vendor) мы выведем данные стандартной конструкцией с disable-output-escaping=«yes», а в случае xsl-процессора от firefox'а данные вставим в невидимый контейнер так, как firefox эти данные может вставить, то есть в экранированном виде.
А потом, после успешного преобразования, и обновления DOM документа, мы перекодируем данные в этих контейнерах на правильные и вставим их на место этих контейнеров.
Для декодирования html-мнемоник используется функция htmlDecode js-библиотеки Encoder.
Пример работы данной техники и архив с решением можно взять тут ra-project.net/xsl_tests/test2.html
PS Не забывайте отправлять правильный content-type для xml/xsl документов. А именно «Content-type: text/xml».
Отладка XSLT на клиенте
Во время обработки xsl-документов в браузере могут происходить различные ошибки:
1) сетевые ошибки — когда xml или xsl данные не были получены;
2) ошибки обработки шаблонов.
Сетевые ошибки
Для контроля сетевых ошибок можно использовать отладочные средства браузеров. Все отладочные средства firebug (firefox), dragonfly (opera) и devtools (chrome) могут показать какие ресурсы были загружены из сети непосредственно ассинхронным запросом. Например, если мы обрабатываем данные in_data.xml с помощью шаблона first.xsl, то загрузку этих данных мы сможем проконтролировать
— раздел «net» в firebug
— раздел «net» в dragonfly
— раздел «resources» в devtools.
Иначе дело обстоит если для успешной обработки нужно подгрузить дополнительный xsl-файл (инклуд). В этом случае firebug (firefox) не покажет, что что-то было загружено.
А интегрированные среды дебагинга dragonfly (opera) и devtools (chrome) покажут какие дополнительные xsl файлы были подгружены.
Ошибки обработки шаблонов
Если во время обработки шаблона произошла ошибка, то её можно отловить и вывести в удобном для вас виде. Мне удобно во время разработки скидывать такие сообщения в консоль firebug'а
jQuery('#id_div').transform(
{ xml:'res/1.xml',
xsl:'res/1.xsl',
success:function (){
jQuery('#id_info').html('готово');
},
error:function (xml_data, xsl_data, success, cur_obj, error){
console.log('xml: '+xml_data);
console.log('xsl: '+xsl_data);
console.log('success: '+success);
console.log('cur_obj:');console.log(cur_obj);
console.log('error:');console.log(error);
}
});
* This source code was highlighted with Source Code Highlighter.
В этом случае вывод ошибки будет примерно таким:
Событие «error» будет вызвано в случае возникновения ошибки. В функцию события будет передано несколько параметров, основной из которых — error — собстенно описание ошибки.
disable-output-escaping=«yes» в firefox
Описание проблемы
В некоторых случаях в xml-данных могут приходить целые куски отформатированного html, в этих случаях эти куски нужно вставлять в конечный документ без изменений, то есть «как есть». Например это могут быть данные, содержащие результаты поиска, в которых искомое слово выделенно жирным («мы <b>искали</b> все возможные решения»). Сделать простую замену текста средствами xslt можно, но того не стоит (попробуйте как-нибудь на досуге заняться этим). Поэтому проще передавать уже отформатированный текст. Опытный программист придумает ещё массу примеров. Для вставки данных без экранирования в xslt есть специальный атрибут disable-output-escaping, который необходимо установить в «yes». Выглядит это так
<xsl:value-of select="xxx" disable-output-escaping="yes"/>
* This source code was highlighted with Source Code Highlighter.
Но в firefox, начиная самой первой версией и заканчивая всей третьей веткой (в firefox 4 не тестировал), не полная реализация xsl-процессора. Их xsl-процессор, который индентифицирует себя как «Transformiix», не обрабатывает disable-output-escaping=«yes». Этой ошибке уже много лет https://bugzilla.mozilla.org/show_bug.cgi?id=98168 и недавно мы «отмечали» 9-летие этой баги. Там же по ссылке написаны оправдания команды firefox, которые можно свести к одному — там много работы, если хотите правьте сами.
Решение проблемы
Существует такое решение проблемы — использовать вместо конструкции <xsl:value-of select=«xxx» disable-output-escaping=«yes»/> вызов <xsl:copy-of select=«xxx»/>. Но в этом случае мы не можем передать в узле xxx данные в виде
<xxx>Резельтат поиска <![CDATA[<i>"первый"</i>]]></xxx>
* This source code was highlighted with Source Code Highlighter.
а придётся передавать данные так
<xxx>Резельтат поиска <i>"первый"</i></xxx>
* This source code was highlighted with Source Code Highlighter.
то есть это будет уже не совсем верный xml-файл. И тогда мы получаем проблему в остальных браузерах, где такое решение работать уже не будет.
Другое решение проблемы
Я решил использовать другой подход. Использовать специальный фикс, написанный на javascript.
1. Вместо привычного
<xsl:value-of select="xxx" disable-output-escaping="yes"/>
в наших шаблонах придётся использовать вызов <xsl:call-template name="inc_disable_output_escaping"><xsl:with-param name="param" select="xxx"/></xsl:call-template>
* This source code was highlighted with Source Code Highlighter.
Где темплейт inc_disable_output_escaping выглядит так:
<xsl:template name="inc_disable_output_escaping">
<xsl:param name="param"></xsl:param>
<xsl:choose>
<xsl:when test="system-property('xsl:vendor')='Transformiix'">
<!-- костыль для firefox -->
<div style="display:none" class="fix_ff_disable_output_escaping"><xsl:value-of select="$param" disable-output-escaping="yes"/></div>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$param" disable-output-escaping="yes"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
* This source code was highlighted with Source Code Highlighter.
В этом темплейте по имени xsl-процессора (xsl:vendor) мы выведем данные стандартной конструкцией с disable-output-escaping=«yes», а в случае xsl-процессора от firefox'а данные вставим в невидимый контейнер так, как firefox эти данные может вставить, то есть в экранированном виде.
А потом, после успешного преобразования, и обновления DOM документа, мы перекодируем данные в этих контейнерах на правильные и вставим их на место этих контейнеров.
function fix_ff_disable_output_escaping() {
jQuery('div.fix_ff_disable_output_escaping').each(
function(i, obj){
var j_obj=jQuery(obj);
j_obj.replaceWith(Encoder.htmlDecode(j_obj.html()));
}
)
}
* This source code was highlighted with Source Code Highlighter.
Для декодирования html-мнемоник используется функция htmlDecode js-библиотеки Encoder.
Пример работы данной техники и архив с решением можно взять тут ra-project.net/xsl_tests/test2.html
PS Не забывайте отправлять правильный content-type для xml/xsl документов. А именно «Content-type: text/xml».