powered by simpleCommunicator - 2.0.30     © 2024 Programmizd 02
Map
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
14 сообщений из 14, страница 1 из 1
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39568914
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Конечно на ум сразу приходит использовать цикл:

Код: 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
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39569038
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я хотел бы уточнить, что на входе в преобразование 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
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39569178
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Все просто. Циклы организовываются рекурсией, обращение к динамическому имени через конструкцию
Код: 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
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39569240
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_Все просто. Циклы организовываются рекурсией, обращение к динамическому имени через конструкцию [src xml]
*[name() = ....]


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

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

$idx - 1

1-ку нужно обязательно через пробел, если написать так $idx-1, то ругается.
а вот $idx+1 нормально
...
Рейтинг: 0 / 0
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39585866
Фотография _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>


verter1-ку нужно обязательно через пробел, если написать так $idx-1, то ругается.Потому, что "-" - это валидный символ для идентификатора и идентификатор может его содержать. А "+" не может и потому происходит разрыв
...
Рейтинг: 0 / 0
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39586452
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_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
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39586513
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
verterто выдаст ошибку Invalid XSLУ Вас, конечно же определено пространство имен с алиасом "x"?
...
Рейтинг: 0 / 0
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39586515
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
verterи ещё очень неприятная вещь:

не работает форматирование ячейки Excel в цифровой формат x:num='', т.е. если написать так:Может Вы перестанете кидать все свои проблемы в одну тему? Неумение работать с пространствами имен никак не касается возможности вывода узлов с динамическим именем
...
Рейтинг: 0 / 0
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39586558
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_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
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39586653
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
разобрался. нужно в самом начале объявить это пространство имён, вот так:

Код: 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
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39586765
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_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
Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
    #39587146
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
14 сообщений из 14, страница 1 из 1
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Как в xslt преобразовать заранее неизвестное кол-во колонок в таблице?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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