Гость
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Файл стиля XSLT / 7 сообщений из 7, страница 1 из 1
02.02.2022, 11:30
    #40131198
eliasum
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Файл стиля XSLT
Добрый день! Есть входной xml файл:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
<Item key="k1" title="t1" description="d1">
  <Adress title="t2" description="d2">
    <Template key="01,09-10,21" title="d3" description="d3">
      <Channel title="t4" description="d4">
        <Template key="1-3" title="t5" description="d5" />
      </Channel>
    </Template>
  </Adress>
</Item>



Его нужно трансформировать к такому виду:
Код: 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.
<Item key="k1" title="t1" description="d1">
  <Adress title="t2" description="d2">
    <Item key="01" title="d3" description="d3">
      <Channel title="t4" description="d4">
        <Item key="1" title="t5" description="d5" />
        <Item key="2" title="t5" description="d5" />
        <Item key="3" title="t5" description="d5" />
      </Channel>
    </Item>
    <Item key="09" title="d3" description="d3">
      <Channel title="t4" description="d4">
        <Item key="1" title="t5" description="d5" />
        <Item key="2" title="t5" description="d5" />
        <Item key="3" title="t5" description="d5" />
      </Channel>
    </Item>
    <Item key="10" title="d3" description="d3">
      <Channel title="t4" description="d4">
        <Item key="1" title="t5" description="d5" />
        <Item key="2" title="t5" description="d5" />
        <Item key="3" title="t5" description="d5" />
      </Channel>
    </Item>
    <Item key="21" title="d3" description="d3">
      <Channel title="t4" description="d4">
        <Item key="1" title="t5" description="d5" />
        <Item key="2" title="t5" description="d5" />
        <Item key="3" title="t5" description="d5" />
      </Channel>
    </Item>
  </Adress>
</Item>



На данный момент написал такой файл стилей:
Код: 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.
55.
56.
57.
58.
59.
60.
61.
<?xml version="1.0" encoding="utf-8"?>
 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  
    <!--Identity template-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
        
    <xsl:template name="tokenize">
        <xsl:param name="text"/>
        <xsl:param name="delimiter" select="','"/>
        <xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
            <xsl:if test="$token and not(contains($token, '-'))">
                <Item key="{$token}"/>
            </xsl:if>
            
            <!--enumerate-->
            <xsl:if test="contains($token, '-')">
                <xsl:call-template name="enumerate">
                    <xsl:with-param name="start" select="substring($token, 1, 2)"/>
                    <xsl:with-param name="end" select="substring($token, 4, 5)"/>
                </xsl:call-template>
            </xsl:if>
            <xsl:text>
</xsl:text>
            
            <xsl:if test="contains($text, $delimiter)">
                <!-- recursive call -->
                <xsl:call-template name="tokenize">
                    <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
                </xsl:call-template>                
            </xsl:if>
    </xsl:template>
    
    <xsl:template name="enumerate">
        <xsl:param name="start"/>
        <xsl:param name="end"/>
        <xsl:if test="$start">
            <Item key="{$start}"/>
        </xsl:if>
        <xsl:if test="$start &lt; $end">
            <xsl:text>
</xsl:text>
            <xsl:call-template name="enumerate">
                <xsl:with-param name="start" select="format-number($start + 1,'00')"/>
                <xsl:with-param name="end" select="format-number($end,'00')"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    <xsl:template match="Template">
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="@key"/>
            </xsl:call-template>    
    </xsl:template> 
    
</xsl:stylesheet>



Не получается сделать обход правильно для нужного числа новых тегов Item и соответствующих значений атрибутов key.
P.S. XSLT Version:1.0, XSLT Processor:Microsoft
...
Рейтинг: 0 / 0
02.02.2022, 12:29
    #40131219
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Файл стиля XSLT
Как минимум, общий шаблон
eliasum
Код: xml
1.
<xsl:template match="@*|node()">

должен быть самым последним
...
Рейтинг: 0 / 0
02.02.2022, 13:21
    #40131232
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Файл стиля XSLT
Если поисправлять остальные ошибки (в частности, неправильное формирование Item) и провести небольшую оптимизацию, то получится вот так
Код: 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.
55.
56.
57.
58.
59.
60.
61.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    
    <xsl:template match="Template">
        <xsl:call-template name="tokenize">
            <xsl:with-param name="text" select="concat(@key, ',')"/>
            <xsl:with-param name="delimiter" select="','"/>
        </xsl:call-template>    
    </xsl:template> 
    
    <!-- Skip process Template/@key -->
    <xsl:template match="Template/@key"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template name="tokenize">
        <xsl:param name="text"/>
        <xsl:param name="delimiter" select="','"/>
        <xsl:variable name="token" select="substring-before($text, $delimiter)" />
        <xsl:if test="$token != ''">
            <xsl:choose>
                <xsl:when test="contains($token, '-')">
                    <xsl:call-template name="enumerate">
                        <xsl:with-param name="start" select="substring-before($token, '-')"/>
                        <xsl:with-param name="end" select="substring-after($token, '-')"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:call-template name="enumerate">
                        <xsl:with-param name="start" select="$token"/>
                        <xsl:with-param name="end" select="$token"/>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
            <!-- recursive call -->
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
                <xsl:with-param name="delimiter" select="$delimiter"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    <xsl:template name="enumerate">
        <xsl:param name="start"/>
        <xsl:param name="end"/>
        <xsl:if test="$start &lt;= $end">
            <Item key="{number($start)}">
                <!-- Copy attributes -->
                <xsl:apply-templates select="@*"/>
            </Item>
            <xsl:call-template name="enumerate">
                <xsl:with-param name="start" select="$start + 1"/>
                <xsl:with-param name="end" select="$end"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

...
Рейтинг: 0 / 0
02.02.2022, 13:57
    #40131238
eliasum
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Файл стиля XSLT
_Vasilisk_, спасибо за ответ!

Ваш код трансформирует в такой файл xml:
Код: xml
1.
2.
3.
4.
5.
<Item key="k1" title="t1" description="d1">
  <Adress title="t2" description="d2">
	<Item key="1" title="d3" description="d3" /><Item key="9" title="d3" description="d3" /><Item key="10" title="d3" description="d3" /><Item key="21" title="d3" description="d3" />
  </Adress>
</Item>



https://www.xsltfiddle.liberty-development.net/pNP54dX
...
Рейтинг: 0 / 0
02.02.2022, 14:08
    #40131242
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Файл стиля XSLT
eliasum
Ваш код трансформирует в такой файл xml:
Опять 25. XML - это НЕ ТЕКСТОВЫЙ формат. И просматривать его в блокноте нельзя. Откройте любой браузер и смотрите там
...
Рейтинг: 0 / 0
02.02.2022, 14:17
    #40131245
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Файл стиля XSLT
А для обработки Channel нужно изменить

_Vasilisk_
Код: xml
1.
2.
3.
4.
<Item key="{number($start)}">
  <!-- Copy attributes -->
  <xsl:apply-templates select="@*"/>
</Item>

на
Код: xml
1.
2.
3.
4.
5.
6.
<Item key="{number($start)}">
  <!-- Copy attributes -->
  <xsl:apply-templates select="@*"/>
  <!-- Process childs -->
  <xsl:apply-templates/>
</Item>
...
Рейтинг: 0 / 0
02.02.2022, 14:25
    #40131249
eliasum
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Файл стиля XSLT
_Vasilisk_, спасибо большое, всё работает!
...
Рейтинг: 0 / 0
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Файл стиля XSLT / 7 сообщений из 7, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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