fix(xdto-compile,xdto-info,xdto-edit): правки по итогам прогона на субагентах

Четырём субагентам выданы реалистичные задачи по песочнице, навыки в
формулировках не назывались. Разбор — в debug/xdto/FINDINGS.md, §13.

ГЛАВНОЕ — дефект компилятора. При уплощении вложенного xs:choice ветки
оставались обязательными: схема «самовывоз ИЛИ адрес доставки» давала пакет,
требующий заполнить оба, и ни один реальный документ в него не ложился.
Компилятор предупреждал о потере выбора, но молчал о последствии, а валидатор
показывал «0 ошибок, 0 предупреждений» — структурно пакет корректен,
семантически мёртв. Теперь ветки становятся необязательными (единственное
уплощение, оставляющее тип заполнимым), предупреждение называет их поимённо.
Корневой xs:choice не затронут: он отображается в ordered="false".

xdto-edit: -Value "@файл" по конвенции skd-edit — на кавычках при инлайновой
передаче XSD споткнулись двое агентов из четырёх, причём сырой LoadXml уводил
чинить схему вместо транспорта. При сбое разбора теперь понятное сообщение.

xdto-info: поиск, законно ничего не нашедший, падал throw'ом со стектрейсом и
читался как поломка инструмента — теперь строка и exit 1. Блок «Создание»
покрывал только корневой тип, хотя вся реальная работа в XDTO — вложенные и
анонимные типы; добавлены рецепты по факту наличия. Отсутствие раздела «Точки
входа» было неоднозначным — теперь явная строка. Новый -RequiredOnly даёт
скелет «заполни обязательное»: необязательный объект уходит вместе с поддеревом.
По умолчанию выключен — иначе список читался бы как полный.

xdto-validate: предупреждение про anyType описывало историю («платформа заменяет
при импорте»), хотя в файле уже зафиксирован anyType; сначала состояние, потом
происхождение.

Проверено: 40 тестов на обоих рантаймах, round-trip 760/760, валидатор
0 ложных срабатываний на корпусе.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-26 13:44:46 +03:00
co-authored by Claude Opus 5
parent 1a1bbbac6f
commit 6486f433de
23 changed files with 590 additions and 36 deletions
+6
View File
@@ -60,6 +60,12 @@ XSD выразительнее модели XDTO. Всё, что не перен
`xs:include` игнорируется: зависимости в XDTO разрешаются только по namespace, `xs:include` игнорируется: зависимости в XDTO разрешаются только по namespace,
поэтому включаемую схему нужно собрать отдельным пакетом и заменить `include` на `import`. поэтому включаемую схему нужно собрать отдельным пакетом и заменить `include` на `import`.
## Посмотреть, что получилось
Модель пакета лежит в `Ext/Package.bin`. Несмотря на расширение, это текстовый XML,
но читать его напрямую обычно незачем: состав собранного пакета показывает
`/xdto-info`, а полную схему — `/xdto-decompile`.
## Зависимости между пакетами ## Зависимости между пакетами
`<xs:import namespace="…"/>` разрешается по namespace среди пакетов конфигурации `<xs:import namespace="…"/>` разрешается по namespace среди пакетов конфигурации
@@ -493,24 +493,38 @@ function Resolve-Group([System.Xml.XmlElement]$el, [string]$kind) {
# Модель XDTO знает только плоский список свойств: вложенные частицы уплощаются. # Модель XDTO знает только плоский список свойств: вложенные частицы уплощаются.
# Каждое уплощение — предупреждение, потому что меняется смысл схемы. # Каждое уплощение — предупреждение, потому что меняется смысл схемы.
function Collect-Particle([System.Xml.XmlElement]$particle, $elemList, [ref]$isOpen, [string]$typeName, [int]$depth) { function Collect-Particle([System.Xml.XmlElement]$particle, $elemList, [ref]$isOpen, [string]$typeName, [int]$depth, [bool]$optionalize = $false) {
if ($depth -gt 20) { return } if ($depth -gt 20) { return }
foreach ($c in $particle.ChildNodes) { foreach ($c in $particle.ChildNodes) {
if ($c.NodeType -ne [System.Xml.XmlNodeType]::Element -or $c.NamespaceURI -ne $XS_NS) { continue } if ($c.NodeType -ne [System.Xml.XmlNodeType]::Element -or $c.NamespaceURI -ne $XS_NS) { continue }
switch ($c.get_LocalName()) { switch ($c.get_LocalName()) {
"element" { [void]$elemList.Add((Build-Property $c $false)) } "element" {
$prop = Build-Property $c $false
# Ветка уплощённого xs:choice обязана стать необязательной: иначе
# «одно из двух» превращается в «оба сразу», и тип нельзя заполнить
if ($optionalize) { Set-AttrValue $prop "lowerBound" "0" }
[void]$elemList.Add($prop)
}
"any" { $isOpen.Value = $true } "any" { $isOpen.Value = $true }
"sequence" { "sequence" {
Warn "$typeName : вложенная xs:sequence уплощена — модель XDTO хранит плоский список свойств" Warn "$typeName : вложенная xs:sequence уплощена — модель XDTO хранит плоский список свойств"
Collect-Particle $c $elemList $isOpen $typeName ($depth + 1) Collect-Particle $c $elemList $isOpen $typeName ($depth + 1) $optionalize
} }
"choice" { "choice" {
Warn "$typeName : вложенная xs:choice уплощена в последовательность — выбор одного из вариантов не сохранён" $branches = @()
Collect-Particle $c $elemList $isOpen $typeName ($depth + 1) foreach ($b in $c.ChildNodes) {
if ($b.NodeType -eq [System.Xml.XmlNodeType]::Element -and $b.NamespaceURI -eq $XS_NS -and $b.HasAttribute("name")) {
$branches += $b.GetAttribute("name")
}
}
$list = if ($branches.Count -gt 0) { " (" + ($branches -join ", ") + ")" } else { "" }
Warn ("$typeName : вложенная xs:choice уплощена — ветки$list сделаны необязательными. " +
"Выбор одного из вариантов не сохранён: модель не запретит заполнить сразу несколько или ни одного")
Collect-Particle $c $elemList $isOpen $typeName ($depth + 1) $true
} }
"all" { "all" {
Warn "$typeName : xs:all трактуется как последовательность" Warn "$typeName : xs:all трактуется как последовательность"
Collect-Particle $c $elemList $isOpen $typeName ($depth + 1) Collect-Particle $c $elemList $isOpen $typeName ($depth + 1) $optionalize
} }
"group" { "group" {
$g = Resolve-Group $c "group" $g = Resolve-Group $c "group"
@@ -518,7 +532,7 @@ function Collect-Particle([System.Xml.XmlElement]$particle, $elemList, [ref]$isO
foreach ($gc in $g.ChildNodes) { foreach ($gc in $g.ChildNodes) {
if ($gc.NodeType -eq [System.Xml.XmlNodeType]::Element -and $gc.NamespaceURI -eq $XS_NS -and if ($gc.NodeType -eq [System.Xml.XmlNodeType]::Element -and $gc.NamespaceURI -eq $XS_NS -and
@("sequence", "choice", "all") -contains $gc.get_LocalName()) { @("sequence", "choice", "all") -contains $gc.get_LocalName()) {
Collect-Particle $gc $elemList $isOpen $typeName ($depth + 1) Collect-Particle $gc $elemList $isOpen $typeName ($depth + 1) $optionalize
} }
} }
} else { } else {
@@ -541,7 +541,7 @@ def resolve_group(el, kind):
# Модель XDTO знает только плоский список свойств: вложенные частицы уплощаются. # Модель XDTO знает только плоский список свойств: вложенные частицы уплощаются.
# Каждое уплощение — предупреждение, потому что меняется смысл схемы. # Каждое уплощение — предупреждение, потому что меняется смысл схемы.
def collect_particle(particle, elem_list, open_flag, type_name, depth): def collect_particle(particle, elem_list, open_flag, type_name, depth, optionalize=False):
if depth > 20: if depth > 20:
return return
for c in particle: for c in particle:
@@ -549,25 +549,35 @@ def collect_particle(particle, elem_list, open_flag, type_name, depth):
continue continue
ln = local(c) ln = local(c)
if ln == "element": if ln == "element":
elem_list.append(build_property(c, False)) prop = build_property(c, False)
# Ветка уплощённого xs:choice обязана стать необязательной: иначе
# «одно из двух» превращается в «оба сразу», и тип нельзя заполнить
if optionalize:
set_attr_value(prop, "lowerBound", "0")
elem_list.append(prop)
elif ln == "any": elif ln == "any":
open_flag[0] = True open_flag[0] = True
elif ln == "sequence": elif ln == "sequence":
warn(type_name + " : вложенная xs:sequence уплощена — модель XDTO хранит плоский список свойств") warn(type_name + " : вложенная xs:sequence уплощена — модель XDTO хранит плоский список свойств")
collect_particle(c, elem_list, open_flag, type_name, depth + 1) collect_particle(c, elem_list, open_flag, type_name, depth + 1, optionalize)
elif ln == "choice": elif ln == "choice":
warn(type_name + " : вложенная xs:choice уплощена в последовательность — выбор одного из вариантов не сохранён") branches = [b.get("name") for b in c
collect_particle(c, elem_list, open_flag, type_name, depth + 1) if isinstance(b.tag, str) and etree.QName(b).namespace == XS_NS and b.get("name")]
lst = (" (" + ", ".join(branches) + ")") if branches else ""
warn(type_name + " : вложенная xs:choice уплощена — ветки" + lst + " сделаны необязательными. "
"Выбор одного из вариантов не сохранён: модель не запретит заполнить "
"сразу несколько или ни одного")
collect_particle(c, elem_list, open_flag, type_name, depth + 1, True)
elif ln == "all": elif ln == "all":
warn(type_name + " : xs:all трактуется как последовательность") warn(type_name + " : xs:all трактуется как последовательность")
collect_particle(c, elem_list, open_flag, type_name, depth + 1) collect_particle(c, elem_list, open_flag, type_name, depth + 1, optionalize)
elif ln == "group": elif ln == "group":
g = resolve_group(c, "group") g = resolve_group(c, "group")
if g is not None: if g is not None:
for gc in g: for gc in g:
if isinstance(gc.tag, str) and etree.QName(gc).namespace == XS_NS \ if isinstance(gc.tag, str) and etree.QName(gc).namespace == XS_NS \
and local(gc) in ("sequence", "choice", "all"): and local(gc) in ("sequence", "choice", "all"):
collect_particle(gc, elem_list, open_flag, type_name, depth + 1) collect_particle(gc, elem_list, open_flag, type_name, depth + 1, optionalize)
else: else:
warn(type_name + " : не найдена группа " + str(c.get("ref")) + " — её свойства в пакет не попали") warn(type_name + " : не найдена группа " + str(c.get("ref")) + " — её свойства в пакет не попали")
if ln in ("sequence", "choice", "all", "group"): if ln in ("sequence", "choice", "all", "group"):
+14 -1
View File
@@ -23,7 +23,7 @@ allowed-tools:
| `PackagePath` | да | Каталог пакета, `Ext/Package.bin` или `<Имя>.xml`. Псевдоним — `-Path` | | `PackagePath` | да | Каталог пакета, `Ext/Package.bin` или `<Имя>.xml`. Псевдоним — `-Path` |
| `Operation` | да | Операция из таблицы ниже | | `Operation` | да | Операция из таблицы ниже |
| `Target` | зависит | Адрес: имя типа или путь `Тип.Свойство` | | `Target` | зависит | Адрес: имя типа или путь `Тип.Свойство` |
| `Value` | зависит | Фрагмент XSD, литерал, URI или текст | | `Value` | зависит | Фрагмент XSD, литерал, URI или текст. `@путь` — взять содержимое из файла |
| `NoValidate` | нет | Не запускать `xdto-validate` после правки | | `NoValidate` | нет | Не запускать `xdto-validate` после правки |
```powershell ```powershell
@@ -60,6 +60,19 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/xdto-edit.ps1" -Pac
`/xdto-compile`. Отдельных параметров вида `-MinOccurs` нет: чтобы поменять свойство, `/xdto-compile`. Отдельных параметров вида `-MinOccurs` нет: чтобы поменять свойство,
дай его новое объявление целиком через `replace-property`. дай его новое объявление целиком через `replace-property`.
Ограничение длины и прочие фасеты задаются вложенным типом:
```xml
<xs:element name="Комментарий" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string"><xs:maxLength value="200"/></xs:restriction>
</xs:simpleType>
</xs:element>
```
Многострочный фрагмент передавай файлом: `-Value "@frag.xsd"`. Инлайн через оболочку
надёжен только для однострочных фрагментов без вложенных кавычек.
## Адресация ## Адресация
Путь `Тип.Свойство`. Точка безопасна: имена типов и свойств — идентификаторы 1С. Путь `Тип.Свойство`. Точка безопасна: имена типов и свойств — идентификаторы 1С.
+19 -1
View File
@@ -114,6 +114,18 @@ $binFile = Join-Path (Join-Path $pkgDir "Ext") "Package.bin"
$mdFile = Join-Path $xdtoRoot "$pkgName.xml" $mdFile = Join-Path $xdtoRoot "$pkgName.xml"
$configXml = Join-Path $configRoot "Configuration.xml" $configXml = Join-Path $configRoot "Configuration.xml"
# -Value "@путь" — содержимое берётся из файла. Передавать XSD-фрагмент инлайном
# через powershell.exe -File ненадёжно: вложенные кавычки схлопываются на границе
# процессов, и вместо понятной ошибки получается сырой сбой разбора XML.
if ($Value -and $Value.StartsWith("@")) {
$valueFile = $Value.Substring(1)
if (-not [System.IO.Path]::IsPathRooted($valueFile)) {
$valueFile = Join-Path (Get-Location).Path $valueFile
}
if (-not (Test-Path $valueFile -PathType Leaf)) { throw "Файл значения не найден: $valueFile" }
$Value = [System.IO.File]::ReadAllText($valueFile).Trim()
}
Assert-EditAllowed $pkgDir Assert-EditAllowed $pkgDir
$encBom = New-Object System.Text.UTF8Encoding($true) $encBom = New-Object System.Text.UTF8Encoding($true)
@@ -328,7 +340,13 @@ function Import-Fragment($schema, [string]$xml) {
$nsAttrs += " xmlns:$($a.get_LocalName())=`"$($a.Value)`"" $nsAttrs += " xmlns:$($a.get_LocalName())=`"$($a.Value)`""
} }
} }
$tmp.LoadXml("<wrap$nsAttrs>$xml</wrap>") try { $tmp.LoadXml("<wrap$nsAttrs>$xml</wrap>") }
catch {
throw ("Не удалось разобрать -Value как фрагмент XML-схемы: " + $_.Exception.InnerException.Message + "`n" +
"Получено: " + $xml + "`n" +
"Если фрагмент передан инлайном, кавычки могли схлопнуться на границе процессов — " +
"положите его в файл и укажите -Value `"@путь`".")
}
$res = New-Object System.Collections.ArrayList $res = New-Object System.Collections.ArrayList
foreach ($c in $tmp.DocumentElement.ChildNodes) { foreach ($c in $tmp.DocumentElement.ChildNodes) {
if ($c.NodeType -eq [System.Xml.XmlNodeType]::Element) { if ($c.NodeType -eq [System.Xml.XmlNodeType]::Element) {
@@ -145,6 +145,18 @@ bin_file = os.path.join(pkg_dir, "Ext", "Package.bin")
md_file = os.path.join(xdto_root, pkg_name + ".xml") md_file = os.path.join(xdto_root, pkg_name + ".xml")
config_xml = os.path.join(config_root, "Configuration.xml") config_xml = os.path.join(config_root, "Configuration.xml")
# -Value "@путь" — содержимое берётся из файла. Передавать XSD-фрагмент инлайном
# ненадёжно: вложенные кавычки схлопываются на границе процессов, и вместо понятной
# ошибки получается сырой сбой разбора XML.
if args.Value.startswith("@"):
value_file = args.Value[1:]
if not os.path.isabs(value_file):
value_file = os.path.join(os.getcwd(), value_file)
if not os.path.isfile(value_file):
die("Файл значения не найден: " + value_file)
with open(value_file, encoding="utf-8-sig") as f:
args.Value = f.read().strip()
assert_edit_allowed(pkg_dir) assert_edit_allowed(pkg_dir)
SKILLS = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) SKILLS = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
@@ -323,7 +335,13 @@ def import_fragment(schema, xml):
if px and px not in ns: if px and px not in ns:
ns[px] = uri ns[px] = uri
decls = " ".join(f'xmlns:{k}="{v}"' for k, v in ns.items()) decls = " ".join(f'xmlns:{k}="{v}"' for k, v in ns.items())
try:
wrapped = etree.fromstring(f"<wrap {decls}>{xml}</wrap>".encode("utf-8")) wrapped = etree.fromstring(f"<wrap {decls}>{xml}</wrap>".encode("utf-8"))
except etree.XMLSyntaxError as e:
die("Не удалось разобрать -Value как фрагмент XML-схемы: " + str(e) + "\n"
+ "Получено: " + xml + "\n"
+ "Если фрагмент передан инлайном, кавычки могли схлопнуться на границе "
'процессов — положите его в файл и укажите -Value "@путь".')
res = [c for c in wrapped if isinstance(c.tag, str)] res = [c for c in wrapped if isinstance(c.tag, str)]
if not res: if not res:
die(f"Во фрагменте нет ни одного элемента: {xml}") die(f"Во фрагменте нет ни одного элемента: {xml}")
+2 -1
View File
@@ -1,7 +1,7 @@
--- ---
name: xdto-info name: xdto-info
description: Анализ структуры пакета XDTO 1С — типы, свойства, точки входа. Используй как подготовительный шаг при написании кода, создающего и заполняющего объект XDTO, при разборе входящего XML, а также чтобы узнать, какие пакеты есть в конфигурации description: Анализ структуры пакета XDTO 1С — типы, свойства, точки входа. Используй как подготовительный шаг при написании кода, создающего и заполняющего объект XDTO, при разборе входящего XML, а также чтобы узнать, какие пакеты есть в конфигурации
argument-hint: <PackagePath> [-Namespace <URI>|-Package <имя>] [-Name <Тип>] [-Depth N] [-Mode used-by] [-Limit N] [-Offset N] [-OutFile <файл>] argument-hint: <PackagePath> [-Namespace <URI>|-Package <имя>] [-Name <Тип>] [-Depth N] [-RequiredOnly] [-Mode used-by] [-Limit N] [-Offset N] [-OutFile <файл>]
allowed-tools: allowed-tools:
- Bash - Bash
- Read - Read
@@ -23,6 +23,7 @@ allowed-tools:
| `Package` | нет | Выбрать пакет по имени объекта метаданных | | `Package` | нет | Выбрать пакет по имени объекта метаданных |
| `Name` | нет | Имя типа. Без выбранного пакета ищется по всей конфигурации | | `Name` | нет | Имя типа. Без выбранного пакета ищется по всей конфигурации |
| `Depth` | нет | Глубина разузлования вложенных объектов. По умолчанию 1 | | `Depth` | нет | Глубина разузлования вложенных объектов. По умолчанию 1 |
| `RequiredOnly` | нет | Оставить только обязательные свойства — скелет для «заполни обязательное». Необязательный объект уходит вместе со своим содержимым |
| `Mode` | нет | `used-by` — показать, кто ссылается на тип | | `Mode` | нет | `used-by` — показать, кто ссылается на тип |
| `Limit` / `Offset` | нет | Пагинация. По умолчанию 150 строк | | `Limit` / `Offset` | нет | Пагинация. По умолчанию 150 строк |
| `OutFile` | нет | Записать результат в файл (UTF-8 BOM) | | `OutFile` | нет | Записать результат в файл (UTF-8 BOM) |
+53 -9
View File
@@ -10,6 +10,7 @@ param(
[ValidateSet("auto", "used-by")] [ValidateSet("auto", "used-by")]
[string]$Mode = "auto", [string]$Mode = "auto",
[int]$Depth = 1, [int]$Depth = 1,
[switch]$RequiredOnly,
[int]$Limit = 150, [int]$Limit = 150,
[int]$Offset = 0, [int]$Offset = 0,
[string]$OutFile [string]$OutFile
@@ -27,6 +28,13 @@ $MD_NS = "http://v8.1c.ru/8.3/MDClasses"
$sb = New-Object System.Text.StringBuilder $sb = New-Object System.Text.StringBuilder
function O([string]$line = "") { [void]$sb.AppendLine($line) } function O([string]$line = "") { [void]$sb.AppendLine($line) }
function Fail([string]$msg) {
# Отрицательный результат поиска — не исключение: печатаем сообщение
# и выходим с кодом 1, без стектрейса PowerShell
Write-Host $msg
exit 1
}
function Flush-Output { function Flush-Output {
$text = $sb.ToString().TrimEnd() $text = $sb.ToString().TrimEnd()
if ($OutFile) { if ($OutFile) {
@@ -46,7 +54,7 @@ function Flush-Output {
if (-not [System.IO.Path]::IsPathRooted($PackagePath)) { if (-not [System.IO.Path]::IsPathRooted($PackagePath)) {
$PackagePath = Join-Path (Get-Location).Path $PackagePath $PackagePath = Join-Path (Get-Location).Path $PackagePath
} }
if (-not (Test-Path $PackagePath)) { throw "Путь не найден: $PackagePath" } if (-not (Test-Path $PackagePath)) { Fail "Путь не найден: $PackagePath" }
$configRoot = $null $configRoot = $null
$directPkgDir = $null $directPkgDir = $null
@@ -70,7 +78,7 @@ if (Test-Path (Join-Path $PackagePath "Configuration.xml")) {
$configRoot = Split-Path (Split-Path $stem -Parent) -Parent $configRoot = Split-Path (Split-Path $stem -Parent) -Parent
} }
} }
if (-not $configRoot -and -not $directPkgDir) { throw "Не удалось определить пакет или конфигурацию по пути: $PackagePath" } if (-not $configRoot -and -not $directPkgDir) { Fail "Не удалось определить пакет или конфигурацию по пути: $PackagePath" }
# Sort-Object в PowerShell сортирует по культуре, sorted() в Python — по кодам. # Sort-Object в PowerShell сортирует по культуре, sorted() в Python — по кодам.
# Для паритета портов сортируем ординально в обоих. # Для паритета портов сортируем ординально в обоих.
@@ -130,7 +138,7 @@ if ($directPkgDir -and $packages.Count -eq 0) {
$p = Read-Package $directPkgDir $p = Read-Package $directPkgDir
if ($p) { [void]$packages.Add($p); $byNamespace[$p.Namespace] = $p } if ($p) { [void]$packages.Add($p); $byNamespace[$p.Namespace] = $p }
} }
if ($packages.Count -eq 0) { throw "Пакеты XDTO не найдены: $PackagePath" } if ($packages.Count -eq 0) { Fail "Пакеты XDTO не найдены: $PackagePath" }
# --- Type notation: XSD -> 1С --------------------------------------------------- # --- Type notation: XSD -> 1С ---------------------------------------------------
@@ -389,6 +397,20 @@ function Get-PropRows([System.Xml.XmlElement]$type, $pkg, [int]$depth, [int]$ind
return ,$rows return ,$rows
} }
# Оставить только обязательные свойства. Ребёнок необязательного объекта тоже
# уходит: он лежит под необязательной веткой и заполнять его не обязательно.
function Select-Required($rows) {
$res = New-Object System.Collections.ArrayList
$cutFrom = -1
foreach ($r in $rows) {
if ($cutFrom -ge 0 -and $r.Indent -gt $cutFrom) { continue }
$cutFrom = -1
if ($r.Flags -notcontains "обязательный") { $cutFrom = $r.Indent; continue }
[void]$res.Add($r)
}
return ,$res
}
function Write-Rows($rows) { function Write-Rows($rows) {
if ($rows.Count -eq 0) { O " (нет свойств)"; return } if ($rows.Count -eq 0) { O " (нет свойств)"; return }
$shown = $rows $shown = $rows
@@ -450,7 +472,10 @@ function Show-PackageOverview($pkg) {
O " $i$dep" O " $i$dep"
} }
} }
if ($pkg.GlobalProps.Count -gt 0) { if ($pkg.GlobalProps.Count -eq 0) {
O ""
O "Точки входа: нет — пакет не объявляет корневых элементов документа"
} else {
O "" O ""
O "Точки входа ($($pkg.GlobalProps.Count)) — корневые элементы документа:" O "Точки входа ($($pkg.GlobalProps.Count)) — корневые элементы документа:"
foreach ($gp in $pkg.GlobalProps) { foreach ($gp in $pkg.GlobalProps) {
@@ -540,13 +565,32 @@ function Show-Type($pkg, [string]$typeName) {
[void]$seen.Add("$($pkg.Namespace)#$typeName") [void]$seen.Add("$($pkg.Namespace)#$typeName")
$rows = Get-PropRows $el $pkg $Depth 0 $seen $rows = Get-PropRows $el $pkg $Depth 0 $seen
$own = @($rows | Where-Object { $_.Indent -eq 0 }) $own = @($rows | Where-Object { $_.Indent -eq 0 })
if ($RequiredOnly) {
$all = $rows.Count
$rows = Select-Required $rows
$ownReq = @($rows | Where-Object { $_.Indent -eq 0 })
# Фильтр обязан сообщать о себе: иначе список читается как полный
O "Свойства: обязательных $($ownReq.Count) из $($own.Count) (-RequiredOnly; скрыто строк: $($all - $rows.Count))"
} else {
O "Свойства ($($own.Count)):" O "Свойства ($($own.Count)):"
}
Write-Rows $rows Write-Rows $rows
Write-Legend $rows Write-Legend $rows
O "" O ""
O "Создание:" O "Создание:"
O " Тип = ФабрикаXDTO.Тип(`"$($pkg.Namespace)`", `"$typeName`");" O " Тип = ФабрикаXDTO.Тип(`"$($pkg.Namespace)`", `"$typeName`");"
O " Объект = ФабрикаXDTO.Создать(Тип);" O " Объект = ФабрикаXDTO.Создать(Тип);"
# Рецепты для вложенных и анонимных типов: имени у анонимного нет, через
# ФабрикаXDTO.Тип(ns, имя) его не получить — только от свойства владельца
$nested = @($rows | Where-Object { $_.Indent -eq 0 -and $_.Type -like "объект *" } | Select-Object -First 1)
if ($nested.Count -gt 0) {
O " Вложенный = ФабрикаXDTO.Создать(Тип.Свойства.Получить(`"$($nested[0].Name)`").Тип);"
}
$textProp = @($rows | Where-Object { $_.Flags -contains "значение элемента" } | Select-Object -First 1)
if ($textProp.Count -gt 0) {
O " // тип со значением элемента: значение задаётся при создании"
O " Узел = ФабрикаXDTO.Создать(ТипУзла, Значение);"
}
} }
function Show-UsedBy([string]$typeName, $ownerPkg) { function Show-UsedBy([string]$typeName, $ownerPkg) {
@@ -588,15 +632,15 @@ if ($directPkgDir) {
} }
if (-not $selected -and $Namespace) { if (-not $selected -and $Namespace) {
$selected = $packages | Where-Object { $_.Namespace -eq $Namespace } | Select-Object -First 1 $selected = $packages | Where-Object { $_.Namespace -eq $Namespace } | Select-Object -First 1
if (-not $selected) { throw "Пакет с namespace `"$Namespace`" не найден. Список: -PackagePath <корень> без параметров" } if (-not $selected) { Fail "Пакет с namespace `"$Namespace`" не найден. Список: -PackagePath <корень> без параметров" }
} }
if (-not $selected -and $Package) { if (-not $selected -and $Package) {
$selected = $packages | Where-Object { $_.Name -eq $Package } | Select-Object -First 1 $selected = $packages | Where-Object { $_.Name -eq $Package } | Select-Object -First 1
if (-not $selected) { throw "Пакет `"$Package`" не найден. Список: -PackagePath <корень> без параметров" } if (-not $selected) { Fail "Пакет `"$Package`" не найден. Список: -PackagePath <корень> без параметров" }
} }
if ($Mode -eq "used-by") { if ($Mode -eq "used-by") {
if (-not $Name) { throw "Режим used-by требует -Name <Тип>" } if (-not $Name) { Fail "Режим used-by требует -Name <Тип>" }
$ownerPkg = $selected $ownerPkg = $selected
if (-not $ownerPkg) { $ownerPkg = ($packages | Where-Object { $_.Types.ContainsKey($Name) } | Select-Object -First 1) } if (-not $ownerPkg) { $ownerPkg = ($packages | Where-Object { $_.Types.ContainsKey($Name) } | Select-Object -First 1) }
Show-UsedBy $Name $ownerPkg Show-UsedBy $Name $ownerPkg
@@ -608,7 +652,7 @@ if ($Name) {
if (-not $selected) { if (-not $selected) {
# Тип известен, пакет — нет: ищем по всей конфигурации # Тип известен, пакет — нет: ищем по всей конфигурации
$found = @($packages | Where-Object { $_.Types.ContainsKey($Name) }) $found = @($packages | Where-Object { $_.Types.ContainsKey($Name) })
if ($found.Count -eq 0) { throw "Тип `"$Name`" не найден ни в одном пакете конфигурации" } if ($found.Count -eq 0) { Fail "Тип `"$Name`" не найден ни в одном пакете конфигурации" }
if ($found.Count -gt 1) { if ($found.Count -gt 1) {
O "=== Тип `"$Name`" найден в нескольких пакетах ($($found.Count)) ===" O "=== Тип `"$Name`" найден в нескольких пакетах ($($found.Count)) ==="
O "Уточните через -Namespace или -Package:" O "Уточните через -Namespace или -Package:"
@@ -620,7 +664,7 @@ if ($Name) {
$selected = $found[0] $selected = $found[0]
} }
if (-not $selected.Types.ContainsKey($Name)) { if (-not $selected.Types.ContainsKey($Name)) {
throw "В пакете $($selected.Name) нет типа `"$Name`". Список типов: тот же вызов без -Name" Fail "В пакете $($selected.Name) нет типа `"$Name`". Список типов: тот же вызов без -Name"
} }
Show-Type $selected $Name Show-Type $selected $Name
Flush-Output Flush-Output
+40 -2
View File
@@ -20,6 +20,7 @@ parser.add_argument("-Namespace", default="")
parser.add_argument("-Name", default="") parser.add_argument("-Name", default="")
parser.add_argument("-Mode", default="auto", choices=["auto", "used-by"]) parser.add_argument("-Mode", default="auto", choices=["auto", "used-by"])
parser.add_argument("-Depth", type=int, default=1) parser.add_argument("-Depth", type=int, default=1)
parser.add_argument("-RequiredOnly", action="store_true")
parser.add_argument("-Limit", type=int, default=150) parser.add_argument("-Limit", type=int, default=150)
parser.add_argument("-Offset", type=int, default=0) parser.add_argument("-Offset", type=int, default=0)
parser.add_argument("-OutFile", default="") parser.add_argument("-OutFile", default="")
@@ -48,7 +49,9 @@ def flush_output():
def die(msg): def die(msg):
print(msg, file=sys.stderr) # Отрицательный результат поиска — не исключение: сообщение и код 1,
# без трассировки
print(msg)
sys.exit(1) sys.exit(1)
@@ -406,6 +409,22 @@ def get_prop_rows(type_el, pkg, depth, indent, seen):
return rows return rows
# Оставить только обязательные свойства. Ребёнок необязательного объекта тоже
# уходит: он лежит под необязательной веткой и заполнять его не обязательно.
def select_required(rows):
res = []
cut_from = -1
for r in rows:
if cut_from >= 0 and r["Indent"] > cut_from:
continue
cut_from = -1
if "обязательный" not in r["Flags"]:
cut_from = r["Indent"]
continue
res.append(r)
return res
def write_rows(rows): def write_rows(rows):
if not rows: if not rows:
O(" (нет свойств)") O(" (нет свойств)")
@@ -456,7 +475,10 @@ def show_package_overview(pkg):
for i in pkg.Imports: for i in pkg.Imports:
dep = by_namespace[i].Name if i in by_namespace else "(пакет не найден)" dep = by_namespace[i].Name if i in by_namespace else "(пакет не найден)"
O(f" {i}{dep}") O(f" {i}{dep}")
if pkg.GlobalProps: if not pkg.GlobalProps:
O("")
O("Точки входа: нет — пакет не объявляет корневых элементов документа")
else:
O("") O("")
O(f"Точки входа ({len(pkg.GlobalProps)}) — корневые элементы документа:") O(f"Точки входа ({len(pkg.GlobalProps)}) — корневые элементы документа:")
for gp in pkg.GlobalProps: for gp in pkg.GlobalProps:
@@ -546,6 +568,14 @@ def show_type(pkg, type_name):
seen = {f"{pkg.Namespace}#{type_name}"} seen = {f"{pkg.Namespace}#{type_name}"}
rows = get_prop_rows(el, pkg, DEPTH, 0, seen) rows = get_prop_rows(el, pkg, DEPTH, 0, seen)
own = [r for r in rows if r["Indent"] == 0] own = [r for r in rows if r["Indent"] == 0]
if args.RequiredOnly:
total = len(rows)
rows = select_required(rows)
own_req = [r for r in rows if r["Indent"] == 0]
# Фильтр обязан сообщать о себе: иначе список читается как полный
O(f"Свойства: обязательных {len(own_req)} из {len(own)} "
f"(-RequiredOnly; скрыто строк: {total - len(rows)})")
else:
O(f"Свойства ({len(own)}):") O(f"Свойства ({len(own)}):")
write_rows(rows) write_rows(rows)
write_legend(rows) write_legend(rows)
@@ -553,6 +583,14 @@ def show_type(pkg, type_name):
O("Создание:") O("Создание:")
O(f' Тип = ФабрикаXDTO.Тип("{pkg.Namespace}", "{type_name}");') O(f' Тип = ФабрикаXDTO.Тип("{pkg.Namespace}", "{type_name}");')
O(" Объект = ФабрикаXDTO.Создать(Тип);") O(" Объект = ФабрикаXDTO.Создать(Тип);")
# Рецепты для вложенных и анонимных типов: имени у анонимного нет, через
# ФабрикаXDTO.Тип(ns, имя) его не получить — только от свойства владельца
nested = next((r for r in rows if r["Indent"] == 0 and r["Type"].startswith("объект ")), None)
if nested:
O(f' Вложенный = ФабрикаXDTO.Создать(Тип.Свойства.Получить("{nested["Name"]}").Тип);')
if any("значение элемента" in r["Flags"] for r in rows):
O(" // тип со значением элемента: значение задаётся при создании")
O(" Узел = ФабрикаXDTO.Создать(ТипУзла, Значение);")
def show_used_by(type_name, owner_pkg): def show_used_by(type_name, owner_pkg):
@@ -266,7 +266,7 @@ if ($anyTypeProps.Count -gt 0 -and $imports.Count -gt 0) {
$names = @() $names = @()
foreach ($p in $anyTypeProps) { if ($p.HasAttribute("name")) { $names += $p.GetAttribute("name") } } foreach ($p in $anyTypeProps) { if ($p.HasAttribute("name")) { $names += $p.GetAttribute("name") } }
$shown = ($names | Select-Object -First 5) -join ", " $shown = ($names | Select-Object -First 5) -join ", "
Report-Warn "Свойств с type=`"xs:anyType`": $($anyTypeProps.Count) при объявленных импортах ($shown). Возможна тихая деградация: при импорте XML-схемы платформа заменяет неразрешённый чужой тип на anyType без ошибки" Report-Warn "Свойств с type=`"xs:anyType`": $($anyTypeProps.Count) при объявленных импортах ($shown). Тип не разрешён — заполнить структурно такое свойство нельзя. Обычно это след импорта XML-схемы: платформа заменяет неразрешённый чужой тип на anyType без ошибки"
} }
# --- 7. Unused imports --- # --- 7. Unused imports ---
@@ -293,7 +293,7 @@ if any_type_props and imports:
shown = ", ".join(names[:5]) shown = ", ".join(names[:5])
report_warn( report_warn(
f'Свойств с type="xs:anyType": {len(any_type_props)} при объявленных импортах ({shown}). ' f'Свойств с type="xs:anyType": {len(any_type_props)} при объявленных импортах ({shown}). '
"Возможна тихая деградация: при импорте XML-схемы платформа заменяет неразрешённый " "Тип не разрешён — заполнить структурно такое свойство нельзя. Обычно это след импорта XML-схемы: платформа заменяет неразрешённый "
"чужой тип на anyType без ошибки" "чужой тип на anyType без ошибки"
) )
@@ -2,8 +2,8 @@
<objectType name="Документ"> <objectType name="Документ">
<property name="Версия" type="xs:string" form="Attribute"/> <property name="Версия" type="xs:string" form="Attribute"/>
<property name="Первый" type="xs:string"/> <property name="Первый" type="xs:string"/>
<property name="ВариантА" type="xs:string"/> <property name="ВариантА" type="xs:string" lowerBound="0"/>
<property name="ВариантБ" type="xs:string"/> <property name="ВариантБ" type="xs:string" lowerBound="0"/>
<property name="ИзГруппы" type="xs:string"/> <property name="ИзГруппы" type="xs:string"/>
<property name="Повторяемый" type="xs:string"/> <property name="Повторяемый" type="xs:string"/>
</objectType> </objectType>
@@ -0,0 +1,31 @@
{
"name": "-RequiredOnly: скелет обязательных, необязательный объект уходит с поддеревом",
"caseFiles": [
"nested.xsd"
],
"preRun": [
{
"script": "xdto-compile/scripts/xdto-compile",
"args": {
"-XsdPath": "{workDir}/nested.xsd",
"-OutputDir": "{workDir}"
}
}
],
"params": {
"packagePath": "XDTOPackages/nested",
"outFile": "required-only.txt"
},
"args_extra": [
"-Name",
"Документ",
"-Depth",
"3",
"-RequiredOnly"
],
"expect": {
"files": [
"required-only.txt"
]
}
}
@@ -14,3 +14,4 @@
Создание: Создание:
Тип = ФабрикаXDTO.Тип("urn:test:uses", "Заявка"); Тип = ФабрикаXDTO.Тип("urn:test:uses", "Заявка");
Объект = ФабрикаXDTO.Создать(Тип); Объект = ФабрикаXDTO.Создать(Тип);
Вложенный = ФабрикаXDTO.Создать(Тип.Свойства.Получить("Вид").Тип);
@@ -18,3 +18,6 @@
Создание: Создание:
Тип = ФабрикаXDTO.Тип("urn:test:nested", "Документ"); Тип = ФабрикаXDTO.Тип("urn:test:nested", "Документ");
Объект = ФабрикаXDTO.Создать(Тип); Объект = ФабрикаXDTO.Создать(Тип);
Вложенный = ФабрикаXDTO.Создать(Тип.Свойства.Получить("Реквизиты").Тип);
// тип со значением элемента: значение задаётся при создании
Узел = ФабрикаXDTO.Создать(ТипУзла, Значение);
@@ -0,0 +1,252 @@
<?xml version="1.0" encoding="utf-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Configuration uuid="UUID-001">
<InternalInfo>
<xr:ContainedObject>
<xr:ClassId>UUID-002</xr:ClassId>
<xr:ObjectId>UUID-003</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-004</xr:ClassId>
<xr:ObjectId>UUID-005</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-006</xr:ClassId>
<xr:ObjectId>UUID-007</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-008</xr:ClassId>
<xr:ObjectId>UUID-009</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-010</xr:ClassId>
<xr:ObjectId>UUID-011</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-012</xr:ClassId>
<xr:ObjectId>UUID-013</xr:ObjectId>
</xr:ContainedObject>
<xr:ContainedObject>
<xr:ClassId>UUID-014</xr:ClassId>
<xr:ObjectId>UUID-015</xr:ObjectId>
</xr:ContainedObject>
</InternalInfo>
<Properties>
<Name>TestConfig</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>TestConfig</v8:content>
</v8:item>
</Synonym>
<Comment />
<NamePrefix />
<ConfigurationExtensionCompatibilityMode>Version8_3_24</ConfigurationExtensionCompatibilityMode>
<DefaultRunMode>ManagedApplication</DefaultRunMode>
<UsePurposes>
<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
</UsePurposes>
<ScriptVariant>Russian</ScriptVariant>
<DefaultRoles />
<Vendor></Vendor>
<Version></Version>
<UpdateCatalogAddress />
<IncludeHelpInContents>false</IncludeHelpInContents>
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
<UseOrdinaryFormInManagedApplication>false</UseOrdinaryFormInManagedApplication>
<AdditionalFullTextSearchDictionaries />
<CommonSettingsStorage />
<ReportsUserSettingsStorage />
<ReportsVariantsStorage />
<FormDataSettingsStorage />
<DynamicListsUserSettingsStorage />
<URLExternalDataStorage />
<Content />
<DefaultReportForm />
<DefaultReportVariantForm />
<DefaultReportSettingsForm />
<DefaultReportAppearanceTemplate />
<DefaultDynamicListSettingsForm />
<DefaultSearchForm />
<DefaultDataHistoryChangeHistoryForm />
<DefaultDataHistoryVersionDataForm />
<DefaultDataHistoryVersionDifferencesForm />
<DefaultCollaborationSystemUsersChoiceForm />
<RequiredMobileApplicationPermissions />
<UsedMobileApplicationFunctionalities>
<app:functionality>
<app:functionality>Biometrics</app:functionality>
<app:use>true</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Location</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundLocation</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BluetoothPrinters</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>WiFiPrinters</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Contacts</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Calendars</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PushNotifications</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>LocalNotifications</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>InAppPurchases</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PersonalComputerFileExchange</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Ads</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>NumberDialing</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>CallProcessing</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>CallLog</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AutoSendSMS</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>ReceiveSMS</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>SMSLog</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Camera</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Microphone</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>MusicLibrary</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>PictureAndVideoLibraries</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AudioPlaybackAndVibration</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundAudioPlaybackAndVibration</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>InstallPackages</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>OSBackup</app:functionality>
<app:use>true</app:use>
</app:functionality>
<app:functionality>
<app:functionality>ApplicationUsageStatistics</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BarcodeScanning</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>BackgroundAudioRecording</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AllFilesAccess</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Videoconferences</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>NFC</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>DocumentScanning</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>SpeechToText</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>Geofences</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>IncomingShareRequests</app:functionality>
<app:use>false</app:use>
</app:functionality>
<app:functionality>
<app:functionality>AllIncomingShareRequestsTypesProcessing</app:functionality>
<app:use>false</app:use>
</app:functionality>
</UsedMobileApplicationFunctionalities>
<StandaloneConfigurationRestrictionRoles />
<MobileApplicationURLs />
<AllowedIncomingShareRequestTypes />
<MainClientApplicationWindowMode>Normal</MainClientApplicationWindowMode>
<DefaultInterface />
<DefaultStyle />
<DefaultLanguage>Language.Русский</DefaultLanguage>
<BriefInformation />
<DetailedInformation />
<Copyright />
<VendorInformationAddress />
<ConfigurationInformationAddress />
<DataLockControlMode>Managed</DataLockControlMode>
<ObjectAutonumerationMode>NotAutoFree</ObjectAutonumerationMode>
<ModalityUseMode>DontUse</ModalityUseMode>
<SynchronousPlatformExtensionAndAddInCallUseMode>DontUse</SynchronousPlatformExtensionAndAddInCallUseMode>
<InterfaceCompatibilityMode>TaxiEnableVersion8_2</InterfaceCompatibilityMode>
<DatabaseTablespacesUseMode>DontUse</DatabaseTablespacesUseMode>
<CompatibilityMode>Version8_3_24</CompatibilityMode>
<DefaultConstantsForm />
</Properties>
<ChildObjects>
<Language>Русский</Language>
<XDTOPackage>nested</XDTOPackage>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<ClientApplicationInterface xmlns="http://v8.1c.ru/8.2/managed-application/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="InterfaceLayouter">
<top>
<panel id="UUID-001">
<uuid>UUID-002</uuid>
</panel>
</top>
<left>
<panel id="UUID-003">
<uuid>UUID-004</uuid>
</panel>
</left>
<panelDef id="UUID-004"/>
<panelDef id="UUID-005"/>
<panelDef id="UUID-006"/>
<panelDef id="UUID-002"/>
<panelDef id="UUID-007"/>
</ClientApplicationInterface>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<Language uuid="UUID-001">
<Properties>
<Name>Русский</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Русский</v8:content>
</v8:item>
</Synonym>
<Comment/>
<LanguageCode>ru</LanguageCode>
</Properties>
</Language>
</MetaDataObject>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
<XDTOPackage uuid="UUID-001">
<Properties>
<Name>nested</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>nested</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Namespace>urn:test:nested</Namespace>
</Properties>
</XDTOPackage>
</MetaDataObject>
@@ -0,0 +1,15 @@
<package xmlns="http://v8.1c.ru/8.1/xdto" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="urn:test:nested">
<objectType name="Документ">
<property xmlns:d3p1="urn:test:nested" name="Реквизиты" type="d3p1:Реквизиты"/>
<property xmlns:d3p1="urn:test:nested" name="Дочерний" type="d3p1:Документ" lowerBound="0" upperBound="-1"/>
<property name="Встроенный">
<typeDef xsi:type="ObjectType">
<property name="Ид" type="xs:string" form="Attribute"/>
<property name="__content" type="xs:date" form="Text"/>
</typeDef>
</property>
</objectType>
<objectType name="Реквизиты">
<property name="Наименование" type="xs:string"/>
</objectType>
</package>
@@ -0,0 +1,20 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="urn:test:nested" targetNamespace="urn:test:nested">
<xs:complexType name="Документ">
<xs:sequence>
<xs:element name="Реквизиты" type="tns:Реквизиты"/>
<xs:element name="Дочерний" type="tns:Документ" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Встроенный">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:date">
<xs:attribute name="Ид" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Реквизиты">
<xs:sequence><xs:element name="Наименование" type="xs:string"/></xs:sequence>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,20 @@
=== Тип XDTO: Документ === (глубина 3)
Пакет: nested · urn:test:nested
Свойства: обязательных 2 из 3 (-RequiredOnly; скрыто строк: 2)
Реквизиты объект Реквизиты [обязательный]
Наименование Строка [обязательный]
Встроенный объект (анонимный) [обязательный]
Ид Строка [обязательный]
__content Дата [обязательный, значение элемента]
Обозначения:
объект X — присвоить вложенный объект XDTO, состав раскрывает -Depth
значение элемента — собственное значение узла XML
Создание:
Тип = ФабрикаXDTO.Тип("urn:test:nested", "Документ");
Объект = ФабрикаXDTO.Создать(Тип);
Вложенный = ФабрикаXDTO.Создать(Тип.Свойства.Получить("Реквизиты").Тип);
// тип со значением элемента: значение задаётся при создании
Узел = ФабрикаXDTO.Создать(ТипУзла, Значение);
@@ -7,7 +7,7 @@
"params": { "packagePath": "pkg-anytype/XDTOPackages/anytype" }, "params": { "packagePath": "pkg-anytype/XDTOPackages/anytype" },
"expect": { "expect": {
"stdoutContains": [ "stdoutContains": [
"тихая деградация", "Тип не разрешён",
"признак неразрешённой зависимости" "признак неразрешённой зависимости"
] ]
}, },