Pull to refresh

Кроссбраузерные HTML инклуды \(^_^)/

Reading time7 min
Views6.4K
Пусть у нас есть простенький хтмльчик index1.htm

<!DOCTYPE html><br><html><br>    <head><br>        <title>Xbrowser HTML includes</title><br>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><br>    </head><br>    <body><br>        <h1>First file</h1><br>    </body><br></html>

Как известно, хтмл поддерживает инклуды только через iframe/object, но с ними не очень удобно работать из яваскрипта.

Можно, конечно, прописать в каждую подключаемую страницу скрипт типа такого

new function(){<br>    var frame= window.frameElement<br>    if( !frame ) return<br>    var parent= frame.parentNode<br>    var body= document.getElementsByTagName( 'body' )[0]<br>    var child;<br>    while( child= body.firstChild ) parent.insertBefore( child, frame )<br>    parent.removeChild( frame )<br>}

Он переносит своё содержимое в родительский документ и удаляет фрейм. Но в случае отключённоо яваскрипта мы получим окошко ифрейма не подстраивающееся под размер содержимого.

В XHTML2 пояилась интересная возможность — аттрибут src можно задавать любому элементу и содержимое документа на который он указывает будет всталено вместо содержимого элемента. Напишем index2.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 2.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml2.dtd"><br><html><br>    <head><br>        <title>Xbrowser HTML includes</title><br>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><br>    </head><br>    <body><br>        <h1>Second file</h1><br>        <div src="index1.xml" srctype="text/xml"><br>            <a href="index1.xml">link 2 first file</a><br>        </div><br>    </body><br></html>

Проверили — не работает. Оживить её можно с помощью яваскрипта, который опять же может быть отключён, но это уже не так фатально — пользователю будет показана ссылка на подключаемый файл.

Но мы поступим круче и обойдёмся без яваскрипта. А поможет нам в этом xsl преобразование, накладывающееся само на себя. Напишем index2.xml, который будет ни чем иным, как index.htm обёрнутым в специальную волшебную обёртку.

<!DOCTYPE t:stylesheet [ <!ATTLIST t:stylesheet id ID #REQUIRED> ]> <br><?xml-stylesheet type="text/xsl" href="#t:stylesheet"?><br><t:stylesheet id="t:stylesheet" version="1.0" xmlns:t="http://www.w3.org/1999/XSL/Transform"><br>    <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" /><br>    <t:template match=" @* | node() "><br>        <t:copy><br>            <t:apply-templates select=" @* | node() " /><br>        </t:copy><br>    </t:template><br>    <t:template match=" / "><br>        <t:apply-templates select=" document( '#t:stylesheet' )//html " /><br>    </t:template><br>    <t:template name="content"><br>        <html><br>            <head><br>                <title>Xbrowser HTML includes</title><br>                <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><br>            </head><br>            <body><br>                <h1>Second file</h1><br>                <div src="index1.htm" srctype="text/xml"><br>                    <a href="index1.htm">link 2 first file</a><br>                </div><br>            </body><br>        </html><br>    </t:template><br></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' ) ] "><br>    <t:copy><br>        <t:apply-templates select=" @* " /><br>        <t:apply-templates select=' document( @src )//html/body/* ' /><br>    </t:copy><br></t:template>

Примечательно, что инклудить таким образом можно как xml типа index2.xml, так и html типа index1.htm
Напишем index3.xml, который инклудит index2.xml

<!DOCTYPE t:stylesheet [ <!ATTLIST t:stylesheet id ID #REQUIRED> ]><br><?xml-stylesheet type="text/xsl" href="#t:stylesheet"?><br><t:stylesheet id="t:stylesheet" version="1.0" xmlns:t="http://www.w3.org/1999/XSL/Transform"><br>    <t:output doctype-public="-//W3C//DTD XHTML 2.0//EN" doctype-system="http://www.w3.org/MarkUp/DTD/xhtml2.dtd" /><br>    <t:template match=" @* | node() "><br>        <t:copy><br>            <t:apply-templates select=" @* | node() " /><br>        </t:copy><br>    </t:template><br>    <t:template match=" *[ @src and contains( @srctype, 'xml' ) ] "><br>        <t:copy><br>            <t:apply-templates select=" @* " /><br>            <t:apply-templates select=' document( @src )//html/body/* ' /><br>        </t:copy><br>    </t:template><br>    <t:template match=" / "><br>        <t:apply-templates select=" document( '#t:stylesheet' )//html " /><br>    </t:template><br>    <t:template name="content"><br>        <html><br>         <head><br>            <title>Xbrowser HTML includes</title><br>            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><br>         </head><br>         <body><br>             <h1>Third file</h1><br>             <div src="index2.xml" srctype="text/xml"><br>                 <a href="index2.xml">link 2 second file</a><br>             </div><br>         </body><br>        </html><br>    </t:template><br></t:stylesheet>

Для роботов и убогих мобильных браузеров страницы можно просто отдавать как text/html и тогда вместо вставляемого файла будет рисоваться ссылка на него.

Совместимость: ie6+, ff3+, opera10+, webkit?+
Tags:
Hubs:
+38
Comments132

Articles