Гость
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице? / 14 сообщений из 14, страница 1 из 1
13.12.2017, 12:28
    #39568914
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
Конечно на ум сразу приходит использовать цикл:

Код: xml
1.
2.
3.
<xsl:for-each
  select = Expression
</xsl:for-each>



например, нужно вывести данные по заказчикам:

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<customers>
   <customer>
      <name>Ваня</name>
      <phone>(812)123-4567</phone>
   </customer>
   <customer>
      <name>Петя</name>
      <phone>(812)423-4537</phone>
   </customer>   
</customers>



чтобы это сделать, нужно организовать вот такой классический цикл:

Код: xml
1.
2.
3.
4.
5.
6.
<xsl:for-each select="customers/customer">
  <TR>
    <TD><xsl:value-of select="name" /></TD>
    <TD><xsl:value-of select="phone" /></TD>
  </TR>
</xsl:for-each>



в итоге имеем нужные 2-е колонки:

Код: html
1.
2.
3.
4.
Имя   Телефон
--------------------
Ваня  (812)123-4567
Петя  (812)423-4537 



Но это всё для вывода неизвестного заранее кол-ва строк, а если неизвестно кол-во колонок?

Например, нужно посчитать кол-во сделанных этими клиентами заказов за заданный параметром период, чтобы было вот так:

Код: html
1.
2.
3.
4.
Имя   Телефон          К1   К2  К3
----------------------------------
Ваня  (812)123-4567    5    3    2
Петя  (812)423-4537    2    4    7



В xslt я передаю в качестве параметра кол-во колонок, т.е. знаю, что в этот раз их будет 3 (Январь, Февраль и Март). Но как написать универсальный код рассчитанный на любое значение этого параметра?

Допустим, колонки в результирующем датасете, содержащие кол-во заказов по месяцам будут именоваться по определённому правилу, например так: QTY_1, QTY_2, QTY_3,..,QTY_N. И названия колонок в итоговой таблице тоже: К1, К2, К3,...,КN. (где N - кол-во колонок, т.е. месяцев, т.е. значение передаваемого в xslt параметра).

Как правильно организовать цикл. Может быть можно как то особым образом использовать тэг colspan ?
...
Рейтинг: 0 / 0
13.12.2017, 14:54
    #39569038
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
я хотел бы уточнить, что на входе в преобразование XSLT имеется XML подобный этому:

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<customers>
   <customer>
      <name>Ваня</name>
      <phone>(812)123-4567</phone>
   </customer>
   <customer>
      <name>Петя</name>
      <phone>(812)423-4537</phone>
   </customer>   
</customers>



а на выходу преобразования получается HTML.

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

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
<customers>
   <months_qty>n</months_qty>
   <customer>
      <name>Ваня</name>
      <phone>(812)123-4567</phone>
      <qty_1>5<qty_1>
      <qty_2>3<qty_2>
      <qty_3>2<qty_3>
      .....
      <qty_n>x<qty_n>
   </customer>
   <customer>
      <name>Петя</name>
      <phone>(812)423-4537</phone>
      <qty_1>2<qty_1>
      <qty_2>4<qty_2>
      <qty_3>7<qty_3>
      .....
      <qty_n>x<qty_n>
   </customer>   
   .................................
</customers>



Обработать узел </customer>, т.е. переменное кол-во заказчиков соответствующее строкам <TR> - не проблема, используем цикл <xsl:for-each>, а вот как обработать переменное кол-во заказов у каждого заказчика по месяцам, соответствующее ячейке в строке <TD> ?

В XSLT преобразовании я буду знать кол-во месяцев благодаря тегу <months_qty> из исходного XML.
...
Рейтинг: 0 / 0
13.12.2017, 17:20
    #39569178
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
Все просто. Циклы организовываются рекурсией, обращение к динамическому имени через конструкцию
Код: xml
1.
*[name() = ....]


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
  <xsl:template match="customers">
    <table border="1">
      <xsl:variable name="count" select="months_qty"/>
      <tr>
        <th>Name</th>
        <th>Phone</th>
        <xsl:call-template name="printHeaders">
          <xsl:with-param name="idx" select="$count"/>
        </xsl:call-template>
      </tr>
      <xsl:apply-templates select="customer">
        <xsl:with-param name="count" select="$count"/>
      </xsl:apply-templates>
    </table>
  </xsl:template>
  
  <xsl:template match="customer">
    <xsl:param name="count"/>
    <tr>
      <td>
        <xsl:value-of select="name"/>
      </td>
      <td>
        <xsl:value-of select="phone"/>
      </td>
      <xsl:call-template name="printData">
        <xsl:with-param name="idx" select="$count"/>
      </xsl:call-template>
    </tr>
  </xsl:template>
  
  <xsl:template name="printHeaders">
    <xsl:param name="idx"/>
    <xsl:if test="$idx > 0">
      <xsl:call-template name="printHeaders">
        <xsl:with-param name="idx" select="$idx - 1"/>
      </xsl:call-template>
      <th>
        <xsl:value-of select="concat('K', $idx)"/>
      </th>
    </xsl:if>
  </xsl:template>
  
  <xsl:template name="printData">
    <xsl:param name="idx"/>
    <xsl:if test="$idx > 0">
      <xsl:call-template name="printData">
        <xsl:with-param name="idx" select="$idx - 1"/>
      </xsl:call-template>
      <td>
        <xsl:value-of select="*[name() = concat('qty_', $idx)]"/>
      </td>
    </xsl:if>
  </xsl:template>

...
Рейтинг: 0 / 0
13.12.2017, 19:41
    #39569240
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
_Vasilisk_Все просто. Циклы организовываются рекурсией, обращение к динамическому имени через конструкцию [src xml]
*[name() = ....]


Спасибо! Попробую применить.
...
Рейтинг: 0 / 0
17.01.2018, 14:51
    #39585856
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
Проверил. Применил. Всё работает! Спасибо!

Правда есть свои нюансы.
Например, не понимает конкатенацию с '.', т.е. если в наименовании поля есть '.', то не работает.
...
Рейтинг: 0 / 0
17.01.2018, 14:52
    #39585858
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
или ещё:

$idx - 1

1-ку нужно обязательно через пробел, если написать так $idx-1, то ругается.
а вот $idx+1 нормально
...
Рейтинг: 0 / 0
17.01.2018, 15:08
    #39585866
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
verterНапример, не понимает конкатенацию с '.', т.е. если в наименовании поля есть '.', то не работает.У меня все работает
Код: xml
1.
2.
3.
4.
5.
<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Data.1>1</Data.1>
  <Data.2>2</Data.2>
</Root>

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">
  
  <xsl:output method="xml" encoding="UTF-8"/>
  
  <xsl:template match="/Root">
    <out>
      <one>
        <xsl:value-of select="*[name() = concat('Data.', 1)]"/>
      </one>
      <two>
        <xsl:variable name="idx-1" select="3"/>
        <xsl:value-of select="*[name() = concat('Data.', $idx-1 - 1)]"/>
      </two>
    </out>
  </xsl:template>
</xsl:stylesheet>

Код: xml
1.
2.
3.
4.
5.
<?xml version="1.0" encoding="UTF-8"?>
<out>
	<one>1</one>
	<two>2</two>
</out>


verter1-ку нужно обязательно через пробел, если написать так $idx-1, то ругается.Потому, что "-" - это валидный символ для идентификатора и идентификатор может его содержать. А "+" не может и потому происходит разрыв
...
Рейтинг: 0 / 0
18.01.2018, 14:31
    #39586452
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
_Vasilisk_,
и ещё очень неприятная вещь:

не работает форматирование ячейки Excel в цифровой формат x:num='', т.е. если написать так:

Код: html
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<xsl:template name="printData">
  <xsl:param name="idx"/>
  <xsl:if test="$idx > 0">
    <xsl:call-template name="printData">
      <xsl:with-param name="idx" select="$idx - 1"/>
    </xsl:call-template>
    <td x:num=''>
      <xsl:value-of select="*[name() = concat('qty_', $idx)]"/>
    </td>
  </xsl:if>
</xsl:template>



то выдаст ошибку Invalid XSL
...
Рейтинг: 0 / 0
18.01.2018, 15:45
    #39586513
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
verterто выдаст ошибку Invalid XSLУ Вас, конечно же определено пространство имен с алиасом "x"?
...
Рейтинг: 0 / 0
18.01.2018, 15:47
    #39586515
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
verterи ещё очень неприятная вещь:

не работает форматирование ячейки Excel в цифровой формат x:num='', т.е. если написать так:Может Вы перестанете кидать все свои проблемы в одну тему? Неумение работать с пространствами имен никак не касается возможности вывода узлов с динамическим именем
...
Рейтинг: 0 / 0
18.01.2018, 16:42
    #39586558
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
_Vasilisk_,

приношу свои извинения - действительно не определил пространство имён.
в общем виде я делаю так:

Код: html
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
<?xml version="1.0" encoding="Windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="windows-1251" method="html"/>

<xsl:template name="printHeaders">
...
</xsl:template>

<xsl:template name="printData">
...
  <td style='border-top:none' x:num=''>
     <xsl:value-of select="*[name() = concat('qty_', $idx)]"/>
  </td>
</xsl:template>

<xsl:template match="/">
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
...
<xsl:variable name="count" select="MONTHS_QTY"/>
...
<xsl:call-template name="printHeaders">
  <xsl:with-param name="idx" select="$count"/>
</xsl:call-template>
...
<xsl:call-template name="printData">
  <xsl:with-param name="idx" select="$count"/>
</xsl:call-template>   
...
</html>
</xsl:template>
</xsl:stylesheet>



Да, видно что я определяю пространство имён 'x' в главном шаблоне уже после объявления вызываемого шаблона "printData".
Поэтому то и возникает ошибка.
Но как мне тогда в "printData" определить это же пространство имён 'x'?
...
Рейтинг: 0 / 0
18.01.2018, 18:41
    #39586653
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
разобрался. нужно в самом начале объявить это пространство имён, вот так:

Код: html
1.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="urn:schemas-microsoft-com:office:excel">



причём тут тоже нужно оставить:

Код: html
1.
2.
<xsl:template match="/">
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
...
Рейтинг: 0 / 0
19.01.2018, 00:59
    #39586765
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
_Vasilisk_verterНапример, не понимает конкатенацию с '.', т.е. если в наименовании поля есть '.', то не работает.У меня все работает
Код: xml
1.
2.
3.
4.
5.
<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Data.1>1</Data.1>
  <Data.2>2</Data.2>
</Root>

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">
  
  <xsl:output method="xml" encoding="UTF-8"/>
  
  <xsl:template match="/Root">
    <out>
      <one>
        <xsl:value-of select="*[name() = concat('Data.', 1)]"/>
      </one>
      <two>
        <xsl:variable name="idx-1" select="3"/>
        <xsl:value-of select="*[name() = concat('Data.', $idx-1 - 1)]"/>
      </two>
    </out>
  </xsl:template>
</xsl:stylesheet>

Код: xml
1.
2.
3.
4.
5.
<?xml version="1.0" encoding="UTF-8"?>
<out>
	<one>1</one>
	<two>2</two>
</out>





а попробуйте будет ли у вас работать если вот так:

Код: html
1.
<xsl:value-of select="*[name() = concat('Data', '.', $idx-1 - 1)]"/>
...
Рейтинг: 0 / 0
19.01.2018, 15:06
    #39587146
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
verterа попробуйте будет ли у вас работать если вот так:
Код: xml
1.
<xsl:value-of select="*[name() = concat('Data', '.', $idx-1 - 1)]"/>

Проверил.
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  <xsl:template match="/Root">
    <out>
      <one>
        <xsl:value-of select="*[name() = concat('Data', '.', 1)]"/>
      </one>
      <two>
        <xsl:variable name="idx-1" select="3"/>
        <xsl:value-of select="*[name() = concat('Data', '.', $idx-1 - 1)]"/>
      </two>
    </out>
  </xsl:template>

Как и следовало ожидать - работает
...
Рейтинг: 0 / 0
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице? / 14 сообщений из 14, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]