Страница 2 из 4
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 13:34
finsoftrz
Кстати, насчет боязни временных файлов. Вспомнил про xlsx, который не так давно мучили. Там кучка файлов в куче подкаталогов, завернутые в zip архив. Скорее всего, при работе все это распаковывается во временные каталоги и файлы. Это в "современном" формате, а старый xls это один файл. Несправедливо.

Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 13:42
Игорь Столяров
finsoftrz писал(а): 27 Февраль 2023, 13:15
Если есть вложенные теги, то в name они указываются через "/"
Да, всё верно. Но есть небольшой нюанс. Если предположим, есть группа тегов с данными ФЛ
(Имя, Фамилия, Отчество) и она встречается в структуре с 8-9 уровнями вложенности раз 20 -
то будет очень грустно прописывать к каждому тегу "Имя" полный путь. Хотя конечно и возможно.
Но если мы хотим получить общее решение, которое будет работать всегда и везде - то нужно
брать структуру данных ФНС и парсить по ней. Как бы грустно это не было ...
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 14:27
finsoftrz
Про 20 раз 8-9 уровней - это, наверно, образно?

Смысл в том, что "парсер" один, соответствие прописывается в структуре данных, а не в вызовах методов.
Длинные имена тэгов встречаются, например, в ветисе. Длиннее пока не попадалось.
Код: Выделить всё
lor:queueZag queue,pre()
lor:date string(20), name('vd:issueDate')
lor:dateLong string(40), name('vd:lastUpdateDate')
lor:uuid string(40), name('bs:uuid')
lor:form string(10), name('vd:vetDForm')
lor:type string(20), name('vd:vetDType')
lor:stat string(20), name('vd:vetDStatus')
lor:perishable string(20), name('vd:certifiedConsignment/vd:batch/vd:perishable')
lor:sendHS string(40), name('vd:certifiedConsignment/vd:consignor/dt:businessEntity/bs:guid')
lor:sendEnt string(40), name('vd:certifiedConsignment/vd:consignor/dt:enterprise/bs:guid')
lor:reciveHS string(40), name('vd:certifiedConsignment/vd:consignee/dt:businessEntity/bs:guid')
lor:reciveEnt string(40), name('vd:certifiedConsignment/vd:consignee/dt:enterprise/bs:guid')
lor:prodType string(10), name('vd:certifiedConsignment/vd:batch/vd:productType')
lor:prodGUID string(40), name('vd:certifiedConsignment/vd:batch/vd:product/bs:guid')
lor:prodSubGUID string(40), name('vd:certifiedConsignment/vd:batch/vd:subProduct/bs:guid')
lor:prodItGUID string(40), name('vd:certifiedConsignment/vd:batch/vd:productItem/bs:guid')
lor:prodName string(255),name('vd:certifiedConsignment/vd:batch/vd:productItem/dt:name')
lor:value string(20), name('vd:certifiedConsignment/vd:batch/vd:volume')
lor:firstYear string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:year')
lor:firstMonth string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:month')
lor:firstDay string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:day')
lor:firsthour string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:hour')
lor:endYear string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:year')
lor:endMonth string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:month')
lor:endDay string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:day')
lor:endhour string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:hour')
lor:unit string(40), name('vd:certifiedConsignment/vd:batch/vd:unit/bs:guid')
lor:country string(40), name('vd:certifiedConsignment/vd:batch/vd:origin/vd:country/bs:guid')
lor:packingLevel string(10), name('vd:certifiedConsignment/vd:batch/vd:packageList/dt:package/dt:level')
lor:packingType string(40), name('vd:certifiedConsignment/vd:batch/vd:packageList/dt:package/dt:packingType/bs:guid')
lor:packingID string(20), name('vd:certifiedConsignment/vd:batch/vd:packageList/dt:package/dt:packingType/dt:globalID')
lor:packingKol string(10), name('vd:certifiedConsignment/vd:batch/vd:packageList/dt:package/dt:quantity')
lor:transpType string(10), name('vd:certifiedConsignment/vd:transportInfo/vd:transportType')
lor:transpCont string(40), name('vd:certifiedConsignment/vd:transportInfo/vd:transportNumber/vd:containerNumber')
lor:transpTrail string(40), name('vd:certifiedConsignment/vd:transportInfo/vd:transportNumber/vd:trailerNumber')
lor:transpNumber string(60), name('vd:certifiedConsignment/vd:transportInfo/vd:transportNumber/vd:vehicleNumber')
lor:transpStorage string(20), name('vd:certifiedConsignment/vd:transportStorageType')
lor:transpType2 string(10), name('vd:nextTransport/vd:transportType')
lor:transpCont2 string(40), name('vd:nextTransport/vd:transportNumber/vd:containerNumber')
lor:transpTrail2 string(40), name('vd:nextTransport/vd:transportNumber/vd:trailerNumber')
lor:transpNumber2 string(40), name('vd:nextTransport/vd:transportNumber/vd:vehicleNumber')
lor:brokerGUID string(40), name('vd:certifiedConsignment/vd:broker/bs:guid')
lor:authPurpose string(40), name('vd:authentication/vd:purpose/bs:guid')
lor:authInsp string(20), name('vd:authentication/vd:cargoInspected')
lor:authExp string(20), name('vd:authentication/vd:cargoExpertized')
lor:authLoc string(128), name('vd:authentication/vd:locationProsperity')
.
То есть подход простой. То, что можно формализовать и получать одним методом, формализуем и используем для всех разновидностей xml, используя соответствие названий тэгов и name у полей в кларионовских структурах. Для сложных случаев, когда удумаешься формализовывать, тупо встраивается код на vbscript, который сам по себе достаточно простой, понятный и гуглодоступный. В кьюшках/группах в этом случае name можно задать как угодно (только согласовано с кодом vbscript).
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 14:57
Игорь Столяров
finsoftrz писал(а): 27 Февраль 2023, 14:27
Про 20 раз 8-9 уровней - это, наверно, образно?
К сожалению, нет. Это про структуру документа ЭДО. Только полную.
Например, фамилия поставщика ИП: Loc:MyFile.Document.SvSchFact.SvPokup.IdSv.SvIP.FIO.Fam
finsoftrz писал(а): 27 Февраль 2023, 14:27
lor:firstYear string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:year')
lor:firstMonth string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:month')
lor:firstDay string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:day')
lor:firsthour string(10), name('vd:certifiedConsignment/vd:batch/vd:dateOfProduction/vd:firstDate/dt:hour')
....
lor:endYear string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:year')
lor:endMonth string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:month')
lor:endDay string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:day')
lor:endhour string(10), name('vd:certifiedConsignment/vd:batch/vd:expiryDate/vd:firstDate/dt:hour')
Тот же самый [ПИП] и у нас в Меркурии. Работает. И переделывать это конечно уже никто не будет.

Но смотрите, в этой цитате заданы теги типовой даты производства и срока годности (неполные).
И каждая такая типовая дата каждый раз разворачивается в полный путь ... хотя должна быть описана один раз.
И так везде. Вместо структуры - кирпичи, с которыми сложно работать, модифицировать и т.д.
Конечно же в новых проектах такое лепить уже не хочется.
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 15:16
finsoftrz
А какие варианты, циклы с флагами и case/if? На мое восприятие, это еще хуже.
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 15:20
finsoftrz
В принципе, никто нам не мешает оформить повторяющиеся названия тэгов в виде макросов. Как-то не думалось в эту сторону. Вроде все понятно, как есть в структуре, так и пишем в name.
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 15:29
Игорь Столяров
finsoftrz писал(а): 27 Февраль 2023, 15:16
На мое восприятие, это еще хуже
Здесь нужно понять главное различие подходов.
XML (JSON) - это структурированные данные. Не CSV / TXT.
Нахождение данных на определённом уровне структуры - задаёт и меняет смысл этих данных.
При работе с "длинными" именами - мы в линейном GROUP и пытаемся описать структуру в Name('X1\X2\X3 ...')
Но ведь можно (и правильно !) задать эту структру через вложенные GROUP.
И тогда не нужно повторять развёрнутым каждый типовой тег только для того, что бы задать его NAME. Вот !

Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 17:34
finsoftrz
Мне кажется, это дебри. То есть, по сути, Вы пытаетесь на кларионовских структурах сделать зеркальное отражение xml. База данных у нас не древовидная, а реляционная. Смысл парсинга не повторить все внешние структуры, а привести получаемую из них информацию к стандартному для нас представлению, с которым мы работаем внутри приложения. То есть к набору обычных кьюшек и групп. Потом надо с этой информацией работать - сохранять в базе данных, выводить в окна или печатные формы. Я это так воспринимаю.
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 18:00
Игорь Столяров
finsoftrz писал(а): 27 Февраль 2023, 17:34
на кларионовских структурах сделать зеркальное отражение xml
Иное. Я пытаюсь работать с той же структурой данных, в которой составлен XML документ.
Т.е. у документа есть покупатель, покупатель имеет данные ЮЛ, у ЮЛ есть директор, у директора есть ФИО.
Эта структура - свойство данных. А Вы переводите это в свойство кода - задавая в Name('X1\X2 ...') параметры (программу)
работы парсера / скрипта для поиска данных. Ну и для себя название поля - что совсем в этом не запутаться.
Но сама Queue - линейна, все поля равноправны и ещё придётся выкручиваться с именами, если несколько раз
встречаются однотипные структуры вроде даты или ФИО ...
По Вашему примеру из Меркурия - Вы не можете просто одной командой удалить срок годности или присвить ей
дату производства. Или добавить во все места где встречается дата - неформальное значение informalDate.
Поиск, перебор полей, что-то потерялось, где-то съехало и т.д.

Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 18:35
finsoftrz
Зачем надо "одной командой удалить срок годности или присвоить ей дату производства"? Что-то Вы заработались.
На мое восприятие, куда проще - создали структуру/структуры, в которой заложено то, что нам надо в терминах предметной области. Приписали name, которое соответствует тэгам в xml. Размазано у них по нескольким тэгам (как дата на год, месяц, день), подстроились, после парсинга приведем к обычной дате, в таком виде оно использоваться дальше не будет. Я не очень понимаю, зачем из одной сложной иерархической структуры грузить в другую сложную иерархическую структуру. Чтобы потом что?
К слову, загружать ФИО из накладной в ЭДО идея фикс. Информация о контрагенте заносится в информационную систему при заключении договора, а не когда шлют накладные. Из файла ЭДО достаточно взять ИНН, по нему определяется контрагент.
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 19:45
Игорь Столяров
finsoftrz писал(а): 27 Февраль 2023, 18:35
в информационную систему при заключении договора, а не когда шлют накладные
Бывает и такое.

Но ведь не обязательно для покупки товара заключать договор ...
Вы пытаетесь вместо решения общей задачи загрузки данных из ЭДО (или любой XML) -
каждый раз решать задачу конкретного бухгалтера с его идеями. Пришёл документ,
где торкнуло записать штрих-код в GTIN - делаем так, потом пришёл документ где
штрих-код в поле кода, добавили в скрипт костыль искать штрих-код там ...
И вроде, всё работает сразу в двух местах. Но это тупиковый путь - Вы рано или поздно
столкнётесь с объёмами данных, которые сложно лечить костылями "по факту обращения".
А попытка сделать парс XML правильно приведёт Вас туда же, куда и меня.

Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 20:31
finsoftrz
Откуда Вы знаете, как правильно? Любое решение принимается во времени, на основании тех знаний, которые есть на этот момент. Есть интуиция и опыт, которые позволяют выстраивать систему таким образом, чтобы минимизировать затраты на внесение изменений, когда исходные вводные поменяются.
В примере со штрих-кодом. Реальные случаи из практики, когда один поставщик при наличии gtin (для маркированных товаров) не указывает штрих-код в дополнительных параметрах товара. А для немаркированных товаров указывает. Пока не придет подобная накладная, об этом и не узнаете.
Вообще, это банальные вещи, странно, что приходится рассказывать. Погуглите про agile и подобные современные методики разработки.
Про тупиковый путь и костыли, это было смешно.
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 20:52
Игорь Столяров
finsoftrz писал(а): 27 Февраль 2023, 20:31
Откуда Вы знаете, как правильно?
Инструкцию прочитал.

Я понимаю, что обидно когда кто-то приходит и обесценивает
казалось бы огромный труд "тонкой настройки по реальной практике". Но я с уважением
отношусь к любой работе и ищу пути решения общей задачи по законодательству РФ.

Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 21:26
finsoftrz
Обижаются дети в песочнице.

Вы ничего не обесценили, все давно сделано и успешно работает в изменяющихся условиях. Затраты минимальны, я же не пытаюсь объять необъятное. Игорь, Вы меня так троллите или реально думаете, что достаточно "прочитать инструкцию" и со всеми нюансами разберетесь? Думаю, все таки первое, так как сами понимаете, что инструкции очень объемные, содержат много избыточной информации о том, что у Ваших пользователей никогда не встретится, в них много противоречий и нестыковок, много чего не оговорено, они еще и регулярно изменяются. Одному человеку не под силу разбираться во всем этом, да еще автоматизировать. Поэтому я стараюсь максимально включать пользователей. Совместно читаем, обсуждаем, они по своим каналам консультируются, смотрим реализации где-нибудь в 1с, сбис и т.п., потом картинка устаканивается, делается реализация в системе, потом совместно тестируем на реальных данных. Вариантов нет, иначе не работает, слишком много ресурсов надо.
Функция обратная WHERE()
Добавлено: 27 Февраль 2023, 21:54
Игорь Столяров
Я инструкцией называю законодательство РФ. Там всё конкретно (хотя и нудно) описано.
Если сравнивать с Меркурием - то объём документации по ЭДО просто смешной.
Я хочу иметь инструмент, который позволит разбирать документ ЭДО (и любой XML файл)
в соответствии с законодательством РФ. И это не исключает т.н. тонких местных настроек.
К моему большому сожалению Вы не можете посмотреть пример парсера на улучшенной
среде разработки. А там показано, как получается список дополнительных показателей
в структуру "ТекстИнфТип" (самого бесит - но так её назвали в законе).
И если какой-то местный укротитель 1С туда пишет штрих-коды - заберите их там.
Завтра захочет записать срок годности или сертификат - заберите, без проблем.
И для этого не нужно каждый раз "улучшать" и настраивать парсер, потому что в законе
предусмотрена запись в эту структуру дополнительной информации о товаре.
Нужно просто один раз сделать получение всех данных и далее их использовать.
Как-то так.
