feat(skd-validate): подсказки XSD-проверки — что именно исправить

Текст валидатора про порядок («недопустимый дочерний X, ожидается A, B»)
читался как «добавь A». Теперь для нарушений порядка скрипт сам строит
подсказку по XSD: must come before <S>, duplicate, not allowed in <P>.
Обход схемы свой в обоих портах — подсказки совпадают побайтно. Остальные
сообщения — без пространств имён. Ошибка атрибута в PS привязывается к
своему элементу, а не к родителю. В SKILL.md — что делать со строками XSD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dc2yLQfw6wppbopM1Y4Ps
This commit is contained in:
Nick Shirokov
2026-09-29 16:06:17 +03:00
co-authored by Claude Opus 5.5
parent 5465a7803c
commit 8c15c84f73
8 changed files with 512 additions and 15 deletions
+9 -1
View File
@@ -12,7 +12,6 @@ allowed-tools:
Проверяет структурную корректность Template.xml схемы компоновки данных. Выявляет ошибки формата, битые ссылки, дубликаты имён.
Если в проекте есть XSD-схемы платформы (`/v8-xsd-fetch`), дополнительно проверяет порядок элементов, типы и значения по схеме версии формата выгрузки.
## Параметры
@@ -29,3 +28,12 @@ allowed-tools:
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-validate.ps1" -TemplatePath "src/МойОтчёт/Templates/ОсновнаяСхема"
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/skd-validate.ps1" -TemplatePath "Catalogs/Номенклатура/Templates/СКД/Ext/Template.xml"
```
## Проверка по XSD
Если в проекте есть XSD-схемы платформы (`/v8-xsd-fetch`), дополнительно проверяет порядок элементов, типы и значения по схеме версии формата выгрузки. Строки вида `XSD 2.20, line N: <родитель>/<элемент>: …`:
- `must come before <X>` — элемент не на своём месте: перенести его перед `<X>`, содержимое не менять. `duplicate` — лишний повтор. `not allowed in <P>` — в этом месте такого элемента быть не должно. Остальное — недопустимое значение, текст говорит какое.
- `[ERROR]` — по схемам своей версии формата. `[WARN]` с `(no schemas for X)` — по более новой версии, ориентир, а не окончательный вердикт.
- Шаблон собран `/skd-compile` или изменён `/skd-edit` — нарушение означает дефект навыка: сообщи пользователю, а не правь XML вручную молча.
- `no schemas for format X — not checked` — предложи `/v8-xsd-fetch -Versions X`.
@@ -1,4 +1,4 @@
# skd-validate v1.5 — Validate 1C DCS structure
# skd-validate v1.6 — Validate 1C DCS structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
[CmdletBinding(PositionalBinding=$false)]
param(
@@ -1044,6 +1044,151 @@ function Test-XsdPlatformNoise($info) {
return $false
}
# --- Подсказка по схеме: что именно исправить ---
# Текст валидатора про порядок («недопустимый дочерний X, ожидается A, B») читается как «добавь A»,
# а означает «X стоит слишком поздно». Поэтому для нарушений порядка строим свою подсказку: тип
# родителя и порядок его детей берём из XSD, сравниваем с соседями нарушителя в документе. Обход
# схемы — свой, по XSD-документам (не PSVI .NET): так подсказки портов совпадают.
function Get-XsdModel([string]$dir) {
$m = @{
types = New-Object 'System.Collections.Generic.Dictionary[string,object]' ([StringComparer]::Ordinal)
elems = New-Object 'System.Collections.Generic.Dictionary[string,object]' ([StringComparer]::Ordinal)
orders = New-Object 'System.Collections.Generic.Dictionary[string,object]' ([StringComparer]::Ordinal)
}
foreach ($f in Get-ChildItem -LiteralPath $dir -Filter *.xsd -File) {
$doc = New-Object System.Xml.XmlDocument
$doc.Load($f.FullName)
$tns = $doc.DocumentElement.GetAttribute("targetNamespace")
foreach ($n in $doc.DocumentElement.ChildNodes) {
if ($n.NodeType -ne 'Element' -or $n.NamespaceURI -cne 'http://www.w3.org/2001/XMLSchema') { continue }
$name = $n.GetAttribute("name")
if (-not $name) { continue }
if ($n.get_LocalName() -ceq 'complexType' -and -not $m.types.ContainsKey("$tns|$name")) { $m.types["$tns|$name"] = $n }
elseif ($n.get_LocalName() -ceq 'element' -and -not $m.elems.ContainsKey("$tns|$name")) { $m.elems["$tns|$name"] = $n }
}
}
return $m
}
# QName из атрибута схемы → "ns|имя" по пространствам имён узла XSD
function Resolve-XsdQName($node, [string]$qn) {
if (-not $qn) { return $null }
$pp = $qn.Split(':')
$prefix = if ($pp.Count -gt 1) { $pp[0] } else { '' }
return "$($node.GetNamespaceOfPrefix($prefix))|$($pp[-1])"
}
# Дети типа по порядку: @{ name; type; maxOne }. База расширения — первой. Порядок не определён
# (choice, all, any, group) или тип неизвестен — $null.
function Get-XsdChildOrder($model, [string]$typeKey) {
if (-not $typeKey) { return $null }
# Список отдаём через «,»: иначе PS развернёт его — пустой станет $null, одиночный — самим элементом
if ($model.orders.ContainsKey($typeKey)) { $v = $model.orders[$typeKey]; if ($null -eq $v) { return $null }; return ,$v }
$model.orders[$typeKey] = $null # защита от циклов
$ct = if ($model.types.ContainsKey($typeKey)) { $model.types[$typeKey] } else { $null }
if (-not $ct) { return $null }
$list = New-Object System.Collections.ArrayList
$holder = $ct
foreach ($c in $ct.ChildNodes) {
if ($c.NodeType -ne 'Element') { continue }
if ($c.get_LocalName() -ceq 'simpleContent') { $model.orders[$typeKey] = $list; return ,$list }
if ($c.get_LocalName() -ceq 'complexContent') {
$ext = $null
foreach ($x in $c.ChildNodes) { if ($x.NodeType -eq 'Element' -and $x.get_LocalName() -ceq 'extension') { $ext = $x } }
if (-not $ext) { return $null }
$baseKey = Resolve-XsdQName $ext $ext.GetAttribute("base")
$base = Get-XsdChildOrder $model $baseKey
# База известна, но порядок у неё не определён — не определён и здесь
if ($null -eq $base -and $model.types.ContainsKey($baseKey)) { return $null }
if ($base) { foreach ($b in $base) { [void]$list.Add($b) } }
$holder = $ext
}
}
foreach ($c in $holder.ChildNodes) {
if ($c.NodeType -ne 'Element') { continue }
$ln = $c.get_LocalName()
if ($ln -ceq 'sequence') { if (-not (Add-XsdSequence $model $c $list)) { return $null } }
elseif ($ln -ceq 'choice' -or $ln -ceq 'all' -or $ln -ceq 'group' -or $ln -ceq 'any') { return $null }
}
$model.orders[$typeKey] = $list
return ,$list
}
function Add-XsdSequence($model, $seq, $list) {
foreach ($c in $seq.ChildNodes) {
if ($c.NodeType -ne 'Element') { continue }
$ln = $c.get_LocalName()
if ($ln -ceq 'element') {
$ref = $c.GetAttribute("ref")
if ($ref) {
$rk = Resolve-XsdQName $c $ref
$ge = if ($model.elems.ContainsKey($rk)) { $model.elems[$rk] } else { $null }
$name = $rk.Split('|')[-1]
$type = if ($ge -and $ge.GetAttribute("type")) { Resolve-XsdQName $ge $ge.GetAttribute("type") } else { $null }
} else {
$name = $c.GetAttribute("name")
$type = if ($c.GetAttribute("type")) { Resolve-XsdQName $c $c.GetAttribute("type") } else { $null }
}
$mx = $c.GetAttribute("maxOccurs")
[void]$list.Add(@{ name = $name; type = $type; maxOne = (-not $mx -or $mx -ceq '1') })
} elseif ($ln -ceq 'sequence') {
if (-not (Add-XsdSequence $model $c $list)) { return $false }
} elseif ($ln -ceq 'annotation') {
continue
} else {
return $false
}
}
return $true
}
# Тип родителя нарушителя: спуск от корня по цепочке предков (@{ name; ns; xsiKey })
function Resolve-XsdParentType($model, $ancestors) {
if ($ancestors.Count -eq 0) { return $null }
$root = $ancestors[0]
$rk = "$($root.ns)|$($root.name)"
if ($root.xsiKey) { $type = $root.xsiKey }
elseif ($model.elems.ContainsKey($rk) -and $model.elems[$rk].GetAttribute("type")) { $type = Resolve-XsdQName $model.elems[$rk] $model.elems[$rk].GetAttribute("type") }
elseif ($model.types.ContainsKey($rk)) { $type = $rk }
else { return $null }
for ($i = 1; $i -lt $ancestors.Count; $i++) {
$a = $ancestors[$i]
if ($a.xsiKey) { $type = $a.xsiKey; continue }
$order = Get-XsdChildOrder $model $type
if ($null -eq $order) { return $null }
$hit = $null
foreach ($o in $order) { if ($o.name -ceq $a.name) { $hit = $o; break } }
if (-not $hit -or -not $hit.type) { return $null }
$type = $hit.type
}
return $type
}
function Get-XsdOrderHint($model, $ancestors, [string]$name, $preceding) {
$pt = Resolve-XsdParentType $model $ancestors
$order = Get-XsdChildOrder $model $pt
if ($null -eq $order) { return $null }
$names = [string[]]@($order | ForEach-Object { $_.name })
$idx = [array]::IndexOf($names, $name)
if ($idx -lt 0) { return "not allowed in <$($ancestors[$ancestors.Count - 1].name)>" }
if ($order[$idx].maxOne -and ([string[]]@($preceding) -ccontains $name)) { return "duplicate — only one <$name> allowed" }
foreach ($sib in $preceding) {
if ([array]::IndexOf($names, [string]$sib) -gt $idx) { return "must come before <$sib>" }
}
return $null
}
# Текст валидатора без пространств имён: остаются имена и значения
function Compress-XsdMessage([string]$m) {
$m = $m -replace '[\r\n]+', ' '
$m = $m -replace '\s(в пространстве имен|in namespace)\s"[^"]*"', ''
$m = $m -replace "\s(в пространстве имен|in namespace)\s'[^']*'", ''
$m = $m -replace '\{[^}]*\}', ''
$m = $m -replace '(["''])https?://[^"'']*:', '$1'
return $m.Trim()
}
function Invoke-XsdCheck {
$xsdRoot = Resolve-XsdRoot ([System.IO.Path]::GetDirectoryName($resolvedPath))
if (-not $xsdRoot) { Report-OK "XSD: no schemas in project — not checked"; return }
@@ -1085,16 +1230,24 @@ function Invoke-XsdCheck {
$set.XmlResolver = $null
foreach ($sc in $schemas) { [void]$set.Add($sc) }
try { $set.Compile() } catch { Report-Warn "XSD: schemas in '$useDir' do not compile — not checked: $($_.Exception.Message)"; return }
$script:xsdModel = Get-XsdModel $useDir
# Своя цепочка открытых элементов: в обработчике нужен родитель нарушителя
$script:xsdStack = New-Object System.Collections.ArrayList
$script:xsdFound = 0
# Ошибку атрибута .NET сообщает, стоя на атрибуте: имени элемента-владельца в этот момент нет.
# Откладываем и выводим после Read(), когда читатель уже на элементе.
$script:xsdPending = New-Object System.Collections.ArrayList
$script:xsdTag = if ($exact) { "XSD $useVer" } else { "XSD $useVer (no schemas for $ver)" }
$script:xsdExact = $exact
$handler = {
param($sender, $e)
if ($script:stopped) { return }
$st = $script:xsdStack
if ($sender.NodeType -eq 'Attribute') {
[void]$script:xsdPending.Add(@{ line = $e.Exception.LineNumber; text = (Compress-XsdMessage $e.Message) })
return
}
if ($sender.NodeType -eq 'Element') {
$xt = $sender.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance")
$info = @{ elem = $sender.LocalName; parent = $(if ($st.Count -gt 0) { $st[$st.Count - 1].name } else { '' }); xsiNs = ''; xsiLocal = '' }
@@ -1109,7 +1262,13 @@ function Invoke-XsdCheck {
}
if (Test-XsdPlatformNoise $info) { return }
$script:xsdFound++
$msg = "$($script:xsdTag), line $($e.Exception.LineNumber): $($info.parent)/$($info.elem): $($e.Message -replace '[\r\n]+', ' ')"
$hint = $null
if ($sender.NodeType -eq 'Element') {
$prec = if ($st.Count -gt 0) { $st[$st.Count - 1].children } else { @() }
$hint = Get-XsdOrderHint $script:xsdModel $st $sender.LocalName $prec
}
$text = if ($hint) { $hint } else { Compress-XsdMessage $e.Message }
$msg = "$($script:xsdTag), line $($e.Exception.LineNumber): $($info.parent)/$($info.elem): $text"
if ($script:xsdExact) { Report-Error $msg } else { Report-Warn $msg }
}
$rs = New-Object System.Xml.XmlReaderSettings
@@ -1120,13 +1279,32 @@ function Invoke-XsdCheck {
$r = [System.Xml.XmlReader]::Create($resolvedPath, $rs)
try {
while ($r.Read()) {
if ($r.NodeType -eq 'Element' -and -not $r.IsEmptyElement) {
if ($r.NodeType -eq 'Element') {
# Имя — в дети родителя (и у пустого элемента: он тоже сосед для подсказки)
if ($script:xsdStack.Count -gt 0) { [void]$script:xsdStack[$script:xsdStack.Count - 1].children.Add($r.LocalName) }
foreach ($pa in $script:xsdPending) {
$xt = $r.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance")
$info = @{ elem = $r.LocalName; parent = $(if ($script:xsdStack.Count -gt 0) { $script:xsdStack[$script:xsdStack.Count - 1].name } else { '' }); xsiNs = ''; xsiLocal = '' }
if ($xt) {
$pp = $xt.Split(':')
$info.xsiLocal = $pp[-1]
if ($pp.Count -gt 1) { $info.xsiNs = "$($r.LookupNamespace($pp[0]))" }
}
if (Test-XsdPlatformNoise $info) { continue }
$script:xsdFound++
$msg = "$($script:xsdTag), line $($pa.line): $($info.parent)/$($info.elem): $($pa.text)"
if ($script:xsdExact) { Report-Error $msg } else { Report-Warn $msg }
}
$script:xsdPending.Clear()
if ($script:stopped) { break }
if ($r.IsEmptyElement) { continue }
$xt = $r.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance")
$entry = @{ name = $r.LocalName; xsiNs = ''; xsiLocal = '' }
$entry = @{ name = $r.LocalName; ns = $r.NamespaceURI; xsiNs = ''; xsiLocal = ''; xsiKey = $null; children = New-Object System.Collections.ArrayList }
if ($xt) {
$pp = $xt.Split(':')
$entry.xsiLocal = $pp[-1]
if ($pp.Count -gt 1) { $entry.xsiNs = "$($r.LookupNamespace($pp[0]))" }
$entry.xsiNs = if ($pp.Count -gt 1) { "$($r.LookupNamespace($pp[0]))" } else { "$($r.LookupNamespace(''))" }
$entry.xsiKey = "$($entry.xsiNs)|$($entry.xsiLocal)"
}
[void]$script:xsdStack.Add($entry)
} elseif ($r.NodeType -eq 'EndElement' -and $script:xsdStack.Count -gt 0) {
@@ -1,4 +1,4 @@
# skd-validate v1.5 — Validate 1C DCS structure (Python port)
# skd-validate v1.6 — Validate 1C DCS structure (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -1111,6 +1111,182 @@ def _xsd_error_element(err):
return None
# ── Подсказка по схеме: что именно исправить ──
# Текст валидатора про порядок («недопустимый дочерний X, ожидается A, B») читается как «добавь A»,
# а означает «X стоит слишком поздно». Поэтому для нарушений порядка строим свою подсказку: тип
# родителя и порядок его детей берём из XSD, сравниваем с соседями нарушителя в документе. Обход
# схемы — свой, по XSD-документам, как в PS-мастере: так подсказки портов совпадают.
def xsd_model(vdir):
m = {"types": {}, "elems": {}, "orders": {}}
for name in sorted(os.listdir(vdir)):
fp = os.path.join(vdir, name)
if not (name.lower().endswith(".xsd") and os.path.isfile(fp)):
continue
root_el = etree.parse(fp).getroot()
tns = root_el.get("targetNamespace") or ""
for n in root_el:
if not isinstance(n.tag, str) or etree.QName(n).namespace != XS_NS or not n.get("name"):
continue
key = f"{tns}|{n.get('name')}"
ln = etree.QName(n).localname
if ln == "complexType":
m["types"].setdefault(key, n)
elif ln == "element":
m["elems"].setdefault(key, n)
return m
def xsd_resolve_qname(node, qn):
"""QName из атрибута схемы → "ns|имя" по пространствам имён узла XSD."""
if not qn:
return None
pp = qn.split(":")
prefix = pp[0] if len(pp) > 1 else None
return f"{node.nsmap.get(prefix) or ''}|{pp[-1]}"
def xsd_child_order(model, type_key):
"""Дети типа по порядку: {name, type, maxOne}. База расширения — первой. Порядок не определён
(choice, all, any, group) или тип неизвестен — None."""
if not type_key:
return None
if type_key in model["orders"]:
return model["orders"][type_key]
model["orders"][type_key] = None # защита от циклов
ct = model["types"].get(type_key)
if ct is None:
return None
lst = []
holder = ct
for c in ct:
if not isinstance(c.tag, str):
continue
ln = etree.QName(c).localname
if ln == "simpleContent":
model["orders"][type_key] = lst
return lst
if ln == "complexContent":
ext = None
for x in c:
if isinstance(x.tag, str) and etree.QName(x).localname == "extension":
ext = x
if ext is None:
return None
base_key = xsd_resolve_qname(ext, ext.get("base"))
base = xsd_child_order(model, base_key)
# База известна, но порядок у неё не определён — не определён и здесь
if base is None and base_key in model["types"]:
return None
if base:
lst.extend(base)
holder = ext
for c in holder:
if not isinstance(c.tag, str):
continue
ln = etree.QName(c).localname
if ln == "sequence":
if not _xsd_add_sequence(model, c, lst):
return None
elif ln in ("choice", "all", "group", "any"):
return None
model["orders"][type_key] = lst
return lst
def _xsd_add_sequence(model, seq, lst):
for c in seq:
if not isinstance(c.tag, str):
continue
ln = etree.QName(c).localname
if ln == "element":
ref = c.get("ref")
if ref:
rk = xsd_resolve_qname(c, ref)
ge = model["elems"].get(rk)
name = rk.split("|")[-1]
typ = xsd_resolve_qname(ge, ge.get("type")) if ge is not None and ge.get("type") else None
else:
name = c.get("name")
typ = xsd_resolve_qname(c, c.get("type")) if c.get("type") else None
mx = c.get("maxOccurs")
lst.append({"name": name, "type": typ, "maxOne": (not mx or mx == "1")})
elif ln == "sequence":
if not _xsd_add_sequence(model, c, lst):
return False
elif ln == "annotation":
continue
else:
return False
return True
def _xsd_ancestor(el):
"""Предок для спуска по схеме: {name, ns, xsiKey}."""
q = etree.QName(el)
e = {"name": q.localname, "ns": q.namespace or "", "xsiKey": None}
xt = el.get(XSI_TYPE)
if xt:
pp = xt.split(":")
prefix = pp[0] if len(pp) > 1 else None
e["xsiKey"] = f"{el.nsmap.get(prefix) or ''}|{pp[-1]}"
return e
def xsd_parent_type(model, ancestors):
"""Тип родителя нарушителя: спуск от корня по цепочке предков."""
if not ancestors:
return None
root = ancestors[0]
rk = f"{root['ns']}|{root['name']}"
if root["xsiKey"]:
typ = root["xsiKey"]
elif rk in model["elems"] and model["elems"][rk].get("type"):
typ = xsd_resolve_qname(model["elems"][rk], model["elems"][rk].get("type"))
elif rk in model["types"]:
typ = rk
else:
return None
for a in ancestors[1:]:
if a["xsiKey"]:
typ = a["xsiKey"]
continue
order = xsd_child_order(model, typ)
if order is None:
return None
hit = next((o for o in order if o["name"] == a["name"]), None)
if hit is None or not hit["type"]:
return None
typ = hit["type"]
return typ
def xsd_order_hint(model, ancestors, name, preceding):
order = xsd_child_order(model, xsd_parent_type(model, ancestors))
if order is None:
return None
names = [o["name"] for o in order]
if name not in names:
return f"not allowed in <{ancestors[-1]['name']}>"
idx = names.index(name)
if order[idx]["maxOne"] and name in preceding:
return f"duplicate — only one <{name}> allowed"
for sib in preceding:
if sib in names and names.index(sib) > idx:
return f"must come before <{sib}>"
return None
def compress_xsd_message(m):
"""Текст валидатора без пространств имён: остаются имена и значения."""
m = re.sub(r'[\r\n]+', ' ', m)
m = re.sub(r'\s(в пространстве имен|in namespace)\s"[^"]*"', '', m)
m = re.sub(r"\s(в пространстве имен|in namespace)\s'[^']*'", '', m)
m = re.sub(r'\{[^}]*\}', '', m)
m = re.sub(r'(["\'])https?://[^"\']*:', r'\1', m)
return ' '.join(m.split())
def xsd_check():
xsd_root = resolve_xsd_root(os.path.dirname(resolved_path))
if not xsd_root:
@@ -1133,6 +1309,7 @@ def xsd_check():
use_ver = cands[0]
exact = use_ver == ver
model = xsd_model(os.path.join(xsd_root, use_ver))
tmp = tempfile.mkdtemp(prefix="skd-xsd-")
try:
try:
@@ -1154,7 +1331,15 @@ def xsd_check():
if xsd_platform_noise(info):
continue
found += 1
msg = f"{tag}, line {err.line}: {info['parent']}/{info['elem']}: {' '.join(err.message.split())}"
hint = None
# «Лишний/не на месте» у libxml2 — «This element is not expected» (текст не локализуется)
if el is not None and "This element is not expected" in err.message:
ancestors = [_xsd_ancestor(a) for a in reversed(list(el.iterancestors()))]
preceding = [etree.QName(x).localname for x in reversed(list(el.itersiblings(preceding=True)))
if isinstance(x.tag, str)]
hint = xsd_order_hint(model, ancestors, etree.QName(el).localname, preceding)
text = hint or compress_xsd_message(err.message)
msg = f"{tag}, line {err.line}: {info['parent']}/{info['elem']}: {text}"
if exact:
report_error(msg)
else:
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" version="2.20">
<Configuration uuid="00000000-0000-0000-0000-000000000001"/>
</MetaDataObject>
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<DataCompositionSchema xmlns="http://v8.1c.ru/8.1/data-composition-system/schema" xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common" xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core" xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dataSource>
<name>ИсточникДанных1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>НаборДанных1</name>
<field xsi:type="DataSetFieldField">
<dataPath>Число</dataPath>
<field>Число</field>
<presentationExpression>Формат(Число, "ЧГ=")</presentationExpression>
<presentationExpression>Формат(Число, "ЧГ=")</presentationExpression>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>10</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
</field>
<field xsi:type="DataSetFieldField">
<dataPath>Флаг</dataPath>
<field>Флаг</field>
<fooBar>x</fooBar>
<valueType>
<v8:Type>xs:boolean</v8:Type>
</valueType>
</field>
<dataSource>ИсточникДанных1</dataSource>
<query>ВЫБРАТЬ 1 КАК Число, ИСТИНА КАК Флаг</query>
</dataSet>
<calculatedField>
<dataPath>Удвоенное</dataPath>
<expression>Число * 2</expression>
<useRestriction>
<group>true</group>
</useRestriction>
<valueType>
<v8:Type>xs:decimal</v8:Type>
<v8:NumberQualifiers>
<v8:Digits>10</v8:Digits>
<v8:FractionDigits>0</v8:FractionDigits>
<v8:AllowedSign>Any</v8:AllowedSign>
</v8:NumberQualifiers>
</valueType>
</calculatedField>
<parameter>
<name>П</name>
<valueType>
<v8:Type>xs:boolean</v8:Type>
</valueType>
<value xsi:type="xs:boolean">false</value>
<useRestriction>false</useRestriction>
</parameter>
<settingsVariant>
<dcsset:name>Основной</dcsset:name>
<dcsset:presentation xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Основной</v8:content>
</v8:item>
</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemField">
<dcsset:field>Число</dcsset:field>
</dcsset:item>
</dcsset:selection>
<dcsset:filter>
<dcsset:item xsi:type="dcsset:FilterItemComparison">
<dcsset:left xsi:type="dcscor:Field">Флаг</dcsset:left>
<dcsset:comparisonType>Equal</dcsset:comparisonType>
<dcsset:right xsi:type="xs:boolean">true</dcsset:right>
</dcsset:item>
</dcsset:filter>
<dcsset:dataParameters>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:parameter>П</dcscor:parameter>
<dcscor:value xsi:type="xs:boolean">false</dcscor:value>
<dcsset:userSettingID>0eb70b37-3a01-40a0-81c1-98028ef06a05</dcsset:userSettingID>
</dcscor:item>
</dcsset:dataParameters>
<dcsset:outputParameters>
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
<dcscor:parameter>Заголовок</dcscor:parameter>
<dcscor:value xsi:type="v8:LocalStringType">
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Пример</v8:content>
</v8:item>
</dcscor:value>
</dcscor:item>
</dcsset:outputParameters>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:order>
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
</dcsset:order>
<dcsset:selection>
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>
</dcsset:selection>
</dcsset:item>
</dcsset:settings>
</settingsVariant>
</DataCompositionSchema>
@@ -1,5 +1,5 @@
{
"name": "XSD точной версии: нарушенный порядок и False — ошибки с местом нарушения",
"name": "XSD точной версии: подсказки по порядку и сжатый текст без пространств имён",
"setup": "fixture:xsd-bad-220",
"requires": ".v8-xsd/2.20",
"preRun": [
@@ -18,11 +18,12 @@
"expectError": true,
"expect": {
"stdoutContains": [
"[ERROR] XSD 2.20, line 20: field/presentationExpression",
"[ERROR] XSD 2.20, line 43: calculatedField/useRestriction",
"[ERROR] XSD 2.20, line 52: parameter/value",
"[ERROR] XSD 2.20, line 87: settings/dataParameters"
]
"[ERROR] XSD 2.20, line 20: field/presentationExpression: must come before <valueType>",
"[ERROR] XSD 2.20, line 43: calculatedField/useRestriction: must come before <valueType>",
"[ERROR] XSD 2.20, line 52: parameter/value:",
"[ERROR] XSD 2.20, line 87: settings/dataParameters: must come before <outputParameters>"
],
"stdoutNotContains": "http://v8.1c.ru"
},
"noSnapshot": "результат — только вывод; схемы 1С не должны попасть в эталон"
}
@@ -0,0 +1,15 @@
{
"name": "Подсказки XSD: повтор элемента и элемент, которого нет в модели родителя",
"setup": "fixture:xsd-hints-220",
"requires": ".v8-xsd/2.20",
"preRun": [{ "writeFile": { "path": ".v8-project.json", "content": { "xsdPath": "{repoRoot}/.v8-xsd" } } }],
"params": { "templatePath": "Reports/Отчет/Templates/Схема/Ext/Template.xml" },
"expectError": true,
"expect": {
"stdoutContains": [
"field/presentationExpression: duplicate — only one <presentationExpression> allowed",
"field/fooBar: not allowed in <field>"
]
},
"noSnapshot": "результат — только вывод; схемы 1С не должны попасть в эталон"
}
@@ -20,7 +20,7 @@
},
"expect": {
"stdoutContains": [
"[WARN] XSD 2.12 (no schemas for 2.11), line 20: field/presentationExpression"
"[WARN] XSD 2.12 (no schemas for 2.11), line 20: field/presentationExpression: must come before <valueType>"
],
"stdoutNotContains": "[ERROR]"
},