powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / XML+XSLT-> txt
11 сообщений из 11, страница 1 из 1
XML+XSLT-> txt
    #37471409
sasha9001
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Исходный xml выглядит следующим образом
<?xml version="1.0" encoding="iso-8859-1" ?>
- <data>
<item id="1" category="1" subcategory="a">1</item>
<item id="8" category="3" subcategory="d">2</item>
<item id="2" category="2" subcategory="b">3</item>
<item id="7" category="1" subcategory="b">4</item>
<item id="3" category="1" subcategory="c">5</item>
<item id="6" category="2" subcategory="a">6</item>
<item id="4" category="2" subcategory="e">7</item>
<item id="5" category="3" subcategory="d">8</item>
<category id="1">Категория 1</category>
<category id="2">Категория 2</category>
<category id="3">Категория 3</category>
<subcategory id="a">Подкатегория 1</subcategory>
<subcategory id="b">Подкатегория 2</subcategory>
<subcategory id="c">Подкатегория 3</subcategory>
<subcategory id="d">Подкатегория 4</subcategory>
<subcategory id="e">Подкатегория 5</subcategory>
</data>

Необходимо с помощью XSLT 1.0 преобразовать его в текстовый файл вида
Категория 1
Подкатегория 1
id число
1 1
Подкатегория 2
id число
7 4
Подкатегория 3
id число
3 4
Категория 2
Подкатегория 1
id число
6 6
Подкатегория 2
id число
2 3
Подкатегория 5
id число
4 7
и т.д.

XSLT может содержать программный текст на C#.

Дополнительное требование - разбивка выходного файла на страницы специальным разделителем (не принципиально каким именно) по принципу - страница не может содержать более N итемов, разделитель может находиться только перед заголовками категорий или подкатегорий (заранее известно, что количество итемов в подкатегории не может превысить N). Т.е. на одной странице может находиться и 1, и N итемов; и 1, и несколько категорий/подкатегорий.

С XML до сих пор занимался только парсингом. С XSLT до сих пор не связывался вообще. Можно ли преобразовать исходный XML только средствами XSLT или нужно предварительно преобразовывать сам XML (во втором случае задача создания XSLT существенно упрощается, я так понимаю, но задача именно на XSLT, т.е. XSLT должна быть использована по максимуму)?

Если можно, то, пожалуйста, ткните носом куда рыть.
1. Способ группировки с помощью XSLT я нашел, но, как понял, он позволяет выполнить группировку только по одному уровню (в моем случае это может быть category+subcategory). Тогда возникает вопрос: как тогда избавиться от имени категории при разбивке этой связки при повторении.
2. Можно ли только с помощью XSLT связать атрибут в одном теге с его расшифровкой в другом, т.е. выполнить внутренний запрос к XML. Желательно, конечно, минимизировать количество этих запросов.
3. С разбивкой на страницы - совсем завал. Во-первых, как пересчитать итемы, да еще и вернуться назад при обходе дерева. И вообще, как всунуть в дерево несуществующую сущность (страницу).

Заранее спасибо за помощь бедному студенту. И простите за сумбурное изложение, но горю. :(
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37472512
mage.lan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sasha9001,

пока простой вариант, чтобы вы поняли как XSL работает. Для пагинации надо немного изменить подход, попозже напишу...

Код: plaintext
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.
<?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" indent="yes" method="text" />
	
<xsl:variable name="cat" select="/data/category" />
<xsl:variable name="items" select="/data/item" />
<xsl:variable name="sub" select="/data/subcategory" />
<xsl:template match="/">
	<xsl:apply-templates select="$cat" />
</xsl:template>
<xsl:template match="category">
	<xsl:value-of select="text()" />
	<xsl:text xml:space="preserve">
</xsl:text>
	<xsl:apply-templates select="$items[@category=current()/@id]">
		<xsl:sort select="@subcategory" />
	</xsl:apply-templates>
</xsl:template>
<xsl:template match="item">
	<xsl:value-of select="$sub[@id=current()/@subcategory]/text()" />
	<xsl:text xml:space="preserve">
id число
</xsl:text>
	<xsl:value-of select="concat(@id, ' ', text())" />
	<xsl:text xml:space="preserve">
</xsl:text>
</xsl:template>
</xsl:stylesheet>
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37472773
mage.lan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
этот вариант помудренее, расчитан на мелкомягкий парсер, о чем говорит выделение фрагмента-дерева msxsl:node-set($_tree)/item, на других парсерах - читайте доки, функция будет называться похоже.
Код: plaintext
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.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl=" http://www.w3.org/1999/XSL/Transform"  xmlns:msxsl="urn:schemas-microsoft-com:xslt">
	<xsl:output encoding="windows-1251" indent="yes" method="text" />
	
<xsl:variable name="lines-per-page" select="9" />
<xsl:variable name="cat" select="/data/category" />
<xsl:variable name="items" select="/data/item" />
<xsl:variable name="sub" select="/data/subcategory" />
<xsl:variable name="_tree">
	<xsl:for-each select="$cat">
		<item line="1">
			<print>
				<xsl:value-of select="text()" />
			</print>
		</item>
		<xsl:for-each select="$items[@category=current()/@id]">
			<xsl:sort select="@subcategory" />
			
			<item line="3">
				<print>
					<xsl:value-of select="$sub[@id=current()/@subcategory]/text()" />
				</print>
				<print>
					<xsl:text>id число</xsl:text>
				</print>
				<print>
					<xsl:value-of select="concat(@id, ' ', text())" />
				</print>
			</item> 
		</xsl:for-each>
	</xsl:for-each>
</xsl:variable>
<xsl:variable name="tree" select="msxsl:node-set($_tree)/item" />

<xsl:template match="/">
	<xsl:call-template name="snake" />
</xsl:template>

<xsl:template name="snake">
	<xsl:param name="item" select="$tree[1]" />
	<xsl:param name="break-pos" select="0" />

	<xsl:variable name="cur-line" select="sum($item/preceding-sibling::item/@line)" />
	<xsl:variable name="cur-line-x" select="$cur-line - $break-pos" />
	<xsl:variable name="has-break" select="($cur-line-x >= $lines-per-page) or (( $cur-line-x + $item/@line ) > $lines-per-page )" />

	<xsl:if test="$has-break">
		<xsl:text xml:space="preserve">--- --- --- page break
</xsl:text>
	</xsl:if>

	<xsl:for-each select="$item/print">
		<xsl:value-of select="text()" />
		<xsl:text xml:space="preserve">
</xsl:text>
	</xsl:for-each>
	<xsl:if test="$item/following-sibling::item">
		<xsl:call-template name="snake">
			<xsl:with-param name="item" select="$item/following-sibling::item[1]" />
			<xsl:with-param name="break-pos">
				<xsl:choose>
					<xsl:when test="$has-break">
						<xsl:value-of select="$cur-line" />
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="$break-pos" />
					</xsl:otherwise>
				</xsl:choose>
			</xsl:with-param>
		</xsl:call-template>
	</xsl:if>
</xsl:template>
</xsl:stylesheet>
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37472778
mage.lan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
<xsl:variable name="has-break" select="($cur-line-x = $lines-per-page) or (( $cur-line-x + $item/@line ) &gt; $lines-per-page )" />
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37473461
sasha9001
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
mage.lan ,

спасибо огромное. Пойду скармливать мой XML.
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37473664
sasha9001
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Как оказалось, рано радовался.
Оказывается, эта зараза не группирует по подкатегории.

На выходе получаю вот такое:
Категория 1
Подкатегория 1
id число
1 1
Подкатегория 2
id число
15 4
Подкатегория 2
id число
10 9
Подкатегория 2
id число
46 9
Подкатегория 2
id число
98 9

вместо:
Категория 1
Подкатегория 1
id число
1 1
15 4
10 9
46 9
98 9

Но все равно спасибо. Будем разбираться дальше.

Вот чего совсем не понял, так это откуда взялся отступ. :)
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37475792
mage.lan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sasha9001,

вот что значит дать плохой пример, меня больше пагинация беспокоила.

Вам надо чуть сложнее генерировать переменную tree, заменяем этим куском...

Код: plaintext
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.
<xsl:key name="i" match="/data/item" use="concat(@category,@subcategory)" />	
<xsl:variable name="_tree">
	<xsl:for-each select="$cat">
		<item line="1">
			<print>
				<xsl:value-of select="text()" />
			</print>
		</item>
		<xsl:for-each select="$items[@category=current()/@id][generate-id()=generate-id(key('i', concat(@category,@subcategory)))]">
			<xsl:sort select="@subcategory" />

			<xsl:variable name="sub-set" select="key('i', concat(current()/@category,current()/@subcategory))" />			
			<item line="{count( $sub-set ) + 2}">
				<print>
					<xsl:value-of select="$sub[@id=current()/@subcategory]/text()" />
				</print>
				<print>
					<xsl:text>id число</xsl:text>
				</print>
				<xsl:for-each select="$sub-set">
					<xsl:sort select="@id" data-type="number" />
					<print>
						<xsl:value-of select="concat(@id, ' ', text())" />
					</print>
				</xsl:for-each>
			</item> 
		</xsl:for-each>
	</xsl:for-each>
</xsl:variable>
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37482733
sasha9001
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А можно ли ввести сортировку и по категориям, и по подкатегориям?
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37482751
mage.lan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sasha9001,

по категориям вообще без проблем, добовляем после
<xsl:for-each select="$cat">
строку
<xsl:sort select="text()" />


сабкатегории сортируются по id, с ними сложнее, попробуйте поменять:
<xsl:sort select="@subcategory" />
на
<xsl:sort select="$sub[@id=current()/@subcategory]/text()" />
не уверен, что будет работать (пробовать некогда), но вдруг.
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37483068
sasha9001
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
По подкатегории как раз никакой проблемы. И я как раз по id и отсортировал.
А вот по категории как раз проблема. Как раз подобное попробовал (только сортировать пытался напрямую по $cat). Валидатор тут же сказал, что xsl:sort в этом месте использовать нельзя.

Сейчас попробую Ваш вариант. За идею огромное спасибо.

ПС. Вот сейчас начал еще биться над тем, чтобы обойтись без перестроения дерева в переменной. Пока с идеями туго. Никак не могу придумать, как рекурсивно вызывать шаблон, считая при этом итемы. По идее, было бы красиво обойти xml за один раз.
...
Рейтинг: 0 / 0
XML+XSLT-> txt
    #37483357
mage.lan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sasha9001,

Это без меня, развлекайьесь.

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


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