Кроссбраузерные HTML инклуды \(^_^)/
XSLT*
Пусть у нас есть простенький хтмльчик index1.htm
Как известно, хтмл поддерживает инклуды только через iframe/object, но с ними не очень удобно работать из яваскрипта.
Можно, конечно, прописать в каждую подключаемую страницу скрипт типа такого
Он переносит своё содержимое в родительский документ и удаляет фрейм. Но в случае отключённоо яваскрипта мы получим окошко ифрейма не подстраивающееся под размер содержимого.
В XHTML2 пояилась интересная возможность — аттрибут src можно задавать любому элементу и содержимое документа на который он указывает будет всталено вместо содержимого элемента. Напишем index2.htm
Проверили — не работает. Оживить её можно с помощью яваскрипта, который опять же может быть отключён, но это уже не так фатально — пользователю будет показана ссылка на подключаемый файл.
Но мы поступим круче и обойдёмся без яваскрипта. А поможет нам в этом xsl преобразование, накладывающееся само на себя. Напишем index2.xml, который будет ни чем иным, как index.htm обёрнутым в специальную волшебную обёртку.
Доктайп тут выполняет две функции:
1. он указывает xml-процессору, что аттрибут id в t:stylesheet является идентификатором, что позволяет использовать его при указании xsl-преобразования.
2. Если документ будет отдан как text/html, то браузет всё ж будет рендерить страницу в режиме соответствия стандартам. В t:output мы прописываем доктайп по той же причине, только для случая, когда документ был отдан как xml и xslt преобразовал себя в html.
Первый шаблон матчится на все узлы и рекурсивно их копирует. Второй — матричится на корень и пропускает xslt тэги, сразу переходя к выводу html. Последнее правило просто содержит html с инклудами. Имя его не имеет никакого значения.
Если проверить сейчас это в браузере, то никаких отличий быть не должо. Однако, если добавить ещё один шаблон, то инклуды внезапно заработают.
Примечательно, что инклудить таким образом можно как xml типа index2.xml, так и html типа index1.htm
Напишем index3.xml, который инклудит index2.xml
Для роботов и убогих мобильных браузеров страницы можно просто отдавать как text/html и тогда вместо вставляемого файла будет рисоваться ссылка на него.
Совместимость: ie6+, ff3+, opera10+, webkit?+
<!DOCTYPE html>
<html>
<head>
<title>Xbrowser HTML includes</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>First file</h1>
</body>
</html>Как известно, хтмл поддерживает инклуды только через iframe/object, но с ними не очень удобно работать из яваскрипта.
Можно, конечно, прописать в каждую подключаемую страницу скрипт типа такого
new function(){
var frame= window.frameElement
if( !frame ) return
var parent= frame.parentNode
var body= document.getElementsByTagName( 'body' )[0]
var child;
while( child= body.firstChild ) parent.insertBefore( child, frame )
parent.removeChild( frame )
}Он переносит своё содержимое в родительский документ и удаляет фрейм. Но в случае отключённоо яваскрипта мы получим окошко ифрейма не подстраивающееся под размер содержимого.
В XHTML2 пояилась интересная возможность — аттрибут src можно задавать любому элементу и содержимое документа на который он указывает будет всталено вместо содержимого элемента. Напишем index2.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 2.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml2.dtd">
<html>
<head>
<title>Xbrowser HTML includes</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>Second file</h1>
<div src="index1.xml" srctype="text/xml">
<a href="index1.xml">link 2 first file</a>
</div>
</body>
</html>Проверили — не работает. Оживить её можно с помощью яваскрипта, который опять же может быть отключён, но это уже не так фатально — пользователю будет показана ссылка на подключаемый файл.
Но мы поступим круче и обойдёмся без яваскрипта. А поможет нам в этом xsl преобразование, накладывающееся само на себя. Напишем index2.xml, который будет ни чем иным, как index.htm обёрнутым в специальную волшебную обёртку.
<!DOCTYPE t:stylesheet [ <!ATTLIST t:stylesheet id ID #REQUIRED> ]>
<?xml-stylesheet type="text/xsl" href="#t:stylesheet"?>
<t:stylesheet id="t:stylesheet" version="1.0" xmlns:t="http://www.w3.org/1999/XSL/Transform">
<t:output method="html" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" />
<t:template match=" @* | node() ">
<t:copy>
<t:apply-templates select=" @* | node() " />
</t:copy>
</t:template>
<t:template match=" / ">
<t:apply-templates select=" document( '#t:stylesheet' )//html " />
</t:template>
<t:template name="content">
<html>
<head>
<title>Xbrowser HTML includes</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>Second file</h1>
<div src="index1.htm" srctype="text/xml">
<a href="index1.htm">link 2 first file</a>
</div>
</body>
</html>
</t:template>
</t:stylesheet>Доктайп тут выполняет две функции:
1. он указывает xml-процессору, что аттрибут id в t:stylesheet является идентификатором, что позволяет использовать его при указании xsl-преобразования.
2. Если документ будет отдан как text/html, то браузет всё ж будет рендерить страницу в режиме соответствия стандартам. В t:output мы прописываем доктайп по той же причине, только для случая, когда документ был отдан как xml и xslt преобразовал себя в html.
Первый шаблон матчится на все узлы и рекурсивно их копирует. Второй — матричится на корень и пропускает xslt тэги, сразу переходя к выводу html. Последнее правило просто содержит html с инклудами. Имя его не имеет никакого значения.
Если проверить сейчас это в браузере, то никаких отличий быть не должо. Однако, если добавить ещё один шаблон, то инклуды внезапно заработают.
<t:template match=" *[ @src and contains( @srctype, 'xml' ) ] ">
<t:copy>
<t:apply-templates select=" @* " />
<t:apply-templates select=' document( @src )//html/body/* ' />
</t:copy>
</t:template>Примечательно, что инклудить таким образом можно как xml типа index2.xml, так и html типа index1.htm
Напишем index3.xml, который инклудит index2.xml
<!DOCTYPE t:stylesheet [ <!ATTLIST t:stylesheet id ID #REQUIRED> ]>
<?xml-stylesheet type="text/xsl" href="#t:stylesheet"?>
<t:stylesheet id="t:stylesheet" version="1.0" xmlns:t="http://www.w3.org/1999/XSL/Transform">
<t:output doctype-public="-//W3C//DTD XHTML 2.0//EN" doctype-system="http://www.w3.org/MarkUp/DTD/xhtml2.dtd" />
<t:template match=" @* | node() ">
<t:copy>
<t:apply-templates select=" @* | node() " />
</t:copy>
</t:template>
<t:template match=" *[ @src and contains( @srctype, 'xml' ) ] ">
<t:copy>
<t:apply-templates select=" @* " />
<t:apply-templates select=' document( @src )//html/body/* ' />
</t:copy>
</t:template>
<t:template match=" / ">
<t:apply-templates select=" document( '#t:stylesheet' )//html " />
</t:template>
<t:template name="content">
<html>
<head>
<title>Xbrowser HTML includes</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>Third file</h1>
<div src="index2.xml" srctype="text/xml">
<a href="index2.xml">link 2 second file</a>
</div>
</body>
</html>
</t:template>
</t:stylesheet>Для роботов и убогих мобильных браузеров страницы можно просто отдавать как text/html и тогда вместо вставляемого файла будет рисоваться ссылка на него.
Совместимость: ie6+, ff3+, opera10+, webkit?+

комментарии (132)