powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Многоуровневая группировка
9 сообщений из 9, страница 1 из 1
Многоуровневая группировка
    #36490701
mrxiii
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Привет! Есть вопрос по многоуровневой группировке.

Обрабатываемый набор данных выглядит следующим образом:

F01F02F03F04F05Город 1Компания АСотрудник А1Контракт А1-110Город 1Компания АСотрудник А2Контракт А2-120Город 1Компания АСотрудник А2Контракт А2-230Город 1Компания БСотрудник Б1Контракт Б1-140Город 1Компания БСотрудник Б1Контракт Б1-250Город 1Компания БСотрудник Б2Контракт Б2-160Город 2Компания ВСотрудник В1Контракт В1-170Город 2Компания ВСотрудник В1Контракт В1-280Город 2Компания ГСотрудник Г1Контракт Г1-190
Входной XML:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<DATA>
<DataSet>
<DATASET_ROW><F01>Город  1 </F01><F02>Компания А</F02><F03>Сотрудник А1</F03><F04>Контракт А1- 1 </F04><F05> 10 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  1 </F01><F02>Компания А</F02><F03>Сотрудник А2</F03><F04>Контракт А2- 1 </F04><F05> 20 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  1 </F01><F02>Компания А</F02><F03>Сотрудник А2</F03><F04>Контракт А2- 2 </F04><F05> 30 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  1 </F01><F02>Компания Б</F02><F03>Сотрудник Б1</F03><F04>Контракт Б1- 1 </F04><F05> 40 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  1 </F01><F02>Компания Б</F02><F03>Сотрудник Б1</F03><F04>Контракт Б1- 2 </F04><F05> 50 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  1 </F01><F02>Компания Б</F02><F03>Сотрудник Б2</F03><F04>Контракт Б2- 1 </F04><F05> 60 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  2 </F01><F02>Компания В</F02><F03>Сотрудник В1</F03><F04>Контракт В1- 1 </F04><F05> 70 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  2 </F01><F02>Компания В</F02><F03>Сотрудник В1</F03><F04>Контракт В1- 2 </F04><F05> 80 </F05></DATASET_ROW>
<DATASET_ROW><F01>Город  2 </F01><F02>Компания Г</F02><F03>Сотрудник Г1</F03><F04>Контракт Г1- 1 </F04><F05> 90 </F05></DATASET_ROW>
</DataSet>
</DATA>

На выходе нужно получить Excel-отчёт с приложенного изображения.

С простой группировкой проблем не возникало, делал примерно так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
<xsl:choose>
	<xsl:when test="position()=1">
		<ss:Cell>
			<xsl:if test="count(current-group())>1">
				<xsl:attribute name="ss:MergeDown"><xsl:value-of select="count(current-group())-1"/></xsl:attribute>
			</xsl:if>
			<ss:Data ss:Type="String">
				<xsl:value-of select="string(F01)"/>
			</ss:Data>
		</ss:Cell>
		<ss:Cell>
			<ss:Data ss:Type="Number">
				<xsl:value-of select="position()"/>
			</ss:Data>
		</ss:Cell>
	</xsl:when>
	<xsl:otherwise>
		<ss:Cell ss:Index="2">
			<ss:Data ss:Type="Number">
				<xsl:value-of select="position()"/>
			</ss:Data>
		</ss:Cell>
	</xsl:otherwise>
</xsl:choose>

Но как быть, когда число уровней группировки увеличивается?
Подскажите плз, в каком направлении копать?
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36491298
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то так
Код: 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:template match="DATASET_ROW">
    <xsl:if test="not(preceding-sibling::DATASET_ROW[F01 = current()/F01])">
      <DATASET_ROW>
        <F01>
          <xsl:apply-templates select="F01"/>
          <xsl:apply-templates select="../DATASET_ROW[F01 = current()/F01]" mode="F02"/>
        </F01>
      </DATASET_ROW>
    </xsl:if>
  </xsl:template>

  <xsl:template match="DATASET_ROW" mode="F02">
    <xsl:if test="not(preceding-sibling::DATASET_ROW[
      F01 = current()/F01 and F02 = current()/F02])">
      <F02>
        <xsl:apply-templates select="F02"/>
      </F02>
    </xsl:if>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:value-of select="."/>
  </xsl:template>

  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
Думаю, идея понятна.

С уважением, Vasilisk
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36493351
mrxiii
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Vasilisk, спасибо! Но не совсем понятно.
Результат будет выглядеть примерно так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
	<DataSet>
		<DATASET_ROW>
			<F01>Город  1 </F01>
			<F02>Компания А</F02>
			<F02>Компания Б</F02>
		</DATASET_ROW>
		<DATASET_ROW>
			<F01>Город  2 </F01>
			<F02>Компания В</F02>
			<F02>Компания Г</F02>
		</DATASET_ROW>
	</DataSet>
</DATA>
Как от такого набора данных перейти к группировке строк как в отчете?

Дело даже не в подготовке формата вывода данных (это, допустим, можно сделать на уровне SQL), а в составлении XSL, форматирующего эти данные в приведённый вид – с многоуровневой построчной группировкой и промежуточными итогами.
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36493470
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я в Excel не силен. Я показал Вам многоуровневую группировку. Я не думаю, что используя мой код потребуется много труда для перевода его в Excel

С уважением, Vasilisk
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36494013
mrxiii
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Vasilisk, а насколько реализуема такого рода логика?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
ЕСЛИ строка содержит первое вхождение значения 'Город'
  ТО [количество строк 'Контракт' в текущем 'Городе' + количество 'Компаний' в текущем 'Городе' (подсуммы)],
     [количество строк 'Контракт' в текущей 'Компании'],
     [количество строк 'Контракт' в текущем 'Сотруднике']
     
ЕСЛИ строка содержит первое вхождение значения 'Компания'
   И строка Не содержит первое вхождение значения 'Города'
  ТО [количество строк 'Контракт' в текущей 'Компании'],
     [количество строк 'Контракт' в текущем 'Сотруднике']
   
ЕСЛИ строка содержит первое вхождение значения 'Сотрудник'
   И Не содержит первое вхождение значений 'Город', 'Компания'
  ТО [количество строк 'Контракт' в текущем 'Сотруднике']
  
ЕСЛИ строка не содержит первых вхождений значений 'Город', 'Компания', 'Сотрудник'
  ТО []
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36495630
mrxiii
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Решение:

Код: 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.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
			      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			      xmlns:xs="http://www.w3.org/2001/XMLSchema" 
			      xmlns="urn:schemas-microsoft-com:office:spreadsheet" 
			      xmlns:o="urn:schemas-microsoft-com:office:office" 
			      xmlns:x="urn:schemas-microsoft-com:office:excel" 
			      xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" 
			      xmlns:html="http://www.w3.org/TR/REC-html40" 
			      xmlns:xdoxslt="http://www.oracle.com/XSL/Transform/java/oracle.apps.xdo.template.rtf.XSLTFunctions"
			      exclude-result-prefixes="xs xsi xsl">
	<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
	<xsl:template match="/">
		<xsl:processing-instruction name="mso-application">
			<xsl:text>progid="Excel.Sheet"</xsl:text>
		</xsl:processing-instruction>
		<Workbook>
			<xsl:attribute name="xsi:schemaLocation"><xsl:value-of select="' '"/></xsl:attribute>
			<!-- Переменная содержит раздел с данными -->
			<xsl:variable name="DataSet" select=".//DataSet"/>
			<!-- В данной переменной содержится статическая шапка отчета -->
			<xsl:variable name="ExpandedRowCount" select="number(1000000)"/>
			<!-- Переменная содержит общее количество строк, в Dataset -->
			<xsl:variable name="All_Records" select="count(.//DataSet/DATASET_ROW)"/>
			<o:DocumentProperties ... />
			<x:ExcelWorkbook ... />
			<Styles ... />
			<Worksheet>
				<!-- Название вкладки -->
				<xsl:attribute name="ss:Name"><xsl:value-of select="'Отчет №'"/></xsl:attribute>
				<Table>
					<xsl:attribute name="ss:ExpandedRowCount"><xsl:value-of select="$ExpandedRowCount"/></xsl:attribute>
					<xsl:attribute name="x:FullRows"><xsl:value-of select="1"/></xsl:attribute>
					<xsl:attribute name="x:FullColumns"><xsl:value-of select="1"/></xsl:attribute>
					<!-- Количество и ширина столбцов -->
					<xsl:attribute name="ss:ExpandedColumnCount"><xsl:value-of select="5"/></xsl:attribute>
					<Column ss:AutoFitWidth="0" ss:Width="100"/>
					<Column ss:AutoFitWidth="0" ss:Width="100"/>
					<Column ss:AutoFitWidth="0" ss:Width="100"/>
					<Column ss:AutoFitWidth="0" ss:Width="100"/>
					<Column ss:AutoFitWidth="0" ss:Width="100"/>
					<!-- Заголовок -->
					<!-- Наименования столбцов -->
					<Row ss:AutoFitHeight="1">
						<Cell ss:StyleID="head-c-txt">
							<Data ss:Type="String">Город</Data>
						</Cell>
						<Cell ss:StyleID="head-c-txt">
							<Data ss:Type="String">Компания</Data>
						</Cell>
						<Cell ss:StyleID="head-c-txt">
							<Data ss:Type="String">Сотрудник</Data>
						</Cell>
						<Cell ss:StyleID="head-c-txt">
							<Data ss:Type="String">Контракт</Data>
						</Cell>
						<Cell ss:StyleID="head-c-txt">
							<Data ss:Type="String">Сумма</Data>
						</Cell>
					</Row>
					<!-- Тело таблицы -->
					<xsl:if test="$All_Records > 0">
						<!-- Группировка по Городу -->
						<xsl:for-each-group select=".//DataSet/DATASET_ROW" group-by="F01">
							<xsl:variable name="F01" select="current-grouping-key()"/>
							<xsl:variable name="F01_c" select="count(current-group())"/>
							<!-- Группировка по Компании -->
							<xsl:for-each-group select="current-group()" group-by="F02">
								<xsl:variable name="F02" select="current-grouping-key()"/>
								<xsl:variable name="F02_c" select="count(current-group())"/>
								<xsl:variable name="F02_l" select="last()"/>
								<!-- Группировка по Сотруднику -->
								<xsl:for-each-group select="current-group()" group-by="F03">
									<xsl:variable name="F03_c" select="count(current-group())"/>
									<!-- Вывод данных -->
									<xsl:for-each select="current-group()">
										<Row>
											<xsl:choose>
												<xsl:when test='F01=preceding-sibling::DATASET_ROW[position()=1]/F01'>
													<xsl:choose>
														<xsl:when test='F02=preceding-sibling::DATASET_ROW[position()=1]/F02'>
															<xsl:choose>
																<xsl:when test='F03=preceding-sibling::DATASET_ROW[position()=1]/F03'>
																	<Cell ss:StyleID="body-l-txt-wrap" ss:Index="4">
																		<Data ss:Type="String">
																			<xsl:value-of select="F04"/>
																		</Data>
																	</Cell>
																</xsl:when>
																<xsl:otherwise>
																	<Cell ss:StyleID="body-l-txt-wrap" ss:Index="3">
																		<xsl:if test="$F03_c > 1">
																			<xsl:attribute name="ss:MergeDown"><xsl:value-of select="$F03_c - 1"/></xsl:attribute>
																		</xsl:if>
																		<Data ss:Type="String">
																			<xsl:value-of select="F03"/>
																		</Data>
																	</Cell>
																	<Cell ss:StyleID="body-l-txt-wrap">
																		<Data ss:Type="String">
																			<xsl:value-of select="F04"/>
																		</Data>
																	</Cell>
																</xsl:otherwise>
															</xsl:choose>
														</xsl:when>
														<xsl:otherwise>
															<Cell ss:StyleID="body-l-txt-wrap" ss:Index="2">
																<xsl:if test="$F02_c > 1">
																	<xsl:attribute name="ss:MergeDown"><xsl:value-of select="$F02_c - 1"/></xsl:attribute>
																</xsl:if>
																<Data ss:Type="String">
																	<xsl:value-of select="F02"/>
																</Data>
															</Cell>
															<Cell ss:StyleID="body-l-txt-wrap">
																<xsl:if test="$F03_c > 1">
																	<xsl:attribute name="ss:MergeDown"><xsl:value-of select="$F03_c - 1"/></xsl:attribute>
																</xsl:if>
																<Data ss:Type="String">
																	<xsl:value-of select="F03"/>
																</Data>
															</Cell>
															<Cell ss:StyleID="body-l-txt-wrap">
																<Data ss:Type="String">
																	<xsl:value-of select="F04"/>
																</Data>
															</Cell>
														</xsl:otherwise>
													</xsl:choose>
												</xsl:when>
												<xsl:otherwise>
													<Cell ss:StyleID="body-l-txt-wrap">
														<xsl:if test="$F01_c + $F02_l > 1">
															<xsl:attribute name="ss:MergeDown"><xsl:value-of select="$F01_c + $F02_l - 1"/></xsl:attribute>
														</xsl:if>
														<Data ss:Type="String">
															<xsl:value-of select="F01"/>
														</Data>
													</Cell>
													<Cell ss:StyleID="body-l-txt-wrap">
														<xsl:if test="$F02_c > 1">
															<xsl:attribute name="ss:MergeDown"><xsl:value-of select="$F02_c - 1"/></xsl:attribute>
														</xsl:if>
														<Data ss:Type="String">
															<xsl:value-of select="F02"/>
														</Data>
													</Cell>
													<Cell ss:StyleID="body-l-txt-wrap">
														<xsl:if test="$F03_c > 1">
															<xsl:attribute name="ss:MergeDown"><xsl:value-of select="$F03_c - 1"/></xsl:attribute>
														</xsl:if>
														<Data ss:Type="String">
															<xsl:value-of select="F03"/>
														</Data>
													</Cell>
													<Cell ss:StyleID="body-l-txt-wrap">
														<Data ss:Type="String">
															<xsl:value-of select="F04"/>
														</Data>
													</Cell>
												</xsl:otherwise>
											</xsl:choose>
											<Cell ss:StyleID="body-r-txt">
												<xsl:if test="string(F05) != ''">
													<Data ss:Type="Number">
														<xsl:value-of select="F05"/>
													</Data>
												</xsl:if>
											</Cell>
										</Row>
									</xsl:for-each>
									<!-- Итого по Сотруднику -->
								</xsl:for-each-group>
								<!-- Итого по Компании -->
								<Row>
									<Cell ss:StyleID="subsum-l-txt" ss:Index="2">
										<Data ss:Type="String">
											<xsl:value-of select="$F02"/>
											<xsl:value-of select="' Итого'"/>
										</Data>
									</Cell>
									<Cell ss:StyleID="subsum-r-txt">
										<Data ss:Type="Number">
											<xsl:value-of select="count(distinct-values(current-group()/F03[.!='']))"/>
										</Data>
									</Cell>
									<Cell ss:StyleID="subsum-r-txt">
										<Data ss:Type="Number">
											<xsl:value-of select="count(current-group()/F04[.!=''])"/>
										</Data>
									</Cell>
									<Cell ss:StyleID="subsum-r-txt">
										<Data ss:Type="Number">
											<xsl:value-of select="sum(current-group()/F05[.!=''])"/>
										</Data>
									</Cell>
								</Row>
							</xsl:for-each-group>
							<!-- Итого по Городу -->
							<Row>
								<Cell ss:StyleID="subsum-l-txt" ss:MergeAcross="1">
									<Data ss:Type="String">
										<xsl:value-of select="$F01"/>
										<xsl:value-of select="' Итого'"/>
									</Data>
								</Cell>
								<Cell ss:StyleID="subsum-r-txt">
									<Data ss:Type="Number">
										<xsl:value-of select="count(distinct-values(current-group()/F03[.!='']))"/>
									</Data>
								</Cell>
								<Cell ss:StyleID="subsum-r-txt">
									<Data ss:Type="Number">
										<xsl:value-of select="count(current-group()/F04[.!=''])"/>
									</Data>
								</Cell>
								<Cell ss:StyleID="subsum-r-txt">
									<Data ss:Type="Number">
										<xsl:value-of select="sum(current-group()/F05[.!=''])"/>
									</Data>
								</Cell>
							</Row>
						</xsl:for-each-group>
						<!-- Общий итог -->
						<Row>
							<Cell ss:StyleID="sum-l-txt" ss:MergeAcross="1">
								<Data ss:Type="String">
									<xsl:value-of select="'Общий итог'"/>
								</Data>
							</Cell>
							<Cell ss:StyleID="sum-r-txt">
								<Data ss:Type="Number">
									<xsl:value-of select="count(distinct-values($DataSet/DATASET_ROW/F03[.!='']))"/>
								</Data>
							</Cell>
							<Cell ss:StyleID="sum-r-txt">
								<Data ss:Type="Number">
									<xsl:value-of select="count($DataSet/DATASET_ROW/F04[.!=''])"/>
								</Data>
							</Cell>
							<Cell ss:StyleID="sum-r-txt">
								<Data ss:Type="Number">
									<xsl:value-of select="sum($DataSet/DATASET_ROW/F05[.!=''])"/>
								</Data>
							</Cell>
						</Row>
					</xsl:if>
					<xsl:if test="$All_Records < 1">
						<Row>
							<Cell ss:MergeAcross="4" ss:StyleID="body-l-txt">
								<Data ss:Type="String">
									<xsl:value-of select="'По выбранным критериям данные не найдены '"/>
								</Data>
							</Cell>
						</Row>
					</xsl:if>
				</Table>
			</Worksheet>
		</Workbook>
	</xsl:template>
</xsl:stylesheet>
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36495914
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mrxiii
Код: plaintext
1.
2.
3.
<?xml version="1.0" encoding="UTF-8"?>
  .........................
  <xsl:for-each-group select=".//DataSet/DATASET_ROW" group-by="F01">
Удачи
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36496420
mrxiii
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Vasilisk, а что не так? Работает как часы :)
...
Рейтинг: 0 / 0
Многоуровневая группировка
    #36498551
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mrxiiiVasilisk, а что не так? Работает как часы :)Не обращать внимания. Был неадекватен
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Многоуровневая группировка
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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