feat(skd): multi-series и multi-point в StructureItemChart

Диаграмма может содержать несколько <dcsset:series> (и аналогично
<dcsset:point>) — каждая со своим groupItems, filter, order, selection,
viewMode, userSettingID и userSettingPresentation. Используется для
multi-series графиков с группировкой по фильтру (например,
АнализЛояльностиКлиентовXYZ — series по СтадияОтношений: Постоянный,
Разовый, Потенциальный, Потерянный клиент).

Раньше декомпилировали только первый блок (SelectSingleNode), теряя
остальные → −113 строк diff на одном этом отчёте (134 → 21).

decompile: SelectNodes → если >1, сохраняем как массив; single → object
(backward-compat).
compile: проверяем тип points/series — array → цикл, иначе single
блок (backward-compat для существующего DSL).

PS и Py compile синхронизированы.
This commit is contained in:
Nick Shirokov
2026-05-24 16:18:16 +03:00
parent 19da4df61f
commit d9010cd580
3 changed files with 69 additions and 25 deletions
@@ -1,4 +1,4 @@
# skd-compile v1.90 — Compile 1C DCS from JSON
# skd-compile v1.91 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -3014,18 +3014,40 @@ function Emit-StructureItem {
X "$indent`t<dcsset:name>$(Esc-Xml "$($item.name)")</dcsset:name>"
}
# Points
# Points — single object или массив (multi-series диаграмма)
if ($item.points) {
X "$indent`t<dcsset:point>"
Emit-TableAxisBlock -block $item.points -indent "$indent`t`t"
X "$indent`t</dcsset:point>"
$pBlocks = if ($item.points -is [array] -or ($item.points -is [System.Collections.IList] -and $item.points -isnot [string])) {
@($item.points)
} else { @($item.points) }
# Эвристика: если это массив объектов (а не одиночный объект-с-полями) → multi.
$isPointsArray = ($item.points -is [array]) -or ($item.points -is [System.Collections.IList] -and $item.points -isnot [string] -and $item.points -isnot [System.Collections.IDictionary] -and $item.points -isnot [PSCustomObject])
if ($isPointsArray) {
foreach ($pb in $pBlocks) {
X "$indent`t<dcsset:point>"
Emit-TableAxisBlock -block $pb -indent "$indent`t`t"
X "$indent`t</dcsset:point>"
}
} else {
X "$indent`t<dcsset:point>"
Emit-TableAxisBlock -block $item.points -indent "$indent`t`t"
X "$indent`t</dcsset:point>"
}
}
# Series
# Series — single object или массив
if ($item.series) {
X "$indent`t<dcsset:series>"
Emit-TableAxisBlock -block $item.series -indent "$indent`t`t"
X "$indent`t</dcsset:series>"
$isSeriesArray = ($item.series -is [array]) -or ($item.series -is [System.Collections.IList] -and $item.series -isnot [string] -and $item.series -isnot [System.Collections.IDictionary] -and $item.series -isnot [PSCustomObject])
if ($isSeriesArray) {
foreach ($sb in @($item.series)) {
X "$indent`t<dcsset:series>"
Emit-TableAxisBlock -block $sb -indent "$indent`t`t"
X "$indent`t</dcsset:series>"
}
} else {
X "$indent`t<dcsset:series>"
Emit-TableAxisBlock -block $item.series -indent "$indent`t`t"
X "$indent`t</dcsset:series>"
}
}
# Selection (chart values)
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# skd-compile v1.90 — Compile 1C DCS from JSON
# skd-compile v1.91 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import json
@@ -2418,17 +2418,23 @@ def emit_structure_item(lines, item, indent, short_group=False):
if item.get('name'):
lines.append(f'{indent}\t<dcsset:name>{esc_xml(str(item["name"]))}</dcsset:name>')
# Points
if item.get('points'):
lines.append(f'{indent}\t<dcsset:point>')
emit_table_axis_block(lines, item['points'], f'{indent}\t\t')
lines.append(f'{indent}\t</dcsset:point>')
# Points — single object или массив (multi-series диаграмма)
pts = item.get('points')
if pts:
pts_list = pts if isinstance(pts, list) else [pts]
for pb in pts_list:
lines.append(f'{indent}\t<dcsset:point>')
emit_table_axis_block(lines, pb, f'{indent}\t\t')
lines.append(f'{indent}\t</dcsset:point>')
# Series
if item.get('series'):
lines.append(f'{indent}\t<dcsset:series>')
emit_table_axis_block(lines, item['series'], f'{indent}\t\t')
lines.append(f'{indent}\t</dcsset:series>')
# Series — single object или массив
srs = item.get('series')
if srs:
srs_list = srs if isinstance(srs, list) else [srs]
for sb in srs_list:
lines.append(f'{indent}\t<dcsset:series>')
emit_table_axis_block(lines, sb, f'{indent}\t\t')
lines.append(f'{indent}\t</dcsset:series>')
# Selection (chart values)
emit_selection(lines, item.get('selection'), f'{indent}\t')
@@ -1,4 +1,4 @@
# skd-decompile v0.73 — Decompile 1C DCS Template.xml to JSON DSL (draft)
# skd-decompile v0.74 — Decompile 1C DCS Template.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -2118,10 +2118,26 @@ function Build-Structure {
$entry = [ordered]@{ type = 'chart' }
$nm = Get-Text $it "dcsset:name"
if ($nm) { $entry['name'] = $nm }
$pn = $it.SelectSingleNode("dcsset:point", $ns)
if ($pn) { $entry['points'] = Build-TableAxisBlock -node $pn -loc "$loc/$idx/point" }
$sn = $it.SelectSingleNode("dcsset:series", $ns)
if ($sn) { $entry['series'] = Build-TableAxisBlock -node $sn -loc "$loc/$idx/series" }
# point/series — может быть несколько (multi-series диаграмма).
# Single → сохраняем как object (backward-compat); >1 → массив.
$pnList = $it.SelectNodes("dcsset:point", $ns)
if ($pnList.Count -eq 1) {
$entry['points'] = Build-TableAxisBlock -node $pnList[0] -loc "$loc/$idx/point"
} elseif ($pnList.Count -gt 1) {
$pArr = @()
$pi = 0
foreach ($p in $pnList) { $pArr += (Build-TableAxisBlock -node $p -loc "$loc/$idx/point[$pi]"); $pi++ }
$entry['points'] = $pArr
}
$snList = $it.SelectNodes("dcsset:series", $ns)
if ($snList.Count -eq 1) {
$entry['series'] = Build-TableAxisBlock -node $snList[0] -loc "$loc/$idx/series"
} elseif ($snList.Count -gt 1) {
$sArr = @()
$si = 0
foreach ($s in $snList) { $sArr += (Build-TableAxisBlock -node $s -loc "$loc/$idx/series[$si]"); $si++ }
$entry['series'] = $sArr
}
$selN = $it.SelectSingleNode("dcsset:selection", $ns)
$selI = Build-Selection -selNode $selN -loc "$loc/$idx/selection"
if ($selI.Count -gt 0 -and -not ($selI.Count -eq 1 -and $selI[0] -eq 'Auto')) {