Формирование страницы XML/XSLT

timur-kar

Новичок
Формирование страницы XML/XSLT

Пишу мини-движок для сайта, на XML/XSLT.

Задача следующая: нужно определить общий макет страницы и макет содержания страницы в разных XML файлах. Потом из самих страниц вызывать только преобразование XSL с указанием 2ух параметров общий шаблон и шаблон контента. Вопросы:

1) есть XML документ в PHP, как вызвать его преобразование с использованием двух разных XSL файлов. (интересует решение на libxml2, но можно и на других библиотеках - интересно будет посмотреть как это делается в принципе)

2) правилен ли вообще подход при котором я формирую один XML файл и потом его так обрабатываю ? на Smarty я делал так - был один шаблон макета страницы, в него я вставлял ссылку на шаблон контента (smarty делал include) и потом парсил шаблон макета страницы. Плюс этого в том что, и шаблон макета и шаблон контента могут пользоваться одними и теми-же данными.
 

[DAN]

Старожил PHPClub
В xslt тоже есть возможность инклюдить сторонние файлы.
Возможен такой подход: собираешь все xsl-шаблоны в один документ (в DOM-объект), и потом делаешь преобразование за один проход над своими данными.
 

timur-kar

Новичок
Спасибо за ответ

Вариант со сбором 2-ух файлов в один я рассматривал, показался слишком сложным (хотя если легче не найду - буду делать его)
. Еще пробовал 2 раза процессить (сначала одним, потом другим xsl) :) - ошибочный вариант :)
Инклюдить сторонние файлы - есть вопрос, можно ли инклюдить переменный файл (чтобы его имя брать из variable или из XML-данных).

Да, и еще - можно ли в XML хранить текст статьи с HTML-разметкой (<br/> и т.д.) ? А то при парсинге она отваливается, а хотелось бы хранить именно с разметкой. Можно конечно прописать все шаблоны HTML в XSL, но это же не нормальный путь ? Или это подход неправильный - хранить текст с HTML разметкой в XML ? Но тогда XML становится довольно неудобным :(
 

Alexandre

PHPПенсионер
можно ли инклюдить переменный файл (чтобы его имя брать из variable или из XML-данных).
нет
Синтаксис:
Код:
<xsl:include   href = "URI reference" />
Parent elements <xsl:stylesheet >
Но как вариант, можно:
задать имя файла некой переменной
а использовать переменную, в качестве имени шаблона :)
 

timur-kar

Новичок
Ясно

а как можно собрать 2 XSL файла в один DomDocument ?
У меня пока не получается, причем проблема такая - мне из XSL файла надо получить его корневой элемент.
Пробую делать:

getElementsByTagName("xsl:stylesheet") - не получается :(

а из DomDocument нельзя взять firstChild :(
 

Alexandre

PHPПенсионер
не понимаю, зачем собирать два xsl в один ДОМ

1) можно сделать импорт идух документов

2) можно сделать 2 XSLT преобразования

в принципе можно изменить xsl преобразование программно, но оно для этого не предназначено.

используй промежуточный xml

XSL шаблоны должны быть статическими, на то они и шаблоны :)

-~{}~ 22.12.04 14:19:

Лично я делаю так:
имеется генеральный шаблон
имеется шаблон для каждой страницы, который состоит из
набора <tempate match="xxx">

грузится шаблон из папки шаблонов с именем $_SELF, но расширением xsl
Использую правило: один скрипт - один шаблон

шаблош - инклудит генеральный шаблон

в зависимости от значения $_REQUEST[action] формируется тег "<action>".$_REQUEST[action] ."</action>"

формируется выходной xml
делаю преобразование

Для каждого action применяется свой шаблон по <xsl:template match="" />
 

timur-kar

Новичок
XSL шаблоны должны быть статическими, на то они и шаблоны :)
Абсолютно согласен :) но как-то надо реализовывать разделение шаблонов на генеральный и шаблон скрипта :)
Некоторые вещи не получаются поэтому приходится извращаться

Лично я делаю так:
имеется генеральный шаблон
имеется шаблон для каждой страницы, который состоит из
набора <tempate match="xxx">

грузится шаблон из папки шаблонов с именем $_SELF, но расширением xsl
Использую правило: один скрипт - один шаблон

шаблош - инклудит генеральный шаблон
Тоже вариант, но здесь у меня другие проблемы :)
Как я понял у тебя одна папка шаблонов ?
У меня немного другой подход к этому, в директории со скриптом есть поддиректория tpl в которой и должен быть шаблон (всегда так делаю). Плохо получается делать include генерального шаблона. Прописывать относительные пути немного неправильно, а делать <xsl:include href='/page/1.xsl'/>
не получается !!! не знаю почему, вроде в корне есть /page, а в нем есть файл 1.xsl.
Поэтому и есть проблема с тем что include не может работать с переменными или данными XML :(

-~{}~ 23.12.04 11:13:

2Alexandre:
Вообще такой подход подразумевает что сам шаблон страницы знает о том что такое генеральный шаблон, и главное - где его искать. При таких ограничениях в xslt (например как невозможность задания переменной пути к файлу), это неудобно. Да и вообще неправильно чтобы шаблон знал что-то кроме того что он шаблон :)
Такими вещами как компоновка шаблонов должен управлять сам скрипт, но вот это-то пока не получается! Тут в соседнем топике
http://phpclub.ru/talk/showthread.php?s=&threadid=59909&rand=8
много говорилось о многопроходности XSLT-преобразований на серверной стороне и о том что это возможно. Вот и стоит вопрос - как это возможно :)
 

Alexandre

PHPПенсионер
Код:
<?xml version="1.0" encoding="windows-1251" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:include href="main1.xslt" />
<xsl:include href="page.xslt" />
<xsl:оutput   method =  "xml"  encoding = "windows-1251" />

....
все работает,
в page.xslt заданы шаблоны отображения правой части экрана
т.е. шаблон содет быть с меню в правой части экрана либо без нее :)

main1.xslt - генеральный шаблон обрамления.

timur-kar а, что тебе мешает вычислять путь файла в папке, где лежит шаблон и закачивать этот шаблон.
я не вижу в этом ни какой проблемы :)
генеральный шаблон и шаблоны с общими конструкциями (такими как календарь, например) можно хранить в корневой папке [rooot]/tpl

и зная, из какой папки у тебя скрипт вызывается скрипт, всегда можно определить относительный путь до корня сайта и уже его прописывать в шаблоне.

я не вижу причины использовать двойное XSLT преобразование, только для того, чтоб подцепить генеральный шаблон
[offtop]
а вообще-то это дело привычки (или умения кодинга), как организовывать храения шаблонов.

У меня, например, скрипты сгруппированны в модули.
Модуль, это конструкция, которая выполняет законченные действия с определенной предметной областью. Данному скрипту - соответствует свой шаблон.

Например, Модуль Пользователи users.php, может:
- Просмативать список пользователей,
- изменять их профайлы,
- удалять пользователей.

т.е. один скрипт генерит 4-5 разных форм. По этому я не путаюсь ни в шаблонах, ни в скриптах - где что искать :)
если, у меня код не умещается в пределах одного скрипта, то я его разбиваю на классы, хоторые хранятся в своей папки :)

но это тема др, топика ;), можешь посмотреть по ключевому слову MVC - не раз обсуждалось
[/offtop]

Пример, когда это (двойное преобрахование) действительно необходимо:
у теля есть некий контент в xml
тебе надо скрыть по определенным правилам некоторую часть элементов
и отобразить оставшиеся.
Код:
xml -> ПРЕОБРАЗОВАНИЕ 1 -> xml2 -> ПРЕОБРАЗОВАНИЕ 2 -> HTML 
            ^                            ^
          xsl 1                         xsl2
 

timur-kar

Новичок
timur-kar а, что тебе мешает вычислять путь файла в папке, где лежит шаблон и закачивать этот шаблон.
я не вижу в этом ни какой проблемы
генеральный шаблон и шаблоны с общими конструкциями (такими как календарь, например) можно хранить в корневой папке [rooot]/tpl
Вот видишь, ты сам написал [rooot]/tpl
т.е. [rooot] ты сам трактуешь как переменную в которую я должен подставить свой root и прописать в шаблон. Дело в том что я пишу движок, а в движке не должно быть двусторонней связи между шаблоном и самим движком. Т.е. шаблон должен быть изолированным (как я это понимаю) и должен служить ТОЛЬКО для трансформации в HTML. Вся проблема ТОЛЬКО в том что xsl:include не кушает переменные, поэтому придется xsl делать частью движка. Вообще нормальный движок не должен заставлять прописывать новый путь во всех шаблонах если изменился [root], а должен конфигурироваться (и дело не в том что я собираюсь часто менять [root] :) а в том что это нормальный стиль программирования и построения того-же MVC).

А то что двойное преобразование для этого не предназначено - согласен, просто это было бы меньшим злом чем делать шаблон частью движка.

а вообще-то это дело привычки (или умения кодинга), как организовывать храения шаблонов.
Ну, насчет умения не знаю, причем тут оно мне не особо ясно. Я привык делить на части все что можно поделить, в том числе и скрипты и шаблоны, и четко прослеживать зависимости (с документацией). Мне кажется в одном большом файле искать сложнее чем в многих, но четко структуированных. Но это ЦЕЛИКОМ И ПОЛНОСТЬЮ дело привычки - в этом я абсолютно с тобой согласен.

а вообще - спасибо большое за объяснение. Буду делать XSL частью движка т.к. все-таки XSL использовать очень охота, очень похоже что выгода в удобстве от этого будет больше чем потери от того что придется путь прописывать в XSL. Или будем искать как объединить шаблоны в один (тогда пути будут под контролем PHP :) а если четко прописать один класс который всем этим заведует то проблем в этом не будет вообще)
 

[DAN]

Старожил PHPClub
Народ, буду агитировать за следующую концептуальную схему.
1) Как я понял, модульность в системе присутствует. Так вот, каждый модуль знает, какой из xsl-шаблонов надо "прикрутить" к главному шаблону.
2) Трансформация должна быть однозначно однопроходной. Где она будет проходить (на сервере или на клиенте), решать системе.
3) Как формировать результирующий xslt-шаблон - дело вкуса.

Я в свое время делал так. Получал от модуля ссылки на xsl-файлы, преобразовывал их содержимое в dom-объект, и этот объект вставлял (что-то типа append_child() ) в основной шаблон.
Можно, и имхо выгоднее, отдавать эту работу xslt-процессору. Тогда нам понадобится лишь вставить ссылки (<xsl:include href="$you_root_here/page.xslt"/>) в основной шаблон.
Тогда и директорию с шаблонами легко будет конфигурить, и "нормальный стиль программирования" сохранить.
 

crocodile2u

http://vbolshov.org.ru
2 [DAN]:

Я в одном проекте использовал похожую схему, только я составлял скриптом примерно такой XSL:
PHP:
<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="./xsl/common.xsl"/>
<xsl:import href="./xsl/your-page-here.xsl"/>
</xsl:stylesheet>
Вроде получилось неплохо, хотя впоследствии я все-таки решил, что использование XML/XSL в том проекте все-таки не было до конца оправдано.
 

Alexandre

PHPПенсионер
Вся проблема ТОЛЬКО в том что xsl:include не кушает переменные, поэтому придется xsl делать частью движка. Вообще нормальный движок не должен заставлять прописывать новый путь во всех шаблонах если изменился [root],
Есть пути относительные, я про это тракторавл, но crocodile2u правильно привет пример:
<xsl:import href="./xsl/common.xsl"/>
<xsl:import href="./xsl/your-page-here.xsl"/>
Кстати - движкуи не зачем знать абсолютный путь...

ЗЫ. Понял, что народ на практике XSL уже изучил, но как правильно применять еще до конца не знает... ;) Решил написать статью по этому поводу ;) правда - туго со временем, но постараюс ;)
 

timur-kar

Новичок
[DAN]
Схема вполне устраивает, тогда действительно шаблон получается самостоятельным и это есть гуд.

По этой схеме есть вопросы:
Можно ли работать с XSL-шаблоном также как и с нормальным DOM-объектом ? Я понимаю что XSL - это тоже XML, но у меня не получается сделать
getElementsByTagName("xsl:stylesheet"); :(
может я что-то неправильно делаю
жалко что сейчас на работе, а здесь пока PHP5 не поставил.

Да и еще вопрос - можно ли получить корневой узел DOM-мента не зная его имени ?


crocodile2u
Вроде получилось неплохо, хотя впоследствии я все-таки решил, что использование XML/XSL в том проекте все-таки не было до конца оправдано.
Можно ли об этом поподробнее ? Почему не до конца оправдано. Ведь если написать нормальный движок один раз можно будет его использовать и в больших и в малых сайтах. Или дело не в размере сайта ?

Alexandre
Есть пути относительные, я про это тракторавл, но crocodile2u правильно привет пример
Кстати - движкуи не зачем знать абсолютный путь...
Alexandre, ну зачем ты так агитируешь за относительные пути. Это плохо в том случае когда движок должен быть универсальный (еще хуже в случае когда сайт большой). В хорошем универсальном движке должно все настраиваться (конфигурировться) и все связи между компонентами должен осуществлять только сам движок.

ЗЫ. Понял, что народ на практике XSL уже изучил, но как правильно применять еще до конца не знает... Решил написать статью по этому поводу правда - туго со временем, но постараюс
В общем наверно так и есть. Только я еще XSL на практике совсем не изучил :) Только начал. А как его применять - как раз и была тема этого топика ;) Но идею со статьей поддерживаю полностью, будет очень интересно почитать. Вот еще бы там относительных путей не было ;)
 

Alexandre

PHPПенсионер
Вот еще бы там относительных путей не было
timur-kar и чем тебе относительные пути так не нравятся.

у каждой системы есть своя определенная структура каталога,
например:
/images
/css
/js
/classes
/xsl
и эта структура уже предопределена.
пути все отностительны, переносимость универсальная :)
 

timur-kar

Новичок
Alexandre
Если создаешь движок - он должен настраиваться. Он не должен быть частью системы каталогов и она не должна быть его частью. В нем могут быть прописаны пути по умолчанию, но не должен заставлять программиста делать такие пути как прописаны в нем только из-за того что он НЕ УМЕЕТ нормально конфигурироваться :)

-~{}~ 24.12.04 13:46:

Движок - это в смысле движок отвечающий за отображение данных, который преобразует данные и шаблон в HTML, а не движок всего сайта.
 

maxim

Новичок
Автор оригинала: timur-kar
Ясно

а как можно собрать 2 XSL файла в один DomDocument ?
У меня пока не получается, причем проблема такая - мне из XSL файла надо получить его корневой элемент.
Пробую делать:

getElementsByTagName("xsl:stylesheet") - не получается :(

а из DomDocument нельзя взять firstChild :(
Дело в том, что корень документа xml(то есть когда шаблон у тебя еще не стал xslt) надо делать так
if(!$xsl = domxml_open_file($xsl_dir . $xsl_file))echo "File Not found ";

$xsl_root = $xsl->document_element();//теперт этот корень можно прицепить к главному шаблону и затем сделать из него xslt


Я делал так- у меня есть один глобальный шаблон, и на каждый action свой подшаблон. Сначала я подгружал глобальный шаблон, затем грузил подшаблон(у него корень называется x_include). Пути везде абсолютные

$xsl_dir = XSLROOT . 'templates/';
$xsl_file = "page.xml";// главный шаблон

if(!$xsl = domxml_open_file($xsl_dir . $xsl_file))echo "File Not found ";

$xsl_root = $xsl->document_element();//теперь к корню надо добавить подшаблон

//для подшаблона
if(!$xsl_inc = domxml_open_file(XSLROOT . $load_module . "/" . $load_page . ".xml")) echo "Not found ".$load_module . "/" . $load_page . ".xml";//грузим подшаблон


$xsl_inc_root = $xsl_inc->document_element();//получаем его корень
$xsl_inc_child = $xsl_inc_root->child_nodes();// затем массив детей корня
$xsl_inc_child = $xsl_inc_child[1]->child_nodes();
for ($i = 0; $i < sizeof($xsl_inc_child); $i++) {
$xsl_root->append_child($xsl_inc_child[$i]->clone_node(TRUE));//выкидываем элемент с xmlns:xsl и добавляем собственно
}

$xsl = domxml_xslt_stylesheet_doc ($xsl);//из xml документа получаем xsl документ

$result = $xsl->process($xml);//делаем однопроходное преобразование

-~{}~ 24.12.04 18:45:

Из этого топика я почерпнул следующее:

Вообще проблема подключения шаблонов не укладывается в 2 шаблона. Мне бывает неоходимо подключать больше двух, поэтому может целесообразнее возложить подключение всех шаблонов в шаблоне каждого action'а


<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<x_include>

<!-- begin для текущего action-->
<xsl:template match="...">
...
</xsl:template>

<xsl:template match="...">
...
</xsl:template>
<!-- end для текущего action-->

<!-- подключение дополнительных шаблонов header, footer, menu1, menu2 и т.д.-->
<xsl:import href="./xsl/main.xsl"/>
<xsl:import href="./xsl/menu1.xsl"/>

</x_include>
</xsl:stylesheet>

Мне кажется этот вариант наиболее идеологически правильным. Дизайн(в смысле сборка одного шаблона из нескольких) вообще не зависит от программы.

Правда есть один косяк - это относительные пути в шаблоне action'а. Можно конечно на это забить - шаблон это дизайн(он делается для конретного проекта). Программе важно знать где находится один-единственный шаблон action'а и его, собственно, подгрузить. А можно открывать шаблон action'а через DOMXML(или как в текстовом файле) и заменять пути.
 

timur-kar

Новичок
maxim
Спасибо за ответ. Столкнулся со следующей проблемой.
Пользуюсь libxml2 и никак не могу решить следующую вещь: как получить корень XML-документа ????
У DomDocument нет методов documentElement, firstChild. В документации вообще старая информация (в которой методы еще через подчеркивание пишутся). Из XSL-документа не получается взять ни один node у которого название написано через двоеточние :)) например xsl:stylesheet, если брать такой элемент как child другого элемента он его распознает как DomText-элемент ?

Что это - сырость библиотеки или мое незнание ?
 

maxim

Новичок
Насколько я понимаю, libxml2 напрямую ты пользоваться не можешь. Ты пользуешься каким-то модулем ПХП (например как я - DOMXML)
Так вот используя ДОМХМЛ это делается так
$xsl = domxml_open_file($xsl_file);//open file
$xsl_root = $xsl->document_element();//get root
$xsl = domxml_xslt_stylesheet_doc ($xsl);//из xml документа получаем xsl документ

если что непонятно пиши
[email protected]
 

Alexandre

PHPПенсионер
Alexandre
Если создаешь движок - он должен настраиваться. Он не должен быть частью системы каталогов и она не должна быть его частью.

В нем могут быть прописаны пути по умолчанию, но не должен заставлять программиста делать такие пути как прописаны в нем только из-за того что он НЕ УМЕЕТ нормально конфигурироваться

Движок - это в смысле движок отвечающий за отображение данных, который преобразует данные и шаблон в HTML, а не движок всего сайта.
я не буду спорить, но в тоже мере скажу, что большинство движков (наверно даже все), с которыми мне приходилось иметь дело - имели предопределенную структуру каталогов,
по крайней мере от корневого каталога движка.
[root WWW]/[root Engenee]/images
[root WWW]/[root Engenee]/xsl
....

и я не вижу в этом ничего плохого.

Мне как-то прихожилось динамически настраивать xsl шаблон.
я делал просто -
писал шаблон (в ввиде файла) без обрамляющих рутовских тегов <xsl:stylesheet>

втягивал xsl файл как массив строк fle(...)
добавлял строки в начало
<?xml ...?>
<xsl:stylesheet ...>
<xsl:import ... >

и в конец:
</xsl:stylesheet ...>
а дальше уже испотльзовал DOMXML для XSLT преобразования ;)

можешь пойти по этому пути, но это ни есть гууд:)
 

timur-kar

Новичок
maxim
Я использую PHP5 и под него DOM-extension (оно по-моему так и называется и это не domxml)
http://www.php.net/manual/pt_BR/ref.dom.php

там к сожалению нет метода DomDocument->documentElement(); :(
в том то и проблема :(


Alexandre
вероятнее всего мы с тобой говорим о разных движках. Ты говоришь о движке всего сайта, а я говорю о той его части которая будет заниматься отображением.
Я действительно написал: "Пишу мини-движок для сайта, на XML/XSLT." Но движок сайта, в моем понятии должен быть разделе на составляющие которые можно использовать отдельно (одной из составляющих должен быть движок страниц). Так что последующие вопросы касались именно отображающего движка. Давай оставим этот спор, я все равно считаю что части системы должны быть самостоятельными и по минимуму зависеть от друг-друга (а тем более от файловой системы).
Тот путь который ты предложил в конце действительно не есть гуд и я с тобой в этом полностью согласен :)
Скорее всего действительно буду пользоваться относительными путями, но очень обидно когда приходится отходить от некоторых архитектурных решений из-за плохих инструментов :(
 
Сверху