UPD. 20190917 Доработан скрипт сравнения/объединения. Добавлен контроль уникальности кодов справочника "Правила регистрации объектов". В предыдущем варианте при загрузке правил в конфигурацию "Конвертация данных 2" из-за дублирующихся кодов возникали ошибки. Скрипт в статье обновлен.
Правила регистрации актуальны и используются практически во всех типовых обменах 1С, независимо от формата обмена. При параллельной разработке правил регистрации возникает проблема объединения нескольких вариантов правил. Простое сравнение объединение XML невозможно. Т.к. готового инструмента найти не получилось был написан свой скрипт.
import xml.dom.minidom as minidom
import argparse
import re
import sys
#скрипт преобразует xml файлы правил регистрации в структуру заполненную узлами заголовка, состава плана обмена
#и правил регистрации с указанием различаются ли значения заполнения этих узлов
#заголовком считаются теги описания правил вцелом, т.е. все теги кроме <СоставПланаОбмена> и <ПравилаРегистрацииОбъектов>
#сравнение узлов заголовков выполняется по имени тега, т.к. для заголовка уникальны
#сравнение узлов состава плана обмена выполняется по узлам <Элемент> уникальность узла определяется значением тега <Тип>
#узла <Элемент>, т.к. на использования нескольких правил регистрации на один тип объекта в пределах плана обмена
#не представляется возможным
#сравнение узлов правил регистрации объета выполняется по узлам <Правило> уникальность определяется по значению тега <ОбъектНастройки>,
#т.к. на использования нескольких правил регистрации на один тип объекта в пределах плана обмена
#не представляется возможным. При сравнении правил возникает проблема анализа тегов <ОтборПоСвойствамОбъекта> и <ОтборПоСвойствамПланаОБмена>
#т.к. невозможно однозначно идентифицировать узлы <ЭлементОтбора> и <Группа> входящие в отборы
#для обеспечения идентификации к имени тега добавляется числовой индекс уникальный в пределах сравниваемого отбора или группы
#таким образом сравнение элементов отбора и групп выполняется в порядке их появления.
#при сравнении элементов отбора их различия в результирующий файл заносятся в виде двух секций
#первая секция содержит настройки из первого файла
#вторая из второго, какую секцию оставить определяем самостоятельно при просмотре результата объединения
"""
При загрузке результата объединения в Конвертацию данных 2, могут возникнуть ошибки из-за дублирования кодов
внутри справочника правил регистрации объектов.
Для обеспечения уникальности ключей в результате объединения предусмотрена list таблица mergedKeys,
которая используется проверки всех кодов на уникальность для режимов soft и hard.
Для режима manual контроль уникальности кодов производится только для определенных значений (!=undefined).
Если значение кода определено, то оно проверяется на уникальность и заменяется на новое если значение кода не уникально
"""
#объединение выполняется в следующих режимах:
#- soft(default) приоритет первого файла:
# в первый файл принимаются только отсутствующие в первом элементы состава и правила из второго файла
#- manual обновление:
# в первом файле обновляется содержимое элементов состава и правил присутствующих в обоих файлах.
# и добавляются элементы состава и правила присутствующие только во втором файле,
# отсутствующие во втором файле элементы состава и правила остаются неизмененными
# элементы настроек правил объединяются со значениями второго файла,
# а настройки отборов объединяются в порядке их следования
# результирующий файл требует ручного редактирования.
#- hard обновление:
# существующие в обоих файлах элементы состава и правила заменяются на значения второго файла,
# отсутствующие во втором файле элементы состав и правил остаются неизмененными
#.
#полная замена первого файла на второй данным скриптом не производится.
#
#.
#Глобальные переменные для единообразного заполения полей
undefined = "Undefined"
diffKey = "Diff"
itemExist = "Exist"
attrKey = "Attributes"
#list таблица для контроля уникальности заполнения тегов с именем Код
#если код уже есть в таблице, то генерится новое значение кода, как максимальный
#код в преобразованный в число+1, далее код преобразуется в строку дополненную "0"
#длина кода 9 символов тип строка
mergedKeys = []
#теги исключаемые из обработки вывода правил
outputExcludeKeys = [diffKey, itemExist, attrKey]
#теги заголовка файла правил исключаемые из анализа заголовка и анализируемые самостоятельно
excludeHeaderNodes = ["СоставПланаОбмена", "ПравилаРегистрацииОбъектов"]
#теги которые надо обрабатывать обходом дерева при анализе правила
ruleFilterTreeTags = ["ОтборПоСвойствамПланаОбмена", "ОтборПоСвойствамОбъекта"]
ruleFilterItemsTreeTags = ["ТаблицаСвойствОбъекта","ТаблицаСвойствПланаОбмена","Свойство"]
#теги описания группы правил регистрации, все остальные теги это правила регистрации, которые надо сравнивать
#другим способом
#Exist - служебный тег добавляемый при построении структуры результатов сравнения
#позволяет определить существует ли структура содержащая данный тег в определенном файле или нет
regRulesGroupTags = ["Код", "Наименование", "ТипГруппы", itemExist]
#теги описания правила регистрации объекта, которые могут содержать только буквенно цифровую информацию
regRuleTags = ["Код", "ОбъектНастройки", "ОбъектМетаданныхИмя", "ОбъектМетаданныхТип"]
class RulesStructure:
def __init__(self):
self.Header = None
self.ExhangeComposition = None
self.RegRules = None
def ClearSpecChars(str):
reg = re.compile('[^a-zA-Z0-9а-яА-Я\._]')
return reg.sub('',str)
def ClearNoneNamedNodes(tree):
#удалим все узлы без локального имени
noneNamedNodes = []
for node in tree.childNodes:
if node.localName == None:
noneNamedNodes.append(node)
#чистим переданное дерево, т.к. если
#использовать рекурсию можно поудалять
#элементы у которых есть подчиненные не именованные узлы
for node in noneNamedNodes:
tree.removeChild(node)
def ReadRulesIntoStructure(xmlFilePath):
doc = minidom.parse(xmlFilePath)
rulesStruct = RulesStructure()
#разбиваем файлы на составные секции, которые и будем сравнивать
#корневой узел правил
rulesStruct.Header = doc.getElementsByTagName("ПравилаРегистрации")[0]
ClearNoneNamedNodes(rulesStruct.Header)
#узел описания состава плана обмена
rulesStruct.ExhangeComposition = doc.getElementsByTagName("СоставПланаОбмена")[0]
ClearNoneNamedNodes(rulesStruct.ExhangeComposition)
#узел описания правил регистрации объектов
rulesStruct.RegRules = doc.getElementsByTagName("ПравилаРегистрацииОбъектов")[0]
ClearNoneNamedNodes(rulesStruct.RegRules)
return rulesStruct
def GetNodeKey(node, keyTag):
keyNode = node.getElementsByTagName(keyTag)[0]
return ClearSpecChars(keyNode.firstChild.nodeValue)
def GetCompareNodeFromStructure(parent, key):
#Добавляем узел к родителю
if parent.get(key) == None:
parent[key] = {}
#значение элемента сравнения содержит два hash по одному на каждый сравниваемый файл
#
def SetCompareItemValue(node, key, val):
if node.get(key) == None: #не найдено значение с ключем key
node[key] = undefined #создаем не определенное значение
if node[key] == undefined: #если значение не определено заполняем его переданными данными
node[key] = val
def SetCompareNodeItemIntoStructure(node, val1, val2):
SetCompareItemValue(node, firstXMLFilePath, val1)
SetCompareItemValue(node, secondXMLFilePath, val2)
def SetNodeAttributesTag(parent, fileNode, first):
"""
вычитываем аттрибуты для переданного узла и записываем их в структуру сравнения
"""
if hasattr(fileNode, "attributes"):
if hasattr(fileNode.attributes,"length") and fileNode.attributes.length > 0:
if parent.get(attrKey) == None:
parent[attrKey] = {}
for attr in fileNode.attributes._attrs:
attrNode = fileNode.attributes._attrs[attr]
GetNodeWithValue(parent[attrKey], attr, attrNode, first)
def GetFileNodeVal(node):
val = undefined
if node.childNodes.length > 0:
val = node.firstChild.nodeValue
return val
def SetItemExistTag(parent, nodeKey, first=True):
GetCompareNodeFromStructure(parent[nodeKey], itemExist) #служебный реквизит для определения присутствия элемента в файлах
if first == True:
SetCompareNodeItemIntoStructure(parent[nodeKey][itemExist], nodeKey, undefined)
else:
SetCompareNodeItemIntoStructure(parent[nodeKey][itemExist], undefined, nodeKey)
def GetNodeWithExistTag(parent, nodeKey, fileNode, first=True, nodeTag=""):
GetCompareNodeFromStructure(parent, nodeKey) #сформировали узел элемента
#служебный реквизит для определения присутствия элемента в файлах
SetItemExistTag(parent, nodeKey, first)
SetNodeAttributesTag(parent[nodeKey], fileNode, first)
def GetNodeWithValue(parent, nodeKey, fileNode, first=True, nodeTag=""):
GetCompareNodeFromStructure(parent, nodeKey) #в узле сравнения хранятся значения тегов для каждого файла и результат сравнения
val = GetFileNodeVal(fileNode)
if first == True:
SetCompareNodeItemIntoStructure(parent[nodeKey], val, undefined)
else:
SetCompareNodeItemIntoStructure(parent[nodeKey], undefined, val)
SetNodeAttributesTag(parent[nodeKey], fileNode, first)
def ScanFileHeaders(fileHeaders, compareNode, first=True):
for node in fileHeaders:
#теги описания заголовка правил.
#теги СоставПланаОбмена и ПравилаРегистрацииОбъектов исключаются, т.к.
#их содержимое сравнивается отдельно от заголовка
if excludeHeaderNodes.count(node.localName) == 0:
#т.к. теги в заголовке уникальны, то определеям узел по тегу
#в узле сравнения хранятся значения тегов для каждого файла и результат сравнения
GetNodeWithValue(compareNode, node.localName, node, first)
def GetNodeValuesDiff(node):
return (node[firstXMLFilePath] != node[secondXMLFilePath])
def CompareAttributes(node):
nodeDiff = False
if node.get(attrKey) != None:
for attr in node[attrKey]:
attrNode = node[attrKey][attr]
attrDiff = GetNodeValuesDiff(attrNode)
attrNode[diffKey] = attrDiff
nodeDiff = (nodeDiff or attrDiff)
return nodeDiff
def CompareHeaders():
#заполняем элементы заголовков из двух файлов
#для последующего сравнения
compareStructure.Header = {}
ScanFileHeaders(first.Header.childNodes, compareStructure.Header, True)
ScanFileHeaders(second.Header.childNodes, compareStructure.Header, False)
headersDiff = False
#сравниваем узлы заголовков и фиксируем отличия
for compareKey in compareStructure.Header.keys():
compareNode = compareStructure.Header[compareKey]
nodeDiff = GetNodeValuesDiff(compareNode)
nodeDiff = (nodeDiff or CompareAttributes(compareNode))
compareNode[diffKey] = nodeDiff
headersDiff = (headersDiff or nodeDiff)
compareStructure.Header[diffKey] = headersDiff
def ScanFileExchangeComposition(fileExchangeComposition, compareNode, first=True):
#формируем структуру сравнения по файлу
for item in fileExchangeComposition: # Обход <Элемент></Элемент>
#у элемента нет значения, поэтому вычищаем подчиненные элементы без имени
ClearNoneNamedNodes(item)
#каждый элемент состава записывается в hash для последующего сравнения его полей и значения
nodeKey = GetNodeKey(item, "Тип")
#сформировали узел элемента
GetNodeWithExistTag(compareNode, nodeKey, item, first, "Элемент")
for node in item.childNodes: #Обход реквизитов элемента
#т.к. внутри элемента теги уникальны идентифицируем их по имени
GetNodeWithValue(compareNode[nodeKey], node.localName, node, first)
def CompareExchangeComposition():
#сравнение составов планов обменов указанных в правилах
compareStructure.ExhangeComposition = {}
#формируем структуру сравнения по первому файлу
ScanFileExchangeComposition(first.ExhangeComposition.childNodes, compareStructure.ExhangeComposition, True)
#дополняем структуру сравнения по второму файлу
ScanFileExchangeComposition(second.ExhangeComposition.childNodes, compareStructure.ExhangeComposition, False)
exchDiff = False
#сравниваем значения всех узлов структуры и регистрируем расхождения
for compareKey in compareStructure.ExhangeComposition.keys(): # Обход <Элемент></Элемент>
item = compareStructure.ExhangeComposition[compareKey]
itemDiff = False
for tagKey in item.keys(): # обход тегов элементов
#в описании состава плана обмена имена объектов не могут содержать спец символов
#поэтому при сравнении вычищаем их
tagNode = item[tagKey]
val1 = ClearSpecChars(tagNode[firstXMLFilePath])
val2 = ClearSpecChars(tagNode[secondXMLFilePath])
diff = ((val1 != val2) or CompareAttributes(tagNode))
item[tagKey][diffKey] = diff
itemDiff = (itemDiff or diff)
item[diffKey] = itemDiff
exchDiff = (exchDiff or itemDiff)
compareStructure.ExhangeComposition[diffKey] = exchDiff
def ScanOptionsTableFromFilterItem(fileNode, parent, first):
"""сканируем ТаблицаСвойствОбъекта или ТаблицаСвойствПланаОбмена"""
nodeKey = fileNode.localName
ClearNoneNamedNodes(fileNode)
GetNodeWithExistTag(parent, nodeKey, fileNode, first)
for property in fileNode.childNodes:#читаем тег свойство
ClearNoneNamedNodes(property)
GetNodeWithExistTag(parent[nodeKey], property.localName, property, first)
for tag in property.childNodes:
GetNodeWithValue(parent[nodeKey][property.localName], tag.localName, tag, first)
def ScanFilterItemFromFilterNode(fileNode, parent, itemID, first):
"""
элемент отбора может содержать до двух специфических секций
ТаблицаСвойствОбъекта и ТаблицаСвойствПланаОбмена в зависимости
от типа отбора
"""
nodeKey = "ЭлементОтбора_"+str(itemID)
ClearNoneNamedNodes(fileNode)
GetNodeWithExistTag(parent, nodeKey, fileNode, first)
for tag in fileNode.childNodes:
tagKey = tag.localName
if tagKey == "ТаблицаСвойствОбъекта" or tagKey == "ТаблицаСвойствПланаОбмена":
ScanOptionsTableFromFilterItem(tag, parent[nodeKey], first)
else: #обрабатываем прочие реквизиты элемента как узлы со значением
GetNodeWithValue(parent[nodeKey], tagKey, tag, first)
def ScanGroupFromFilterNode(fileNode, parent, groupID, first):
"""
специфика группы отбора в том, что она содержит как подчененные
группы, так и элементы отборов и теги с описанием свойств группы
для однозначной идентификации вложенных групп и элементов
генерим идентификаторы, которые являются последовательными
номерами отдельно для элементов и для групп. Это позволит сравнивать
элементы/группы отбора последовательно по мере их появления
в файле, а в процессе мерджинга меняя этот номер выполнять
слияние соответствующих блоков
"""
nodeKey = "Группа_"+str(groupID)
ClearNoneNamedNodes(fileNode)
GetNodeWithExistTag(parent, nodeKey, fileNode, first)
for tag in fileNode.childNodes:
tagKey = tag.localName
groupID = 0
itemID = 0
if tag.localName == "Группа":
ScanGroupFromFilterNode(tag, parent[nodeKey], groupID, first)
groupID = groupID + 1 #следующий ид группы внутри данной группы
elif tag.localName == "ЭлементОтбора":
ScanFilterItemFromFilterNode(tag, parent[nodeKey], itemID, first)
itemID = itemID + 1 #следующий ид элемента внутри данной группы
else:
GetNodeWithValue(parent[nodeKey], tagKey, tag, first)
def ScanRegRuleFilterNode(fileNode, parentCompareNode, nodeKey, first=True):
ClearNoneNamedNodes(fileNode)
GetNodeWithExistTag(parentCompareNode, nodeKey, fileNode, first)
for tag in fileNode.childNodes:
tagKey = tag.localName
groupID = 0
itemID = 0
if tagKey == "Группа":
ScanGroupFromFilterNode(tag, parentCompareNode[nodeKey], groupID, first)
groupID = groupID + 1 #следующий ид группы внутри данного отбора
elif tagKey == "ЭлементОтбора":
ScanFilterItemFromFilterNode(tag, parentCompareNode[nodeKey], itemID, first)
itemID = itemID + 1 #следующий ид элемента внутри данного отбора
else:
raise Exception("Отбор по свойствам не может содержать tag:"+tagKey)
def ScanFileRegRules(fileRegRules, compareNode, first=True):
#формируем структуру сравнения по первому файлу
for group in fileRegRules: #обход <Группа>
ClearNoneNamedNodes(group)
groupKey = GetNodeKey(group, "ТипГруппы")
GetNodeWithExistTag(compareNode, groupKey, group, first, "Группа")
#перебираем правила в группе. предполагаем отсутствие дублей
for item in group.childNodes:
if item.localName == "Правило":
#обработка элемента Правило
ClearNoneNamedNodes(item)
ruleKey = GetNodeKey(item, "ОбъектНастройки")
#создали узел сравнения для правила
GetNodeWithExistTag(compareStructure.RegRules[groupKey], ruleKey, item, first, "Правило")
for tag in item.childNodes:
tagKey = tag.localName
GetCompareNodeFromStructure(compareStructure.RegRules[groupKey][ruleKey], tagKey)
if ruleFilterTreeTags.count(tagKey) > 0:
#это тег отбора по свойствам объекта или плана обмена
#обработка данного тега отдельная задача
ScanRegRuleFilterNode(tag, compareStructure.RegRules[groupKey][ruleKey], tagKey, first)
else: #тег со значением
GetNodeWithValue(compareStructure.RegRules[groupKey][ruleKey], tagKey, tag, first)
else:
#обработка обычного реквизита группы
#имена тегов реквизитов группы уникальны в ее пределах
GetNodeWithValue(compareStructure.RegRules[groupKey], item.localName, item, first)
def CompareTreeItemOfRule(node):
"""
Сравнение древовидных тегов входящих в правило
"""
nodeDiff = False
for tagKey in node.keys():
diff = False
if (
"ЭлементОтбора_" == tagKey[:len("ЭлементОтбора_")]
or "Группа_" == tagKey[:len("Группа_")]
or "ТаблицаСвойствОбъекта" == tagKey[:len("ТаблицаСвойствОбъекта")]
or "Свойство" == tagKey[:len("Свойство_")]
or "ТаблицаСвойствПланаОбмена" == tagKey[:len("ТаблицаСвойствПланаОбмена")]
):
diff = CompareTreeItemOfRule(node[tagKey])
else:
diff = GetNodeValuesDiff(node[tagKey])
node[tagKey][diffKey] = diff
nodeDiff = nodeDiff or diff
node[diffKey] = nodeDiff
return nodeDiff
def CompareRegRuleNode(node, itemDiff):
nodeDiff = False
for tagKey in node.keys():
if tagKey == attrKey: #атрибуты проверяются отдельным механизмом
diff = CompareAttributes(node)
elif ruleFilterTreeTags.count(tagKey) == 0: #сравнение реквизитов правила не являющихся отборами
val1 = node[tagKey][firstXMLFilePath]
val2 = node[tagKey][secondXMLFilePath]
diff = False
if regRuleTags.count(tagKey) > 0:
diff = ((ClearSpecChars(val1) != ClearSpecChars(val2)) or CompareAttributes(node[tagKey]))
else:
diff = ((val1 != val2) or CompareAttributes(node[tagKey]))
else: #сравнение элементов отборов
diff = CompareTreeItemOfRule(node[tagKey])
node[tagKey][diffKey] = diff
nodeDiff = (nodeDiff or diff)
node[diffKey] = nodeDiff
return nodeDiff
def CompareRegRules():
#Сравниваем правила регистрации
compareStructure.RegRules ={}
#формируем структуру сравнения по первому файлу
ScanFileRegRules(first.RegRules.childNodes, compareStructure.RegRules, True)
ScanFileRegRules(second.RegRules.childNodes, compareStructure.RegRules, False)
rulesDiff = False
#сравниваем значения всех узлов структуры и регистрируем расхождения
for compareKey in compareStructure.RegRules.keys(): # Обход <Группа></Группа>
item = compareStructure.RegRules[compareKey]
itemDiff = False #признак наличия изменений в группе или ее элементах
diff = False
for tagKey in item.keys(): # обход тегов элементов
if regRulesGroupTags.count(tagKey) > 0:
#в описании состава плана обмена имена объектов не могут содержать спец символов
#поэтому при сравнении вычищаем их
val1 = ClearSpecChars(item[tagKey][firstXMLFilePath])
val2 = ClearSpecChars(item[tagKey][secondXMLFilePath])
diff = (val1 != val2) or CompareAttributes(item[tagKey])
item[tagKey][diffKey] = diff
else:
#запуск сравнения правила
diff = CompareRegRuleNode(item[tagKey], itemDiff)
itemDiff = (itemDiff or diff)
item[diffKey] = itemDiff
rulesDiff = (rulesDiff or itemDiff)
compareStructure.RegRules[diffKey] = rulesDiff
def WriteStr(str, level=0):
for i in range(level-1):
print("\t", end='')
print(str, end='')
def GetNodeDataKey(node):
#различие режимов manual и hard в обработке реквизитов
#hard полностью заменяет значение данных реквизитов на новые, а manual сохраняет в результате оба варианта настроек
#для последующего редактирования
dataKey = None
if type(node) is dict and node.get(firstXMLFilePath) != None and node.get(secondXMLFilePath) != None:
if manualPriority == True:
#полужесткое объединение. При наличии узлов в двух файлах отдаем предпочтение данным из второго файла.
#Если во втором файле узел отсутствует значение узла остается неизменным.
if node[secondXMLFilePath] != undefined:
dataKey = secondXMLFilePath
else:
dataKey = firstXMLFilePath
elif hardPriority == True:
#жесткое объединение. При наличии узлов в двух файлах отдаем предпочтение данным из второго файла.
#Если во втором файле узел отсутствует значение узла остается неизменным.
if node[secondXMLFilePath] != undefined:
dataKey = secondXMLFilePath
else:
dataKey = firstXMLFilePath
else:
#мягкое объединение. Если узел заполнен данными из первого файла, то новое значение игнорируется
if node[firstXMLFilePath] != undefined:
dataKey = firstXMLFilePath
else:
dataKey = secondXMLFilePath
return dataKey
def OutputAttributeItemValue(item, itemKey, masterDataKey, level):
curLevel = level+1
if hardPriority == True or softPriority == True or item[diffKey] != True:
#для hard и soft используется только мастер ключ данных
#т.к. для этих режимов один из файлов является приоритетным
#и позволяет использовать данные не приоритетного файла
#только при отсутствии основных данных
#ecли изменений в узле небыло, то выводим данные по мастер ключу
WriteStr(' {0}="{1}"'.format(itemKey,item[masterDataKey]))
else:
WriteStr(' '+itemKey+'=\n')
WriteStr("<!-- "+firstXMLFilePath+" -->\n", curLevel)
WriteStr('"'+item[firstXMLFilePath]+'"\n', curLevel)
WriteStr("<!-- "+secondXMLFilePath+" -->\n", curLevel)
WriteStr('"'+item[secondXMLFilePath]+'"\n', curLevel)
WriteStr("<!-- -->\n", curLevel)
def GetValidNodeCode(nodeCode):
if nodeCode == undefined:
return undefined
result = nodeCode
if mergedKeys.count(nodeCode) != 0:
#generate new code
lastCode = mergedKeys[len(mergedKeys)-1]
result = "{:0>9}".format(int(lastCode)+1)
mergedKeys.append(result)
mergedKeys.sort()
return result
def GetItemValue(item, itemKey, valueKey):
itemValue = item[valueKey]
if itemKey == "Код":
itemValue = GetValidNodeCode(itemValue)
return itemValue
def OutputSimpleItemValue(item, itemKey, masterDataKey, level):
curLevel = level+1
if hardPriority == True or softPriority == True or item[diffKey] != True:
#для hard и soft используется только мастер ключ данных
#т.к. для этих режимов один из файлов является приоритетным
#и позволяет использовать данные не приоритетного файла
#только при отсутствии основных данных
#ecли изменений в узле небыло, то выводим данные по мастер ключу
if item[masterDataKey] != undefined:
WriteStr('<{0}>{1}</{2}>\n'.format(itemKey,GetItemValue(item,itemKey,masterDataKey),itemKey), curLevel)
else:
WriteStr('<'+itemKey+'>\n', curLevel)
WriteStr("<!-- "+firstXMLFilePath+" -->\n", curLevel+1)
WriteStr(GetItemValue(item,itemKey,firstXMLFilePath)+'\n', curLevel+1)
WriteStr("<!-- "+secondXMLFilePath+" -->\n", curLevel+1)
WriteStr(GetItemValue(item,itemKey,secondXMLFilePath)+'\n', curLevel+1)
WriteStr("<!-- -->\n", curLevel+1)
WriteStr('</'+itemKey+'>\n', curLevel)
#процедуры вывода результата сравнения/объединения правил регистрации
def OutputPropertiesTable(node, nodeKey, masterDataKey, level):
#вывод результата сравнения для узла ТаблицаСвойствОбъекта или ТаблицаСвойствПланаОбмена
#при условии атоматического объединения или отсутствия изменений
curLevel = level + 1
if node[itemExist][masterDataKey] != undefined: #в приоритетном файле узел существует
WriteStr("<"+nodeKey+">\n", curLevel)
#у этих элементов только один вложенный реквизит Свойство
if node["Свойство"][itemExist][masterDataKey] != undefined: #свойство существует
WriteStr("<Свойство>\n", curLevel+1)
for itemKey in node["Свойство"]: #обходим его содержимое
if outputExcludeKeys.count(itemKey) == 0:
item = node["Свойство"][itemKey]
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel+1)
WriteStr("</Свойство>\n", curLevel+1)
WriteStr("</"+nodeKey+">\n", curLevel)
def OutputPropertiesTableManualMode(node, nodeKey, level):
#вывод результата сравнения для узла ТаблицаСвойствОбъекта или ТаблицаСвойствПланаОбмена
#при условии атоматического объединения или отсутствия изменений
curLevel = level + 1
if node[itemExist][masterDataKey] != undefined: #в приоритетном файле узел существует
WriteStr("<"+nodeKey+">\n", curLevel)
#у этих элементов только один вложенный реквизит Свойство
if node["Свойство"][itemExist][masterDataKey] != undefined: #свойство существует
WriteStr("<Свойство>\n", curLevel+1)
for itemKey in node["Свойство"]: #обходим его содержимое
if outputExcludeKeys.count(itemKey) == 0:
item = node["Свойство"][itemKey]
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel+1)
WriteStr("</Свойство>\n", curLevel+1)
WriteStr("</"+nodeKey+">\n", curLevel)
def OutputFilterGroup(node, nodeKey, masterDataKey, level):
#вывод результата сравнения для узла Группа при условии атоматического объединения или отсутствия изменений
curLevel = level+1
if node[itemExist][masterDataKey] != undefined: #в приоритетном файле узел существует
WriteStr("<Группа>\n", curLevel)
for itemKey in node:
if outputExcludeKeys.count(itemKey) == 0:
item = node[itemKey]
if "ЭлементОтбора_" != itemKey[:len("ЭлементОтбора_")]: #это простой элемент структуры Группа
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel)
else: #вывод ЭлементОтбора
OutputFilterItem(item, itemKey, masterDataKey, curLevel)
WriteStr("</Группа>\n", curLevel)
def OutputFilterGroupManualMode(node, nodeKey, masterDataKey, level):
#вывод результата сравнения для узла Группа
#при условии ручного объединения если есть изменения
curLevel = level+1
if node[itemExist][firstXMLFilePath] != undefined or node[itemExist][secondXMLFilePath] != undefined:
#в узел существует
WriteStr("<Группа>\n", curLevel)
for itemKey in node:
if outputExcludeKeys.count(itemKey) == 0:
item = node[itemKey]
if "ЭлементОтбора_" != itemKey[:len("ЭлементОтбора_")]: #это простой элемент структуры Группа
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel)
else: #вывод ЭлементОтбора
OutputFilterItemManualMode(item, itemKey, masterDataKey, curLevel)
WriteStr("</Группа>\n", curLevel)
def OutputFilterItem(node, nodeKey, masterDataKey, level):
#вывод результата сравнения для узла ЭлементОтбора при условии атоматического объединения или отсутствия изменений
curLevel = level+1
if node[itemExist][masterDataKey] != undefined: #в приоритетном файле узел существует
WriteStr("<ЭлементОтбора>\n", curLevel)
for itemKey in node:
if outputExcludeKeys.count(itemKey) == 0:
item = node[itemKey]
if ruleFilterItemsTreeTags.count(itemKey) == 0: #это простой элемент структуры ЭлементОтбора
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel)
else: #вывод элементов ТаблицаСвойствОбъекта или ТаблицаСвойствПланаОбмена
OutputPropertiesTable(item, itemKey, masterDataKey, curLevel)
WriteStr("</ЭлементОтбора>\n", curLevel)
def OutputFilterItemManualMode(node, nodeKey, masterDataKey, level):
#вывод результата сравнения для узла ЭлементОтбора
#при условии ручного объединения если есть изменения
curLevel = level+1
if node[itemExist][masterDataKey] != undefined: #в приоритетном файле узел существует
WriteStr("<ЭлементОтбора>\n", curLevel)
for itemKey in node:
if outputExcludeKeys.count(itemKey) == 0:
item = node[itemKey]
if ruleFilterItemsTreeTags.count(itemKey) == 0: #это простой элемент структуры ЭлементОтбора
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel)
else: #вывод элементов ТаблицаСвойствОбъекта или ТаблицаСвойствПланаОбмена
OutputPropertiesTable(item, itemKey, masterDataKey, curLevel)
WriteStr("</ЭлементОтбора>\n", curLevel)
def OutputRegRuleFilterNodeItem(node, nodeKey, masterDataKey, level):
#вывод результата сравнения элемента структуры отбора
#при наличии приоритетного файла или отсутствии изменений
if outputExcludeKeys.count(nodeKey) == 0:
#определяем тип узла отбора
if node[itemExist][masterDataKey] != undefined:
if "ЭлементОтбора_" == nodeKey[:len("ЭлементОтбора_")]:
OutputFilterItem(node, nodeKey, masterDataKey, level)
elif "Группа_" == nodeKey[:len("Группа_")]:
OutputFilterGroup(node, nodeKey, masterDataKey, level)
else:
raise Exception("Отбор по свойствам не может содержать tag:"+nodeKey)
def OutputRegRuleFilterNodeItemManualMode(node, nodeKey, masterDataKey, level):
#вывод результата сравнения элемента структуры отбора
#при условии ручного объединения если есть изменения
if outputExcludeKeys.count(nodeKey) == 0:
#определяем тип узла отбора
if node[itemExist][firstXMLFilePath] != undefined or node[itemExist][firstXMLFilePath] != undefined:
if "ЭлементОтбора_" == nodeKey[:len("ЭлементОтбора_")]:
OutputFilterItemManualMode(node, nodeKey, masterDataKey, level)
elif "Группа_" == nodeKey[:len("Группа_")]:
OutputFilterGroupManualMode(node, nodeKey, masterDataKey, level)
else:
raise Exception("Отбор по свойствам не может содержать tag:"+nodeKey)
def OutputRegRuleFilterNode(node, nodeKey, masterDataKey, level):
curLevel = level+1
if hardPriority == True or softPriority == True or node[diffKey] != True: #есть приоритетный узел или нет измененй
if node[itemExist][masterDataKey] != undefined:
WriteStr("<"+nodeKey+">\n", curLevel)
for itemKey in node:
OutputRegRuleFilterNodeItem(node[itemKey], itemKey, masterDataKey, curLevel)
WriteStr("</"+nodeKey+">\n", curLevel)
else:
WriteStr("<"+nodeKey+"/>\n", curLevel)
else:
#это ручной режим при наличии изменений
if node[itemExist][firstXMLFilePath] != undefined or node[itemExist][firstXMLFilePath] != undefined:
WriteStr("<"+nodeKey+">\n", curLevel)
for itemKey in node:
OutputRegRuleFilterNodeItemManualMode(node[itemKey], itemKey, masterDataKey, curLevel)
WriteStr("</"+nodeKey+">\n", curLevel)
else:
WriteStr("<"+nodeKey+"/>\n", curLevel)
def OutputRegRuleDiff(node, nodeKey, level):
curLevel = level+1
masterDataKey = GetNodeDataKey(node[itemExist])
if masterDataKey == None: #правило не определено
return 0
WriteStr("<Правило", curLevel)
if node.get(attrKey) != None:
attrs = node[attrKey]
for attrItemKey in attrs:
if outputExcludeKeys.count(attrItemKey) == 0:
attrItem = attrs[attrItemKey]
OutputAttributeItemValue(attrItem, attrItemKey, masterDataKey, curLevel)
WriteStr(">\n", 0) #закрыли тег правила
for itemKey in node: #выводим теги правила
if outputExcludeKeys.count(itemKey) != 0: #исключаем теги не входящие в правило теги с древовидной структурой
continue
item = node[itemKey]
if ruleFilterTreeTags.count(itemKey) == 0:#исключаем теги отборов по свойствам с древовидной структурой
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel)
else: #вывод древовоидных тегов
OutputRegRuleFilterNode(item, itemKey, masterDataKey, curLevel)
WriteStr("</Правило>\n", curLevel) #закрыли правило
def OutputRegRulesGroupDiff(node, nodeKey, level):
#Выгружаем группу правил регистрации
curLevel = level + 1
masterDataKey = GetNodeDataKey(node[itemExist])
if masterDataKey == None:
return None
if type(node) is dict:
WriteStr("<Группа", curLevel) #Открываем группу в любом случае,
#т.к. в случае отсутствия ее в первом файле
#она должна быть перенесена из второго
if node.get(attrKey) != None:
for itemKey in node[attrKey]:
if outputExcludeKeys.count(itemKey) != 0:
continue
item = node[attrKey][itemKey]
OutputAttributeItemValue(item, itemKey, masterDataKey, curLevel)
WriteStr(">\n") #закрыли тег группы
#переходим к обходу реквизитов
for itemKey in node: #узел ОбъектНастройки есть только у правила регистрации
item = node[itemKey]
if outputExcludeKeys.count(itemKey) == 0 and type(item) is dict and item.get("ОбъектНастройки") == None:
OutputSimpleItemValue(item, itemKey, masterDataKey, curLevel)
#выполняем обход правил регистрации группы
#это позволяет сохранить порядок тегов сверху тери группы, далее правила
for itemKey in node: #узел ОбъектНастройки есть только у правила регистрации
item = node[itemKey]
if outputExcludeKeys.count(itemKey) == 0 and type(item) is dict and item.get("ОбъектНастройки") != None:
OutputRegRuleDiff(item, itemKey, curLevel)
WriteStr("</Группа>\n", curLevel)#закрыли группу
def OutputRegRulesNodesDiff(parent, level):
curLevel = level+1
WriteStr("<ПравилаРегистрацииОбъектов>\n", curLevel)
for nodeKey in parent:
if outputExcludeKeys.count(nodeKey) == 0:
OutputRegRulesGroupDiff(parent[nodeKey], nodeKey, curLevel)
WriteStr("</ПравилаРегистрацииОбъектов>\n", curLevel)
#окончание секции процедур вывода результата сравнения/объединения правил регистрации
#процедуры вывода результата сравнения заголовков
def OutputHeaderItemAttributes(node, dataKey, level):
if node.get(attrKey) != None:
for attrItemKey in node[attrKey]:
attrs = node[attrKey]
OutputAttributeItemValue(attrs[attrItemKey], attrItemKey, dataKey, level)
def OutputHeaderItemDiff(node, nodeKey, level):
curLevel = level
if (type(node) is dict):
if node.get(firstXMLFilePath) != None and node.get(secondXMLFilePath) != None:
dataKey = GetNodeDataKey(node)
if dataKey != None: #если ключ данных не определен, то узел не выводится
WriteStr("<"+nodeKey, curLevel)
OutputHeaderItemAttributes(node, dataKey, curLevel)
WriteStr(">") #закрываем тег
WriteStr(node[dataKey]) #выводим значение тега
WriteStr("</"+nodeKey+">\n")
def OutputHeaderNodesDiff(parent, level):
#вывод в результирующий файл результата сравнения узлов Headers
#т.к. все реквизиты являются обязательными, то контролировать режим объединения
#можно по определению мастер ключа данных, который определяется
#при выводе значения узла описания заголовка OutputHeaderItemDiff
curLevel = level+1
if type(parent) is dict:
for node in parent:
if excludeHeaderNodes.count(node) != 0 or outputExcludeKeys.count(node) != 0:
continue
OutputHeaderItemDiff(parent[node], node, curLevel)
if type(parent[node]) is dict:
OutputHeaderNodesDiff(parent[node], curLevel)
#окончание секции процедур вывода результата сравнения заголовков
#процедуры вывода результатов сравнения составов планов обмена
def OutputEchangeCompositionNodeDiff(node, nodeKey, level):
curLevel = level+1
if type(node) is dict:
dataKey = GetNodeDataKey(node[itemExist])
#определяем какие данные использовать для записи элемента
#в зависимости от режима объединения
# и надо ли записывать его вообще
if dataKey == None:
return 0
WriteStr("<Элемент>\n", curLevel)
for itemKey in node:
if outputExcludeKeys.count(itemKey) == 0:
if dataKey != None:
OutputSimpleItemValue(node[itemKey], itemKey, dataKey, curLevel)
WriteStr("</Элемент>\n", curLevel)
def OutputExchangeCompositionNodesDiff(parent, level):
curLevel = level+1
WriteStr("<СоставПланаОбмена>\n", curLevel)
for nodeKey in parent:
if outputExcludeKeys.count(nodeKey) == 0:
OutputEchangeCompositionNodeDiff(parent[nodeKey], nodeKey, curLevel)
WriteStr("</СоставПланаОбмена>\n", curLevel)
#окончание секции процедур вывода результатов сравнения составов планов обмена
parser = argparse.ArgumentParser(description='Diff two xml 1C registration rules files with structure.')
parser.add_argument('firstXMLFilePath', type=str, help='first file for compare. Merged data save into it.')
parser.add_argument('secondXMLFilePath', type=str, help='second file for compare.')
parser.add_argument('--outputXMLFilePath', type=str, default='', help='diff result output file')
parser.add_argument('--soft', action='store_true', help='default key. Merge files with first file piority. See script comments')
parser.add_argument('--manual', action='store_true', help='this key more priority than soft. Merge files with replacing exist node from second file. See script comments')
parser.add_argument('--hard', action='store_true', help='this key more priority than manual. Merge files with second file piority. See script comments')
args = parser.parse_args()
print(args.firstXMLFilePath)
print(args.secondXMLFilePath)
print(args.outputXMLFilePath)
origin_stdout = sys.stdout
fout = None
try:
if args.outputXMLFilePath != '':
fout = open(args.outputXMLFilePath, 'w+', encoding='utf-8')
sys.stdout = fout
softPriority = ((args.soft == True) and (args.manual != True) and (args.hard != True)) or ((args.manual != True) and (args.hard != True))
manualPriority = (args.manual == True) and (args.hard != True)
hardPriority = (args.hard == True)
firstXMLFilePath = args.firstXMLFilePath
secondXMLFilePath = args.secondXMLFilePath
first = ReadRulesIntoStructure(firstXMLFilePath)
second = ReadRulesIntoStructure(secondXMLFilePath)
compareStructure = RulesStructure()
CompareHeaders()
CompareExchangeComposition()
CompareRegRules()
#Выаод результата объединения правил регистрации
WriteStr("<ПравилаРегистрации>\n")
OutputHeaderNodesDiff(compareStructure.Header, 1)
OutputExchangeCompositionNodesDiff(compareStructure.ExhangeComposition, 1)
OutputRegRulesNodesDiff(compareStructure.RegRules, 1)
WriteStr("</ПравилаРегистрации>\n")
if fout != None:
fout.close()
finally:
sys.stdout = origin_stdout
print("The end.")
Реализованы три режима работы:
- soft, режим по-умолчанию. В этом режиме приоритетными правилами являются правила из первого файла. При объединении в него добавляются объекты, которые присутствуют только во втором варианте правил, а существующие остаются не измененными. В примере у справочника номенклатуры во втором файле отсутствуют отборы по свойствам.
Пример объединения в этом режиме:
<ПравилаРегистрацииОбъектов>
<Группа Отключить="false">
<Код>000000002</Код>
<Наименование>Справочники</Наименование>
<ТипГруппы>Справочник</ТипГруппы>
<Правило Отключить="false" Валидное="true">
<Код>000000001</Код>
<Наименование>Номенклатура</Наименование>
<ОбъектНастройки>СправочникСсылка.Номенклатура</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.Номенклатура</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена>
<ЭлементОтбора>
<ЭтоСтрокаКонстанты>false</ЭтоСтрокаКонстанты>
<ТипСвойстваОбъекта>СправочникСсылка.ВидыНоменклатуры</ТипСвойстваОбъекта>
<СвойствоПланаОбмена>[ВыгружаемыеВидыНоменклатуры].ВидНоменклатуры</СвойствоПланаОбмена>
<ВидСравнения>Равно</ВидСравнения>
<СвойствоОбъекта>ВидНоменклатуры</СвойствоОбъекта>
<ТаблицаСвойствОбъекта>
<Свойство>
<Наименование>ВидНоменклатуры</Наименование>
<Тип>СправочникСсылка.ВидыНоменклатуры</Тип>
<Вид>Реквизит</Вид>
</Свойство>
</ТаблицаСвойствОбъекта>
<ТаблицаСвойствПланаОбмена>
<Свойство>
<Наименование>[ВыгружаемыеВидыНоменклатуры]</Наименование>
<Вид>ТабличнаяЧасть</Вид>
</Свойство>
<Свойство>
<Наименование>ВидНоменклатуры</Наименование>
<Тип>СправочникСсылка.ВидыНоменклатуры</Тип>
<Вид>Реквизит</Вид>
</Свойство>
</ТаблицаСвойствПланаОбмена>
</ЭлементОтбора>
</ОтборПоСвойствамПланаОбмена>
<ОтборПоСвойствамОбъекта/>
<ПередОбработкой>//Обработчик перед обработкой 1</ПередОбработкой>
<ПриОбработке>//при обработке 1</ПриОбработке>
<ПриОбработкеДополнительный>//при обработке доп. 1</ПриОбработкеДополнительный>
<ПослеОбработки>//после обработки 1</ПослеОбработки>
</Правило>
<Правило Отключить="false" Валидное="true">
<Код>000000003</Код>
<Наименование>Номенклатура поставщиков</Наименование>
<ОбъектНастройки>СправочникСсылка.НоменклатураПоставщиков</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.НоменклатураПоставщиков</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена/>
<ОтборПоСвойствамОбъекта>
<ЭлементОтбора>
<ТипСвойстваОбъекта>Строка</ТипСвойстваОбъекта>
<ВидСравнения>Равно</ВидСравнения>
<СвойствоОбъекта>Идентификатор</СвойствоОбъекта>
<Вид>АлгоритмЗначения</Вид>
<ЗначениеКонстанты>Значение = "первый файл";</ЗначениеКонстанты>
<ТаблицаСвойствОбъекта>
<Свойство>
<Наименование>Идентификатор</Наименование>
<Тип>Строка</Тип>
<Вид>Реквизит</Вид>
</Свойство>
</ТаблицаСвойствОбъекта>
</ЭлементОтбора>
</ОтборПоСвойствамОбъекта>
</Правило>
</Группа>
<ПравилаРегистрацииОбъектов>
<Группа Отключить="true">
<Код>000000002</Код>
<Наименование>Справочники</Наименование>
<ТипГруппы>Справочник</ТипГруппы>
<Правило Отключить="false" Валидное="true">
<Код>000000001</Код>
<Наименование>Номенклатура</Наименование>
<ОбъектНастройки>СправочникСсылка.Номенклатура</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.Номенклатура</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена/>
<ОтборПоСвойствамОбъекта/>
</Правило>
</Группа>
<ПравилаРегистрацииОбъектов>
<Группа Отключить="false">
<Код>000000002</Код>
<Наименование>Справочники</Наименование>
<ТипГруппы>Справочник</ТипГруппы>
<Правило Отключить="false" Валидное="true">
<Код>000000001</Код>
<Наименование>Номенклатура</Наименование>
<ОбъектНастройки>СправочникСсылка.Номенклатура</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.Номенклатура</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена>
<ЭлементОтбора>
<ЭтоСтрокаКонстанты>false</ЭтоСтрокаКонстанты>
<ТипСвойстваОбъекта>СправочникСсылка.ВидыНоменклатуры</ТипСвойстваОбъекта>
<СвойствоПланаОбмена>[ВыгружаемыеВидыНоменклатуры].ВидНоменклатуры</СвойствоПланаОбмена>
<ВидСравнения>Равно</ВидСравнения>
<СвойствоОбъекта>ВидНоменклатуры</СвойствоОбъекта>
<ТаблицаСвойствОбъекта>
<Свойство>
<Наименование>ВидНоменклатуры</Наименование>
<Тип>СправочникСсылка.ВидыНоменклатуры</Тип>
<Вид>Реквизит</Вид>
</Свойство>
</ТаблицаСвойствОбъекта>
<ТаблицаСвойствПланаОбмена>
<Свойство>
<Наименование>[ВыгружаемыеВидыНоменклатуры]</Наименование>
<Вид>ТабличнаяЧасть</Вид>
<Тип>СправочникСсылка.ВидыНоменклатуры</Тип>
</Свойство>
</ТаблицаСвойствПланаОбмена>
</ЭлементОтбора>
</ОтборПоСвойствамПланаОбмена>
<ОтборПоСвойствамОбъекта>
</ОтборПоСвойствамОбъекта>
<ПередОбработкой>//Обработчик перед обработкой 1</ПередОбработкой>
<ПриОбработке>//при обработке 1</ПриОбработке>
<ПриОбработкеДополнительный>//при обработке доп. 1</ПриОбработкеДополнительный>
<ПослеОбработки>//после обработки 1</ПослеОбработки>
</Правило>
<Правило Отключить="false" Валидное="true">
<Код>000000003</Код>
<Наименование>Номенклатура поставщиков</Наименование>
<ОбъектНастройки>СправочникСсылка.НоменклатураПоставщиков</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.НоменклатураПоставщиков</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена>
</ОтборПоСвойствамПланаОбмена>
<ОтборПоСвойствамОбъекта>
<ЭлементОтбора>
<ТипСвойстваОбъекта>Строка</ТипСвойстваОбъекта>
<ВидСравнения>Равно</ВидСравнения>
<СвойствоОбъекта>Идентификатор</СвойствоОбъекта>
<Вид>АлгоритмЗначения</Вид>
<ЗначениеКонстанты>Значение = "первый файл";</ЗначениеКонстанты>
<ТаблицаСвойствОбъекта>
<Свойство>
<Наименование>Идентификатор</Наименование>
<Тип>Строка</Тип>
<Вид>Реквизит</Вид>
</Свойство>
</ТаблицаСвойствОбъекта>
</ЭлементОтбора>
</ОтборПоСвойствамОбъекта>
</Правило>
</Группа>
- hard, в этом режиме приоритетными являются правила из второго файла. Все совпадающие узлы будут замещены.
<ПравилаРегистрацииОбъектов>
<Группа Отключить="true">
<Код>000000002</Код>
<Наименование>Справочники</Наименование>
<ТипГруппы>Справочник</ТипГруппы>
<Правило Отключить="false" Валидное="true">
<Код>000000001</Код>
<Наименование>Номенклатура</Наименование>
<ОбъектНастройки>СправочникСсылка.Номенклатура</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.Номенклатура</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена>
</ОтборПоСвойствамПланаОбмена>
<ОтборПоСвойствамОбъекта>
</ОтборПоСвойствамОбъекта>
</Правило>
<Правило Отключить="false" Валидное="true">
<Код>000000003</Код>
<Наименование>Номенклатура поставщиков</Наименование>
<ОбъектНастройки>СправочникСсылка.НоменклатураПоставщиков</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.НоменклатураПоставщиков</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена>
</ОтборПоСвойствамПланаОбмена>
<ОтборПоСвойствамОбъекта>
<ЭлементОтбора>
<ТипСвойстваОбъекта>Строка</ТипСвойстваОбъекта>
<ВидСравнения>Равно</ВидСравнения>
<СвойствоОбъекта>Идентификатор</СвойствоОбъекта>
<Вид>АлгоритмЗначения</Вид>
<ЗначениеКонстанты>Значение = "первый файл";</ЗначениеКонстанты>
<ТаблицаСвойствОбъекта>
<Свойство>
<Наименование>Идентификатор</Наименование>
<Тип>Строка</Тип>
<Вид>Реквизит</Вид>
</Свойство>
</ТаблицаСвойствОбъекта>
</ЭлементОтбора>
</ОтборПоСвойствамОбъекта>
</Правило>
</Группа>
- manual, в этом режиме формируется заготовка для ручного объединения правил.
<ПравилаРегистрацииОбъектов>
<Группа Отключить=
<!-- .\debug\firstRules.xml -->
"false"
<!-- .\debug\secondRules.xml -->
"true"
<!-- -->
>
<Код>000000002</Код>
<Наименование>Справочники</Наименование>
<ТипГруппы>Справочник</ТипГруппы>
<Правило Отключить="false" Валидное="true">
<Код>000000001</Код>
<Наименование>Номенклатура</Наименование>
<ОбъектНастройки>СправочникСсылка.Номенклатура</ОбъектНастройки>
<ОбъектМетаданныхИмя>Справочник.Номенклатура</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>Справочник</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена>
</ОтборПоСвойствамПланаОбмена>
<ОтборПоСвойствамОбъекта>
</ОтборПоСвойствамОбъекта>
<ПередОбработкой>
<!-- .\debug\firstRules.xml -->
//Обработчик перед обработкой 1
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ПередОбработкой>
<ПриОбработке>
<!-- .\debug\firstRules.xml -->
//при обработке 1
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ПриОбработке>
<ПриОбработкеДополнительный>
<!-- .\debug\firstRules.xml -->
//при обработке доп. 1
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ПриОбработкеДополнительный>
<ПослеОбработки>
<!-- .\debug\firstRules.xml -->
//после обработки 1
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ПослеОбработки>
</Правило>
<Правило Отключить=
<!-- .\debug\firstRules.xml -->
"false"
<!-- .\debug\secondRules.xml -->
"Undefined"
<!-- -->
Валидное=
<!-- .\debug\firstRules.xml -->
"true"
<!-- .\debug\secondRules.xml -->
"Undefined"
<!-- -->
>
<Код>
<!-- .\debug\firstRules.xml -->
000000003
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</Код>
<Наименование>
<!-- .\debug\firstRules.xml -->
Номенклатура поставщиков
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</Наименование>
<ОбъектНастройки>
<!-- .\debug\firstRules.xml -->
СправочникСсылка.НоменклатураПоставщиков
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ОбъектНастройки>
<ОбъектМетаданныхИмя>
<!-- .\debug\firstRules.xml -->
Справочник.НоменклатураПоставщиков
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ОбъектМетаданныхИмя>
<ОбъектМетаданныхТип>
<!-- .\debug\firstRules.xml -->
Справочник
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ОбъектМетаданныхТип>
<ОтборПоСвойствамПланаОбмена>
</ОтборПоСвойствамПланаОбмена>
<ОтборПоСвойствамОбъекта>
<ЭлементОтбора>
<ТипСвойстваОбъекта>
<!-- .\debug\firstRules.xml -->
Строка
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ТипСвойстваОбъекта>
<ВидСравнения>
<!-- .\debug\firstRules.xml -->
Равно
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ВидСравнения>
<СвойствоОбъекта>
<!-- .\debug\firstRules.xml -->
Идентификатор
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</СвойствоОбъекта>
<Вид>
<!-- .\debug\firstRules.xml -->
АлгоритмЗначения
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</Вид>
<ЗначениеКонстанты>
<!-- .\debug\firstRules.xml -->
Значение = "первый файл";
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</ЗначениеКонстанты>
<ТаблицаСвойствОбъекта>
<Свойство>
<Наименование>
<!-- .\debug\firstRules.xml -->
Идентификатор
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</Наименование>
<Тип>
<!-- .\debug\firstRules.xml -->
Строка
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</Тип>
<Вид>
<!-- .\debug\firstRules.xml -->
Реквизит
<!-- .\debug\secondRules.xml -->
Undefined
<!-- -->
</Вид>
</Свойство>
</ТаблицаСвойствОбъекта>
</ЭлементОтбора>
</ОтборПоСвойствамОбъекта>
</Правило>
</Группа>
Приветствуется любая критика, кроме злословия. При обнаружении ошибок, если не затруднит, сообщите.