Decode SCD data sources from live XML
This commit is contained in:
@@ -76,6 +76,24 @@ parameters, layouts, nested schemas и settings. Макет оформления
|
||||
Работа выполняется последовательно по этому реестру: новый тип не получает
|
||||
write endpoint до собственной fixture и доказанного обратного carrier codec-а.
|
||||
|
||||
## Live XML evidence: базовая СКД
|
||||
|
||||
14.08.2026 read-only diagnostic read подтвердил carrier для
|
||||
`Report.ФинансовыйРезультат / ОсновнаяСхемаКомпоновкиДанных`:
|
||||
|
||||
- Template GUID: `e3140fc8-1688-4640-a68a-e0f7675c68e9`; payload: `.0`;
|
||||
- контейнер: 3 391 байт raw-deflate, после распаковки 23 097 байт;
|
||||
- XML envelope: `SchemaFile`, 12 941 символ до закрывающего тега;
|
||||
- прямые дочерние секции `dataCompositionSchema`: `dataSource` (1),
|
||||
`dataSet` (1), `parameter` (4), `settingsVariant` (1), `totalField` (4);
|
||||
- `dataSource` имеет доказанные прямые поля `name=ИсточникДанных1` и
|
||||
`dataSourceType=Local`.
|
||||
|
||||
На этом доказательстве в decoder добавлена секция `data_sources` и
|
||||
`schema_outline` с точными XML тегами, путями и количеством. Наличие
|
||||
`dataSetLink`, layouts или nested schema в другой СКД не предполагается: они
|
||||
будут добавлены после отдельной live fixture с соответствующим тегом.
|
||||
|
||||
## Ближайшая реализация
|
||||
|
||||
Первый кодовый результат — resolver, который умеет различать форму и макет,
|
||||
|
||||
@@ -36071,7 +36071,7 @@ def scd_inspect(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
if not report:
|
||||
return invalid_argument(method, "report", "report is required as a public 1C report name.")
|
||||
schema_name = str(payload.get("schema") or "").strip()
|
||||
requested_sections = payload.get("sections") or ["parameters", "datasets", "fields", "calculated_fields", "resources", "settings", "variants", "total_fields"]
|
||||
requested_sections = payload.get("sections") or ["data_sources", "parameters", "datasets", "fields", "calculated_fields", "resources", "settings", "variants", "total_fields"]
|
||||
if not isinstance(requested_sections, list) or not all(isinstance(item, str) for item in requested_sections):
|
||||
return invalid_argument(method, "sections", "sections must be an array of strings.")
|
||||
resolve_metadata, resolve_metadata_error = strict_bool_argument(payload, "resolve_metadata", method=method, default=True)
|
||||
|
||||
@@ -161,6 +161,10 @@ def scd_node_item(root: ET.Element, node: ET.Element, category: str) -> dict[str
|
||||
item["value_type"] = value_type
|
||||
if category == "datasets":
|
||||
item["type"] = node.attrib.get("{http://www.w3.org/2001/XMLSchema-instance}type") or node.attrib.get("type") or ""
|
||||
if category == "data_sources":
|
||||
data_source_type = child_text(node, "dataSourceType")
|
||||
if data_source_type:
|
||||
item["data_source_type"] = data_source_type
|
||||
return item
|
||||
|
||||
|
||||
@@ -171,7 +175,7 @@ def inspect_scd_payload(data: bytes, *, sections: list[str] | None = None) -> di
|
||||
synthesized from report code or form attributes.
|
||||
"""
|
||||
|
||||
requested = sections or ["parameters", "datasets", "fields", "calculated_fields", "resources", "settings", "variants", "total_fields"]
|
||||
requested = sections or ["data_sources", "parameters", "datasets", "fields", "calculated_fields", "resources", "settings", "variants", "total_fields"]
|
||||
root, container = xml_from_scd_payload(data)
|
||||
if root is None:
|
||||
return {"status": "partial", "container": container, "sections": {name: [] for name in requested}}
|
||||
@@ -198,6 +202,7 @@ def inspect_scd_payload(data: bytes, *, sections: list[str] | None = None) -> di
|
||||
tag = local_name(node.tag)
|
||||
xml_tag_counts[tag] = xml_tag_counts.get(tag, 0) + 1
|
||||
node_names = {
|
||||
"data_sources": {"dataSource"},
|
||||
"parameters": {"parameter"},
|
||||
"datasets": {"dataSet"},
|
||||
"fields": {"field"},
|
||||
|
||||
@@ -211,6 +211,7 @@ def test_dbnames_version_parser_accepts_utf8_bom_scalar_version() -> None:
|
||||
def test_scd_payload_decoder_reads_xml_after_platform_prefix() -> None:
|
||||
xml = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<SchemaFile><dataCompositionSchema>
|
||||
<dataSource><name>ИсточникДанных1</name><dataSourceType>Local</dataSourceType></dataSource>
|
||||
<dataSet xsi:type="DataSetQuery" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><name>ОсновнойНабор</name><query>ВЫБРАТЬ &Период КАК Период // &Скрытый КАК Скрытый</query></dataSet>
|
||||
<parameter><name>Период</name><valueType>xs:dateTime</valueType></parameter>
|
||||
<field><dataPath>Период</dataPath></field>
|
||||
@@ -226,6 +227,7 @@ def test_scd_payload_decoder_reads_xml_after_platform_prefix() -> None:
|
||||
|
||||
assert result["status"] == "ok"
|
||||
assert result["container"]["compression"] == "raw_deflate"
|
||||
assert result["sections"]["data_sources"] == [{"name": "ИсточникДанных1", "source": {"kind": "scd_xml", "path": "/dataCompositionSchema[1]/dataSource"}, "data_source_type": "Local"}]
|
||||
assert result["sections"]["parameters"] == [{"name": "Период", "source": {"kind": "scd_xml", "path": "/dataCompositionSchema[1]/parameter"}, "value_type": "xs:dateTime"}]
|
||||
assert result["sections"]["datasets"][0]["query"] == "ВЫБРАТЬ &Период КАК Период // &Скрытый КАК Скрытый"
|
||||
assert result["sections"]["calculated_fields"][0]["expression"] == "Сумма * 1.2"
|
||||
@@ -236,13 +238,14 @@ def test_scd_payload_decoder_reads_xml_after_platform_prefix() -> None:
|
||||
"top_level": [
|
||||
{"tag": "calculatedField", "count": 1, "paths": ["/dataCompositionSchema[1]/calculatedField"]},
|
||||
{"tag": "dataSet", "count": 1, "paths": ["/dataCompositionSchema[1]/dataSet"]},
|
||||
{"tag": "dataSource", "count": 1, "paths": ["/dataCompositionSchema[1]/dataSource"]},
|
||||
{"tag": "field", "count": 2, "paths": ["/dataCompositionSchema[1]/field", "/dataCompositionSchema[1]/field[2]"]},
|
||||
{"tag": "parameter", "count": 1, "paths": ["/dataCompositionSchema[1]/parameter"]},
|
||||
{"tag": "resource", "count": 1, "paths": ["/dataCompositionSchema[1]/resource"]},
|
||||
{"tag": "settingsVariant", "count": 1, "paths": ["/dataCompositionSchema[1]/settingsVariant"]},
|
||||
{"tag": "totalField", "count": 1, "paths": ["/dataCompositionSchema[1]/totalField"]},
|
||||
],
|
||||
"all_tag_counts": {"calculatedField": 1, "dataCompositionSchema": 1, "dataPath": 2, "dataSet": 1, "expression": 2, "field": 2, "name": 5, "parameter": 1, "query": 1, "resource": 1, "settingsVariant": 1, "totalField": 1, "valueType": 1},
|
||||
"all_tag_counts": {"calculatedField": 1, "dataCompositionSchema": 1, "dataPath": 2, "dataSet": 1, "dataSource": 1, "dataSourceType": 1, "expression": 2, "field": 2, "name": 6, "parameter": 1, "query": 1, "resource": 1, "settingsVariant": 1, "totalField": 1, "valueType": 1},
|
||||
}
|
||||
assert result["analysis"]["referenced_not_declared_in_schema"] == []
|
||||
assert result["analysis"]["total_field_references"] == {"fields": ["Сумма"], "missing_from_declared_fields": [], "status": "checked"}
|
||||
|
||||
Reference in New Issue
Block a user