Поиск по этому блогу

понедельник, 24 июня 2013 г.

Шаблон XSLT. Трансформируем XML.


В исходном xml файле указываем ссылку на xsl-файл
<?xml version="1.0" encoding="WINDOWS-1251"?>
<?xml-stylesheet type='text/xsl' href='ex1.xsl'?>
...
Шаблон файл ex1.xsl



 <?xml version="1.0"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- метод вывода -->
 <xsl:output method="xml"|"html"|"text"|" encoding="utf-8" indent="yes"/>
 <!-- для форматирования рублей 1 409 301.89  -->
          <xsl:decimal-format name="rub" decimal-separator="." grouping-separator=" " minus-sign="-" NaN="!" zero-digit="0" /> 
         <xsl:template match="/ (выражение XPATH)">
                 <!-- набор инструкций -->
  содержимое элемента
  <xsl:value-of select="выражение XPATH" disable-output-escaping="yes|no" />
  <xsl:value-of select="format-number(($s1), '### ###.00','rub')"/> // вывод рублей
  цикл
  <xsl:for-each select="выражение XPATH"></xsl:for-each>
  цикл с сортировкой
  <xsl:for-each select="выражение XPATH" order-by="условие сортировки">
  сортировка
  <xsl:sort order="ascending" select="элемент, выражение XPATH"/> 
  условие
  <xsl:if test="выражение XPATH">   
  выбор подобный case
  <xsl:choose>
   <xsl:when test=...></xsl:when>
   <xsl:when test=...></xsl:when>
   <xsl:otherwhise>...</xsl:otherwhise>
  </xsl:choose>
  
         </xsl:template>
         <!-- ... -->
  </xsl:stylesheet>

Пример выбора

 <xsl:choose>
  <xsl:when test="name(current())=Название'"><td>Название: </td></xsl:when>
  <xsl:when test="name(current())='СокращенноеНазвание'"><td>+</td></xsl:when>
  <xsl:otherwise><td><xsl:value-of select="name(current())"/></td></xsl:otherwise>  
 </xsl:choose>

Пример цикла
выбираем путь к ноде, если имя ноды начинается со слов 'ИскомоеИмя'
В примере используется локальная переменная.

<xsl:for-each select="//*[ starts-with(name(),'ИскомоеИмя')]">
<h6>Имя: <xsl:value-of select="name(.)"/></h6>
</xsl:for-each>

<div>
<table>
<tr>
<xsl:for-each select="//ПутьИтого/descendant::*">
<tr>
<xsl:variable name="nodename" select="name()" />  -- локальная переменная в цикле
<td><xsl:value-of select="name(current())"/></td>
<td>nodename: <xsl:value-of select="$nodename"/></td>
<td>Раздел1:<xsl:value-of select="//ПутьРаздел1/descendant::*[name() = $nodename]"/></td>
<td>Раздел2:<xsl:value-of select="//ПутьРаздел2/descendant::*[name() = $nodename]"/></td>
</tr>
</xsl:for-each>
</tr>
</table>
</div>

Кроме переменных xsl может использовать параметры <xsl:with-param>
http://www.w3schools.com/xsl//el_with-param.asp

Выбор пути [фильтром] в цикле
<xsl:for-each select="//*[Строка = '100']/./Итого/descendant::*">


Задача. Пробежаться по всем веткам внутри родителя и сложить (отнять) соответствующие суммы
Ребенок1/Сумма/Итого + Ребенок2/Сумма/Итого
Ребенок1/Сумма/Январь + Ребенок2/Сумма/Январь


Кусок xml
<Родитель>
            <Ребенок1>
              <Строка>100</Строка>
              <Сумма>
                <Итого>12000.01</Итого>
                <Январь>1000.00</Январь>
                <Февраль>1000.50</Февраль>
...
                <Декабрь>1000.51</Декабрь>
              </Сумма>
            </Ребенок1>
            <Ребенок2>
              <Строка>101</Строка>
              <Сумма>
                <Итого>24000.20</Итого>
                <Январь>2000.89</Январь>
                <Февраль>1000.01</Февраль>
...
                <Декабрь>2000.88</Декабрь>
              </Сумма>
            </Ребенок2>
</Родитель>

Кусок XSL

<xsl:for-each select="//Родитель/Ребенок1/Сумма/descendant::*">
<tr>
// Выводим имя ноды (Итого, Январь, Февраль...)
<xsl:variable name="nodename" select="name()" />
<td><xsl:value-of select="$nodename"/></td>
// По номеру строки (фильтр [Строка = '100'] ) получаем одноименную ноду
// если родитель один - то можно обойтись без sum
<xsl:variable name="s100" select="//*[Строка = '100']/./Сумма/*[name() = $nodename]" />
// а вот если и родителей несколько, то можно их сложить
<xsl:variable name="s100" select="sum(//*[Строка = '100']/./Сумма/*[name() = $nodename])" />

<td><xsl:value-of select="format-number($s100, '### ###.00','rub')"/></td>

 <xsl:variable name="s101" select="//*[Строка = '101']/./Сумма/*[name() = $nodename]" />
<td><xsl:value-of select="format-number($s101, '### ###.00','rub')"/></td>

 <td>
<xsl:value-of select="format-number(($s100 + $s101), '### ###.00','rub')"/>
</td>

 
<td>
<xsl:value-of select="format-number(($s100 - $s101), '### ###.00','rub')"/>
</td>


 </tr>
</xsl:for-each>




Кратко XPATH
match ="/" - указывает на корень документа
match ="Parent/Child/" - путь к ребенку
match = "//Child" - найдет всех детей независимо от того где он (детеныш) находится
"//" - называется оператором рекурсивного спуска
match = "Parent|Child" - список дочерних элементов

Предикаты (в скобках сокращение)

self::  сам узел (.)
child::  ребенок (..)
parent:: родитель
descendant:: потомки
descendant-or-self:: потомки и сам узел (//)
ancestor:: предки
ancestor-or-self:: сам и предки
following:: все узлы после данного
following-sibling:: все узлы того же уровня после данного
preceding:: все узлы перед данным
preceding-sibling:: все узлы этого же уровня перед данным
attribute:: атрибут (@)
namespace:: узлы пространства имен

Поиск/индексация
[] - оператор фильтра
child::price[price=23.00] возвращает множество узлов, где элемент price имеет значение  23.00

Для поиска элемента по индексу используются []
Parent/Child[0] - первый ребенок
Parent/Child[last()] - последний ребенок
Для явного задания порядка вычисления выражений используются скобки ()
Parent/Child[0] - первый ребенок у каждого родителя
(Parent/Child)[0] - первый Child из всего набора элементов y внутри элементов Parent.
Parent[0]/Child[0] - первый Parent, первый Child

XPATH поддерживает числовые выражения (+, -, *...), сравнение (<, >, !=...) и около 27 функций для стандарта 1.0.

Функции (числовые, строковые, булевы). В стандарте 2.0 эта область была расширена, например, вместо round - округление до целого появилась более "продвинутая" функция round-half-to-even( ).

Строковые функции.

string   Преобразует аргумент в строку.
string-length         Возвращает длину строки.
substring          Возвращает подстроку.
substring-after         Возвращает остаток строки после второго аргумента.
substring-before Возвращает часть строки перед вторым аргументом.
contains          Возвращает 'истину', если первая строка содержит вторую.
starts-with          Возвращает 'истину', если первая строка начинается второй.
concat   Возвращает конкатенацию двух строк.
normalize-space Удаляет лишние пробелы в строке.
translate          Заменяет символы в строке. translate('Исходная строка','Что меняем','На что
                                меняем')

Числовые функции

round                       Округляет до ближайшего целого.
ceiling                       Округляет до ближайшего целого, которое больше данного.
floor                         Округляет до ближайшего целого, которое меньше данного.
count                        Возвращает количество узлов.
number                     Преобразует аргумент в число.
sum                          Возвращает сумму списка чисел.


ссылки