Home Map Index Search News Archives Links About LF
[Top bar]
[Bottom bar]
Эта заметка доступна на: English  Castellano  Deutsch  Francais  Russian  Turkce  

[Фото автора]
Автор Egon Willighagen

Об авторе:

Вступил в голландскую команду LF в 1999 г. и стал вторым редактором в начале этого года. Учится в Университете Неймегена на факультете информационной химии. Играет в баскетбол и любит путешествовать.

Содержание:

Использование Perl - модуля XML::XSLT

[Иллюстрация]

Резюме:

Заметка представляет собой введение в в использование Perl - модуля XML::XSLT. Рассматриваются возможности стандарта XSLT и способы их использования для управления документами XML.



 

Введение

XSLT рекомендован W3C и может рассматриваться как стандарт. XSLT является частью XSL(язык шаблонов XML). Его назначение, как следует из названия, - форматирование XML-документа. Форматирование является основной задачей XSL и в этом процессе часто необходима трансформация данных, что и осуществляет XSLT.

XSLT-обработчики написаны на нескольких языках программирования : на C(XT, разработан James Clark) и на Java(Xalan, разработан Lotus Inc.). Также существуют и Perl-проекты : XML::XSLT и XML::Sabotron. Первый полностью написан на Perl, второй являестся интерфейсом к C++ XSLT-обработчику.  

Модуль XML::XSLT

Текущую версию модуля(0.21) можно загрузить с CPAN. Заметка основывается на данной версии. Perl-модуль был разработан Geert Josten - студентом факультета химии Университета Неймегена, но в настоящее время в разработке участвуют и многие другие. Применение CVS tree позволяет рассчитывать на ускорение разработки модуля, что необходимо W3C для осуществления рабочего проекта XSLT.

Ниже следует Perl-код, демонстрирующий использование модуля :

#!/usr/bin/perl
use XML::XSLT;

my $xmlfile = "example.xml";
my $xslfile = "example.xsl";

my $parser = XML::XSLT->new ($xslfile, "FILE");

$parser->transform_document ($xmlfile, "FILE");
$parser->print_result();

Здесь XML-файл(example.xml) трансформируется на основе XSLT-файла (example.xsl). Также шаблоны могут быть основаны на DOM tree :

#!/usr/bin/perl
use XML::XSLT;
use XML::DOM;

my $domparser = new XML::DOM::Parser;
my $doc = $domparser->parsefile ("file.xml");

my $parser = XML::XSLT->new ($doc, "DOM");

или строке :


#!/usr/bin/perl
use XML::XSLT;

my $xsl_string = qq{
<?xml version="1.0"?>
<xsl:stylesheet>
  <xsl:template match="/">
    <html>
      <xsl:apply-templates/>
    </body>
  </xsl:template>
</xsl:stylesheet>
};

my $parser = XML::XSLT->new ($xsl_string, "STRING");

Все три варианта можно использовать для процедуры transform_document(), показанной в первом примере.

Скрипт транслирующий XML-файл на основе шаблона XSLT можно загрузить здесь. Он использует имена файлов в качестве аргументов : шаблон XSLT и XML файл. Обратите внимание, что скрипт использует механизм "FILE".

Теперь, после того как мы узнали способ применения XSLT-обработчика для трансляции XML-документов в языке Perl, рассмотрим стандарт XSLT.  

Стандарт XSLT

XSLT был разработан с целью упрощения публикации данных, хранимых в XML. XSL-форматирование используется для разработки и представления, а XSLT-для трансформации XML-данных (сортировка, выбор, комбинирование из различных источников). На самом деле, как показывает практика, XSLT достаточен также для разработки и представления.

Модуль XML::XSLT использует не все команды XSLT, но все рассматриваемые в заметке поддерживаются.

XSLT-документ определяет метод трансформации XML-документа. Это достигается определением шаблона для каждого элемента. Ниже рассматривается несколько примеров XSLT-документов, применяемых к одному XML-документу, содержащему рабочий лист Gnumeric (GNOME).

Просмотрев шаблоны можно обнаружить, что они содержат информацию о формате выводимых данных (например : формат страницы, ширина и высота ячейки). Мы создадим XSLT-шаблоны для выполнения следующих задач :

Введение в основы XML::XSLT осуществим написанием XSLT-шаблона выдающего краткий отчет (verysimple.xsl):

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

  <xsl:template match="*">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="text()"/>

  <xsl:template match="Item">
    <xsl:value-of select="./name"/> : <xsl:value-of select="./val-string"/>
  </xsl:template>

</xsl:stylesheet>

Первый шаблон находит все элементы в XML-документе, второй-CDATA в XML- документе и наконец третий выполняет то, что мы хотели сделать : каждый элемент в отчете сопровождается значением CDATA элементов name и val-string. Попробуйте сами! Сравните выводимую информацию с тем, что вы хотели получить.

Но ведь уже первый шаблон находит элемент, не так ли? Тогда почему применяется третий шаблон, а не первый? Все дело в том, что последующий переписывает предыдущий. Поэтому шаблоны расположены от общих к специфичным.

Обратите внимание на добавление множества пробелов. Я не думаю, что есть возможность обойти это для данной версии. Но если файл будет в формате XHTML- нам не о чем беспокоиться. Следующий пример соответствует предыдущему с добавлением служебной информации XHTML для просмотра выходного файла в веб - браузере (simple.xsl):

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

  <xsl:template match="*">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="text()"/>

  <xsl:template match="Item">
    <b><xsl:value-of select="./name"/></b>: <i><xsl:value-of select="./val-string"/></i><br />
  </xsl:template>

  <xsl:template match="/">
    <html>
      <head>
        <title>Summary Gnumeric File</title>
      </head>
      <body bgcolor="white">
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Дополнительный шаблон для элемента root(/) позволяет вставить XHTML-код перед и после основного вывода. Рассмотрим подробнее : при запуске XML::XSLT осуществляется поиск шаблона с элементом root, далее вставляется XHTML-код до открывающего элемента <body> включительно, после этого применяются шаблоны к элементам, затем продолжается обработка с шаблоном root и вставляется закрывающий элемент </body> и др.

В шаблон Item добавляется дополнительный XHTML-код. Обратите внимание, что можно использовать одновременно и XSLT команды и выводимые данные. XSLT-обработчик принимает все элементы не содержащие xsl как выводимые данные.

С этого места будем показывать только новые или измененные шаблоны. Для завершения нашего первого примера добавим заголовок и посмотрим на результаты работы команды (finalsimple.xsl):

  <xsl:template match="Summary">
    <h2>Summary</h2>
    <ul>
      <xsl:apply-templates/>
    </ul>
  </xsl:template>
 

Команда for-each

Команда xsl:for-each предоставляет дополнительные возможности обработки XML-документов, особенно в сочетании с командой xsl:sort, но она еще не включена в модуль XML::XSLT.

Добавим информацию о формате страниц Gnumeric Workbook с помощью xsl:for-each (foreach.xsl):

  <xsl:template match="Sheets">
    <xsl:for-each select="Sheet">
      <h2><xsl:value-of select="Name"/></h2>
      <ul>
        Rows: <xsl:value-of select="MaxRow"/><br />
        Cols: <xsl:value-of select="MaxCol"/><br />
      </ul>
    </xsl:for-each>
  </xsl:template>

К сожалению использованный XML-документ состоит из одной страницы. Можно попробовать применить этот шаблон к другому Gnumeric-файлу, состоящему из нескольких страниц.

Как упоминалось раньше-мы не можем сортировать элементы с помощью XML::XSLT в данный момент. Очень жаль, потому что XML-данные в Gnumeric-файле не отсортированы. Если бы у нас была возможность отсортировать их, мы могли бы составить XHTML-таблицу с точным оглавлением. Все, что мы можем сейчас сделать - поместить всю информацию в одну колонку. Рассмотрим это в следующем примере.  

Команда if

Выведем информацию из третьей колонки (данные о зарплате состоятельных студентов из Голландии) с помощью команды xsl:if (if.xsl):

  <xsl:template match="Sheets">
    <xsl:for-each select="Sheet">
      <h2><xsl:value-of select="Name"/></h2>
      <ul>
        Rows: <xsl:value-of select="MaxRow"/><br />
        Cols: <xsl:value-of select="MaxCol"/><br />
        <xsl:apply-templates select="Cells"/><br />
      </ul>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="Cells">
    Content of Col 3:
    <xsl:for-each select="Cell">
      <xsl:if test="@Col='3'">
        <xsl:value-of select="Content"/><xsl:text>, </xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

Так как сам шаблон "Sheets" не применяет никаких дополнительных шаблонов к элементу "Cell" нам необходимо указать это. Используя команду xsl:apply-templates с аттрибутом "Cells" мы применяем шаблон к этому элементу.

Шаблон "Cells" просматривает все элементы "Cell" (будьте внимательны и проверьте это с исходным XML-файлом), но выводит значение только если аттрибут "Col" имеет значение "3". Обратите внимание, что наличие "@" указывает на аттрибут, а отсутствие - на элемент.

Разработанные нами шаблоны стали более сложными и теперь надо контролировать текущий элемент. В рамках всего документа это невозможно, но можно попытаться в отдельном шаблоне. Например, обращаясь к шаблону "Cells" обработчик проводит поиск этого элемента (в данном случае элемент "Cells"). Далее select="Cell" в команде xsl:for-each производит выборку всех элементов "Cell", и один раз в этом цикле будет обращение к одному из элементов. Обратите внимание, что test="@Col" обращается к аттрибуту "Cell", а не "Cells". К аттрибуту "Cells" можно обратиться - select="../@name", даже если "Cells" не имеет аттрибутов.

Команда xsl:text контролирует вывод всего текста. Пробел в последовательности ", " принимается как не относящийся к выводимой информации.  

Заключение

Эта заметка является лишь введением в использование модуля XML::XSLT. Возможно у вас возникнут вопросы и это хорошо. Оставляйте их на контактной странице или пишите в лист рассылки веб сайта XML::XSLT.  

Ссылки


Webpages maintained by the LinuxFocus Editor team
© Egon Willighagen
LinuxFocus.org 2000

Click here to report a fault or send a comment to Linuxfocus
Translation information:
en -> -- Egon Willighagen
en -> ru Kirill Poukhliakov

2000-07-04, generated by lfparser version 1.5