Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Вывод элементов списка в виде массива (http://forum.oszone.net/showthread.php?t=354430)

NickM 25-10-2023 19:24 3018885

Вывод элементов списка в виде массива
 
Уважаемые, здравствуйте!

Задалcя вопросом обработки *.xml файлов, вроде бы даже добился какого-никакого решения поставленной перед Собою задачи, но вот одного не могу разрешить: вывод элемента списка в виде массива, Powershell его "подрезает" и отображает только несколько первых символов.

Список объявляю так:
Код:

$list2 = New-Object System.Collections.Generic.List[System.Object];
Наполняю так:
Код:

$aSumItog = @(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
foreach ($item in $tmplist2) {
        $list2.Add([PSCustomObject]@{cFIO = $item; cSum = $aSumItog})
}

При выводе в консоль или в файл вижу следуюущее:
Код:

cFIO                            cSum                 
----                            ----                 
Петров Петр Петрович      {0, 0, 0, 0...}

, а хотелось бы видеть все столбцы массива.

Может, кто подскажет как этого добиться?

Sham 26-10-2023 01:08 3018908

Код:

... | Format-Table 'cFIO', @{ Label='cSum'; Expression={ $_.cSum -join ', ' } }

Serguei Kouzmine 26-10-2023 04:44 3018911

еще есть вариант перестать рассчитывать на нативные типы повершелла и просто как JSON выводить данные

Код:

$list2 | convertto-json -depth 10
...


Код:

{
        "cFIO":  "Петров Петр Петрович",
        "cSum":  [
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0
                ]
    }
]


NickM 26-10-2023 06:23 3018912

Цитата:

Цитата Serguei Kouzmine
и просто как JSON выводить данные »

Ага, сгодится для дальнейшего парсинга, но Мне надо было в табличный вид, для человеческого восприятия;

Цитата:

Цитата Sham
Код:

... | Format-Table 'cFIO', @{ Label='cSum'; Expression={ $_.cSum -join ', ' } }
»

Спасибо, попробую прикрутить.

Вчера уже выкрутился созданием нового списка и впихиванием в него элементов массива, да, топорно получилось.

DJ Mogarych 26-10-2023 10:13 3018921

Код:

$aSumItog -join "`n"

YuS_2 26-10-2023 13:30 3018934

Цитата:

Цитата NickM
выкрутился созданием нового списка и впихиванием в него элементов массива »

массив приводим к строке (вариантов мульён) и впихиваем невпихуемое в столбец...
один из вариантов:
Код:

[string]$aSumItog

NickM 26-10-2023 14:09 3018935

Цитата:

Цитата YuS_2
один из вариантов: »

Благодарю за участие!

Поставленный вопрос решил, но очень мало опыта работы с powershell, практически нулевой.

Но, желаемого достиг, правда с излишним быдлокодом, да (стесняюсь полностью код выложить, там полный атас).

Поделюсь, может гуру, при желании, подскажут, как это упростить?


Пару блоков, которые Мне кажутся излишними, но не знаю как их упростить:


1.
В этом пункте требуется получить список $list1 с уникальными текстовыми значениями и инициализированным массивом чисел.

Наполняю два списка данными из *.xml, $tmplist1 используется как временный, для сортировки. В $list1 и $list3 производится работа с массивом числовых значений:
Код:

#Основные массивы-списки для всех требуемых значений
$list1 = New-Object System.Collections.Generic.List[System.Object];
$list3 = New-Object System.Collections.Generic.List[System.Object];
...
$list3.Add([PSCustomObject]@{cPeriod = $cPeriod; cFIO = $cFIO; cINN = $cINN; cSNILS = $cSNILS; cmes = $cMes; cSum = $cSum});
...

#Подготовим временный массив - выполним сортировку и уберём дубли сотрудников
$tmplist1 = New-Object System.Collections.Generic.List[System.Object];
$tmplist1 = $list3 | Select-Object cFIO, cINN, cSNILS | Sort-Object cFIO, cINN, cSNILS | Get-Unique -AsString

#Инициализируем список c перс.данными и пустым массивом для сумм
$aSumItog = @(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
foreach ($item in $tmplist1) {
$list1.Add([PSCustomObject]@{cFIO = $item.cFIO; cINN = $item.cINN; cSNILS = $item.cSNILS; cSum = $aSumItog})
}


2.
Как итог выполнения всего кода, наполненный рабочий список $list1 требуется вывести в *.csv с разделителем [char]9, т.е. сформировать табличную часть.

Реализовал, опять же, с использованием дополнительного списка, где наполняю этот список:
Код:

$tmplist3 = [System.Collections.Generic.List[string]]::new()
foreach ($item in $list1) {
        $tmplist3.Add($item.cFIO + [char]9 + $item.cINN + [char]9 + $item.cSNILS + [char]9 + ($item.cSum -join "`t"))
}

, а после сохраняю:
Код:

$tmplist3 | Out-File 'КНД_1151111.csv'

YuS_2 27-10-2023 09:45 3018979

Цитата:

Цитата NickM
Пару блоков, которые Мне кажутся излишними, но не знаю как их упростить »

Задача очень похожа на ситуацию с проблемой XY

Цитата:

Цитата NickM
Наполняю два списка данными из *.xml »

Здесь, для решения вопроса, просто необходимо увидеть задачу в целом.
Т.е. нужен пример файла (а лучше файлов) с исходными данными (конфиденциальную инфу можно заменить какими-нибудь фейками) и желаемый результат, т.е. то, что необходимо получить из исходных данных. Промежуточные "просмотры" данных в консоли, не имеют смысла обычно, но если сильно желание, то тоже надо бы указать в каком виде хочется их просматривать.

NickM 27-10-2023 11:28 3018995

Вложений: 1
Цитата:

Цитата YuS_2
Задача очень похожа на ситуацию с проблемой XY »

Не, задача предельная ясна и понятна - произвести сверку двух отчётных форм, которые в *.xml формате и развернуть их в табличный вид и сохранить в *.csv для возможности дальнейших манипуляций в табличном редакторе;

Сверка заключается в том, что бы проверить соответствие всех перс.данных по физ.лицам отражённых в трёх месячных формах 1151162 с квартальной формой 1151111.
Для этого, эти перс.данные из *.xml файлов извлекаются, помещаются в списки, а списки уже построчно сравниваются;

Цитата:

Цитата YuS_2
Т.е. нужен пример файла (а лучше файлов) с исходными данными (конфиденциальную инфу можно заменить какими-нибудь фейками) и желаемый результат »

Файлы найти не проблема, это электронный вариант отчётных форм налоговых деклараций КНД 1151111 и КНД 1151162.

Заменил и приложил;

Цитата:

Цитата YuS_2
Промежуточные "просмотры" данных в консоли, не имеют смысла обычно, но если сильно желание, то тоже надо бы указать в каком виде хочется их просматривать. »

Зачастую, в консоли, просматриваю/ отлаживаю вывод, из-за отсутствия знаний, т.к. сказать "негорячую" просматриваю результаты выполнения той или иной процедуры/ функции.

YuS_2 27-10-2023 14:43 3019015

Цитата:

Цитата NickM
помещаются в списки, а списки уже построчно сравниваются »

Цитата:

Цитата NickM
Файлы найти не проблема, это электронный вариант отчётных форм налоговых деклараций КНД 1151111 и КНД 1151162.
Заменил и приложил»

так, вот уже проще... только, что должно получиться из этих файлов на выходе? Т.е. конечный результат (файл) как должен выглядеть? Для полного понимания его тоже надо бы сделать вручную...
И да, судя по файлам, количество элементов (и атрибутов элементов тоже) в них различное... а могут быть ещё какие-нибудь поля, которых нет в примерах? Если парсить xml, то нужны будут наименования элементов, по которым необходимо делать выборку... или там просто всё подряд, что найдем, то и "выплюнуть" на выход?

NickM 27-10-2023 15:24 3019020

Вложений: 1
Цитата:

Цитата YuS_2
И да, судя по файлам, количество элементов (и атрибутов элементов тоже) в них различное... а могут быть ещё какие-нибудь поля, которых нет в примерах? Если парсить xml, то нужны будут наименования элементов, по которым необходимо делать выборку... или там просто всё подряд, что найдем, то и "выплюнуть" на выход? »

Можно вместо ответа прикреплю сценарий? Это не будет выглядеть наглостью?

UPD: Перезалил файл по причине добавления комментариев к сценарию.

Pavel Nagaev 27-10-2023 15:25 3019021

Придирки по коду :-).

$list1 = New-Object System.Collections.Generic.List[System.Object];
$list3 = New-Object System.Collections.Generic.List[System.Object];

Можно на это поменять

using namespace System.Collections.Generic
$list1 =[List[string]]@()
$list3 =[List[string]]@()


Табуляцию [char]9 на "`t"

Причём вы тут
$tmplist3.Add($item.cFIO + [char]9 + $item.cINN + [char]9 + $item.cSNILS + [char]9 + ($item.cSum -join "`t")

используте "`t", но зачем-то и [char]9


вот это
$list3.Add([PSCustomObject]@{cPeriod = $cPeriod; cFIO = $cFIO; cINN = $cINN; cSNILS = $cSNILS; cmes = $cMes; cSum = $cSum});

на это и в конце строки ; не нужна.

$list3.Add([PSCustomObject]@{cPeriod = $cPeriod;
cFIO = $cFIO;
cINN = $cINN;
cSNILS = $cSNILS;
cmes = $cMes;
cSum = $cSum;
}
)
Это чисто удобство чтения.

Кодировку добавить.

$tmplist3 | Out-File 'КНД_1151111.csv' -Encoding utf8

NickM 27-10-2023 15:32 3019022

Цитата:

Цитата Pavel Nagaev
Придирки по коду :-). »

Благодарю, приму к сведению;

Цитата:

Цитата Pavel Nagaev
используете "`t", но зачем-то и [char]9 »

Только учусь :sorry:

Цитата:

Цитата Pavel Nagaev
Кодировку добавить. »

Ага, сейчас сохраняет в "UTF16-LE", но в том же "Excel" кириллица отображается корректно.

YuS_2 27-10-2023 18:43 3019042

Цитата:

Цитата NickM
Можно вместо ответа прикреплю сценарий? Это не будет выглядеть наглостью? »

Да ноу проблемс, но так будет дольше и результат - не факт, что получится то, что требуется. Лучше было бы увидеть результат, который нужен... ну, или алгоритм, что куда и зачем.

NickM 27-10-2023 18:45 3019043

Цитата:

Цитата YuS_2
ну, или алгоритм, что куда и зачем. »

Цитата:

Цитата NickM
UPD: Перезалил файл по причине добавления комментариев к сценарию. »

Прокомментировал каждый блок кода.

YuS_2 28-10-2023 18:18 3019085

Цитата:

Цитата NickM
Прокомментировал каждый блок кода. »

если бы эти комментарии могли помочь...
В общем, я предупреждал, что без алгоритма действий, результат может выйти совсем не таким, каким ожидался... :)
script.ps1 (кодировку скрипта лучше выбрать UTF8)
Код:

function Get-NodeAttrDoc ($xml,$node,$enc){
        process{
                $n = $xml.selectnodes("//$node")
                [pscustomobject]@{
                        'КНД' = $n.кнд
                        'Период' = $n.период
                }
        }
}

function Get-NodeDataOut ($xml,$node,$per,$dat,$fio,$enc,$knd){
        process{
            $t = $xml.selectnodes("//$node")
            $f = $t.$fio
            $s = @(@(0)*13)
            if (($i=[int]$per) -lt 13){$s[$i] = [int]$t.сумвыпл} else {
                $sv = [int[]]$xml.selectnodes("//$dat").сумвыпл
                switch ($per){
                    $kv[0]{$s[1]=$sv[0];$s[2]=$sv[1];$s[3]=$sv[2]}
                    $kv[1]{$s[4]=$sv[0];$s[5]=$sv[1];$s[6]=$sv[2]}
                    $kv[2]{$s[7]=$sv[0];$s[8]=$sv[1];$s[9]=$sv[2]}
                    $kv[3]{$s[10]=$sv[0];$s[11]=$sv[1];$s[12]=$sv[2]}
                }
                $s[0] = ($s|measure -sum).sum
            }
                [pscustomobject]@{
                    'КНД' = $knd
                        'ФИО' = ($f.фамилия,$f.имя,$f.отчество) -join ' '
                        'ИННФЛ' = $t.иннфл
                        'СНИЛС' = $t.снилс
                        'СумГод' = [int]$s[0]
                        '01' = $s[1]
                        '02' = $s[2]
                        '03' = $s[3]
                        '04' = $s[4]
                        '05' = $s[5]
                        '06' = $s[6]
                        '07' = $s[7]
                        '08' = $s[8]
                        '09' = $s[9]
                        '10' = $s[10]
                        '11' = $s[11]
                        '12' = $s[12]
                }
        }
}

function get-sumdoc1162 ($elem,$i){
    $b = $i|%{($elem.$_|measure -sum).sum}
        [pscustomobject]@{
                'КНД' = $elem.кнд[0]
                'ФИО' = $elem.фио[0]
                'ИННФЛ' = $elem.иннфл[0]
                'СНИЛС' = $elem.снилс[0]
                'СумГод' = [int]($b|measure -sum).sum
                '01' = [int]$b[0]
                '02' = [int]$b[1]
                '03' = [int]$b[2]
                '04' = [int]$b[3]
                '05' = [int]$b[4]
                '06' = [int]$b[5]
                '07' = [int]$b[6]
                '08' = [int]$b[7]
                '09' = [int]$b[8]
                '10' = [int]$b[9]
                '11' = [int]$b[10]
                '12' = [int]$b[11]
        }
}

$path = $psscriptroot
if ($host.version.major -gt 5) {
    $enc = 'windows-1251'
    $csv = @{
        Encoding = 'utf8'
        NoTypeInformation = $true
        QuoteFields = 'ФИО'
    }
} else {
    $enc = 'default'
    $csv = @{
        Encoding = 'utf8'
        NoTypeInformation = $true
    }
}
$flt = 'NO_*.xml'
$nd = 'Документ'
$nd_dfl = 'ДанФЛПолуч'
$nd_svmk = 'СвВыплМК'
$nd_psfl = 'ПерсСвФЛ'
$fio = 'ФИО'
$kv = @('21','31','33','34')
$arr1162_i, $arr1111 = @(),@()

dir $path -filt $flt -file|%{
    $x = [xml](gc $_.fullname -enc $enc)
    $tmp = get-nodeattrdoc $x $nd $enc
    $knd = $tmp.кнд
    $per = $tmp.период
    if ($knd -eq '1151111'){
        $arr1111 += get-nodedataout -xml $x -node $nd_dfl -per $per -d $nd_svmk -f $fio -enc $enc -knd $knd
    } else {
        $arr1162_i += get-nodedataout -xml $x -node $nd_psfl -per $per -f $fio -enc $enc -knd $knd
    }
}
$m = 1.. 12|%{"$_".padleft(2,'0')}
$arr1162 = $arr1162_i|group -prop 'иннфл'|%{get-sumdoc1162 $_.group $m}
$arr1162|sort 'ФИО'|export-csv '1162.csv' @csv
$arr1111|sort 'ФИО'|export-csv '1111.csv' @csv

$arr1111+$arr1162|sort 'ФИО'|ft * -a -w


NickM 28-10-2023 21:36 3019096

Цитата:

Цитата YuS_2
результат может выйти совсем не таким, каким ожидался... »

Результат вышел и в принципе по коду всё понятно - Вы вообще не использовали списки и обошлись только массивами, всё завернули в процедуры/ функции и передачами параметров в оные (одной функцией считали данные из двух разных форм), избавились от сравнения текстовых переменных, не учли копейки и возможное отсутствие некоторых тегов.

Круто!

YuS_2 28-10-2023 22:26 3019100

Цитата:

Цитата NickM
Результат вышел »

Оно и понятно, что даже отсутствие результата - тоже результат... Вопрос только в том, выполняет код необходимую задачу или нет. :)

Цитата:

Цитата NickM
не использовали списки »

а зачем они здесь?

Цитата:

Цитата NickM
не учли копейки »

а их надо учитывать?

Цитата:

Цитата NickM
и возможное отсутствие некоторых тегов »

примеры, примеры и ещё раз примеры исходных данных... они всегда нужны для тестов.

NickM 28-10-2023 22:49 3019104

Вложений: 1
Цитата:

Цитата YuS_2
а зачем они здесь? »

Цитата:

Цитата NickM
Не, задача предельная ясна и понятна - произвести сверку двух отчётных форм»

Сам использовал такой код:
Код:

#Выполним сверку между отчётами и результат сохраним в файл
$tmplist4 | ?{$tmplist3 -notcontains $_} | Out-File 'Отсутствуют_в_КНД_1151111.csv';
$tmplist3 | ?{$tmplist4 -notcontains $_} | Out-File 'Отсутствуют_в_КНД_1151162.csv';

Цитата:

Цитата YuS_2
а их надо учитывать? »

Ага, у Нас пока платят в рублях и с копейками:
Цитата:

СумВыпл="70000.00"
Цитата:

Цитата YuS_2
Цитата NickM:
и возможное отсутствие некоторых тегов » »

Сам проверял отсутствие тегов в сравнении с $null:
Код:

if ($item3.cMes -ne $null) {}
...
if ($aSum[$index] -eq $null) {}

Цитата:

Цитата YuS_2
примеры, примеры и ещё раз примеры исходных данных... они всегда нужны для тестов. »

Вот, добавил пару строк в тестовые файлы, на которых может всплыть ошибка преобразования типов данных.

YuS_2 29-10-2023 12:23 3019118

Цитата:

Цитата NickM
Не, задача предельная ясна и понятна - произвести сверку двух отчётных форм» »

И всё равно, это не ответ на вопрос:
Цитата:

Цитата YuS_2
а зачем они здесь? »

Если задать его по-другому: а зачем именно списки? Т.е. вот это:
Код:

New-Object System.Collections.Generic.List[System.Object]
для чего? Чем обычные массивы не устроили?
А на счет сверки двух отчетных форм... что именно сверяется? Вы же не думаете, что скилл телепатии у меня настолько развит? :)
По Вашим примерам понятно, что есть два вида форм, одна из которых содержит данные за месяц, другая за квартал... так вот каким образом Вам необходимо их сверять? Помесячно, поквартально, за год, за пятилетку и т.д.
Т.е. технически сверку сделать - вообще, не проблема. Тут важно получить данные и получить их в том виде, который требуется...

Цитата:

Цитата NickM
Ага, у Нас пока платят в рублях и с копейками »

Вот видите, это пример того, что без внятного ТЗ, как правило и результат ХЗ :)
У нас, например, не в рублях и нет никаких копеек...

Далее...
Цитата:

Цитата NickM
Вот, добавил пару строк в тестовые файлы, на которых может всплыть ошибка преобразования типов данных. »

На основании имеющихся исходных файлов, предполагалось, что на отдельное физлицо приходится по отдельному же файлу (помесячно и поквартально)... видимо, ошибочное было предположение и естественно, парсер, построенный на неверных предположениях, будет и работать неверно... В общем-то, именно поэтому и требуется описание задачи и примеры наиболее различные между собой и желательно не на единственного человека, а на нескольких, чтобы учесть все нюансы. Ковырять же чужой код для восстановления алгоритма - не самый продуктивный вид программирования...

Мой код опирался, помимо основной, больше на вот эту задачу (собственно, в первом сообщении, это и было главным вопросом):
Цитата:

Цитата NickM
Мне надо было в табличный вид, для человеческого восприятия »

По коду парсера:
Основной скелет кода составлен, но для доведения этого кода "до ума", необходимо таки уточнение многих моментов, которые было бы неплохо описать в виде:
1. Вот исходные файлы, на одного-два-три-...-n физлиц.
2. Из них необходимо получать вот такие вот две формы (суммы ли в тех формах должны быть, либо только отдельные данные, сведенные по ИННФЛ или по какому-то ещё признаку, что-то ещё важное...).
3. В общем, сами эти итоговые формы, вернее их содержание, для сверки (опять же по нескольким физлицам), которые должны получиться из исходных данных, необходимо "нарисовать" вручную. А также требующийся формат конечных, выходных файлов, тоже было бы неплохо указать.
Так будет проще составить парсер, который будет делать то, что от него требуется.

По новым примерам было, конечно, проще поправить код... но непонятно, как могут возникать различия при сверке, т.к. Вашим кодом они не обнаружены. В том смысле, что вроде бы нужны ещё и четкие примеры таких различий в исходных данных, которые требуется обнаруживать сверкой.
Вот код, в котором можно легко сделать сверку по тем данным, которые Вы предоставили, но за один квартал. Не обращайте внимание, что нет выходных файлов сверки (это организовать несложно), смотрите в консоль, там можете визуально сравнивать данные, сгруппированные по ИННФЛ. В версии powershell 5.1 автоматическое преобразование типов сделает вывод целых чисел, без нулей после запятой (при желании можно сделать принудительную типизацию), а в версии PS 7.3.6, все числа будут выведены, как [double]
Код:

function Get-NodeAttrDoc ($xml,$node,$enc){
    process{
        $n = $xml.selectnodes("//$node")
        [pscustomobject]@{
            'КНД' = $n.кнд
            'Период' = $n.период
        }
    }
}

function Get-NodeDataOut ($xml,$node,$per,$dat,$fio,$enc,$knd){
    process{
        $tarr = $xml.selectnodes("//$node")
        $out = foreach($t in $tarr){
            $f = $t.$fio
            $s = @(@([double]0)*13)
            if (($i=[int]$per) -lt 13){$s[$i] = [double]$t.сумвыпл} else {
                $sv = [double[]]$xml.selectnodes("//$dat").сумвыпл
                switch ($per){
                    $kv[0]{$s[1]=$sv[0];$s[2]=$sv[1];$s[3]=$sv[2]}
                    $kv[1]{$s[4]=$sv[0];$s[5]=$sv[1];$s[6]=$sv[2]}
                    $kv[2]{$s[7]=$sv[0];$s[8]=$sv[1];$s[9]=$sv[2]}
                    $kv[3]{$s[10]=$sv[0];$s[11]=$sv[1];$s[12]=$sv[2]}
                }
                $s[0] = ($s|measure -sum).sum
            }
            [pscustomobject]@{
                'КНД' = $knd
                'ФИО' = ($f.фамилия,$f.имя,$f.отчество) -join ' '
                'ИННФЛ' = $t.иннфл
                'СНИЛС' = $t.снилс
                'СумГод' = $s[0]
                '01' = $s[1]
                '02' = $s[2]
                '03' = $s[3]
                '04' = $s[4]
                '05' = $s[5]
                '06' = $s[6]
                '07' = $s[7]
                '08' = $s[8]
                '09' = $s[9]
                '10' = $s[10]
                '11' = $s[11]
                '12' = $s[12]
            }
        }
    }
    end{return $out}
}

function get-sumdoc1162 ($elem,$i){
    $b = $i|%{($elem.$_|measure -sum).sum}
    [pscustomobject]@{
        'КНД' = $elem.кнд[0]
        'ФИО' = $elem.фио[0]
        'ИННФЛ' = $elem.иннфл[0]
        'СНИЛС' = $elem.снилс[0]
        'СумГод' = ($b|measure -sum).sum
        '01' = $b[0]
        '02' = $b[1]
        '03' = $b[2]
        '04' = $b[3]
        '05' = $b[4]
        '06' = $b[5]
        '07' = $b[6]
        '08' = $b[7]
        '09' = $b[8]
        '10' = $b[9]
        '11' = $b[10]
        '12' = $b[11]
    }
}

$path = "$psscriptroot\xml"
if ($host.version.major -gt 5) {
    $enc = 'windows-1251'
    $csv = @{
        Encoding = 'utf8'
        NoTypeInformation = $true
        UseQuotes = 'AsNeed'
    }
} else {
    $enc = 'default'
    $csv = @{
        Encoding = 'utf8'
        NoTypeInformation = $true
    }
}
$flt = 'NO_*.xml'
$nd = 'Документ'
$nd_dfl = 'ДанФЛПолуч'
$nd_svmk = 'СвВыплМК'
$nd_psfl = 'ПерсСвФЛ'
$fio = 'ФИО'
$kv = @('21','31','33','34')
$arr1162_i, $arr1111 = @(),@()

dir $path -filt $flt -file|%{
    $x = [xml](gc $_.fullname -enc $enc)
    $tmp = get-nodeattrdoc $x $nd $enc
    $knd = $tmp.кнд
    $per = $tmp.период
    $ndo = @{XML=$x;PER=$per;FIO=$fio;ENC=$enc;KND=$knd}
    if ($knd -eq '1151111'){
        $arr1111 += get-nodedataout @ndo -node $nd_dfl -d $nd_svmk
    } else {
        $arr1162_i += get-nodedataout @ndo -node $nd_psfl
    }
}
$m = 1.. 12|%{"$_".padleft(2,'0')}
$arr1162 = $arr1162_i|group -prop 'иннфл'|%{get-sumdoc1162 $_.group $m}
$arr1162|sort 'ФИО'|export-csv '1162.csv' @csv
$arr1111|sort 'ФИО'|export-csv '1111.csv' @csv
$arr1111+$arr1162|sort 'ФИО'|ft * -a -w


YuS_2 29-10-2023 12:51 3019119

Да, совсем забыл:
код просто подкорректирован для наличия нескольких однотипных элементов в одном файле, но считать может пока неверно... т.е. его ещё надо проверять.

NickM 29-10-2023 12:55 3019120

Цитата:

Цитата YuS_2
По новым примерам было, конечно, проще поправить код... но непонятно, как могут возникать различия при сверке, т.к. Вашим кодом они не обнаружены. »

Всё верно, т.к. в приложенных примерах расхождений не имеется, но как только у физ.лица изменить хоть какой-нибудь сравниваемый тег - ИНН, СНИЛС, сумму в любом месяце квартала в любой из форм, сразу выйдет расхождение;

Цитата:

Цитата YuS_2
Вот видите, это пример того, что без внятного ТЗ, как правило и результат ХЗ »

Извините, полагал, что описание в посте и комментарий в коде окажется достаточным :sorry:
Скрытый текст
Цитата:

ТЗ.
1. Получить табличное представление каждой из форм, где каждая строка представляет из себя:
ФИО, ИНН, СНИЛС, итоговая сумма за год, ежемесячная сумма за каждый месяц – [1], [2]…[12];

2. Произвести сверку двух форм, где различие составляют как перс.данные(ФИО, ИНН, СНИЛС), как итоговая сумма за год, так и суммы за каждый месяц;

Сверка форм осуществляется в разрезе квартала/ кварталов. Т.е. форм 1151162 всегда кратно 3 количества форм 1151111, т.е. если сверяем один квартал, тогда 1151162= 3шт., 1151111= 1шт., сверяем 2 квартала – 6шт. и 2 шт. соответственно (по сути, это не имеет значения, т.к. для проверки всегда подаётся правильное количество форм).

Некоторые замечания по формам:
В 1151111 могут отсутствовать сравниваемые теги с суммами в следующем узле, как и сам родительский узел: «СвВыплСВОПС»--> «СвВыпл»--> «СвВыплМК».


Цитата:

Цитата YuS_2
но для доведения этого кода "до ума", необходимо таки уточнение многих моментов, которые было бы неплохо описать в виде: »

Опять же упомяну приложенный Мною рабочий код, который формирует как табличные данные, так и выполняет сверку;

Цитата:

Цитата YuS_2
Основной скелет кода составлен »

Да, Вы показали как использовать процедуры/ функции в powershell и не только это, что возьму на вооружение/ непременно этим воспользуюсь.

YuS_2 29-10-2023 17:31 3019132

Цитата:

Цитата NickM
но как только у физ.лица изменить хоть какой-нибудь сравниваемый тег - ИНН, СНИЛС, сумму в любом месяце квартала в любой из форм, сразу выйдет расхождение »

Понятно, так и сделал... вылезли ещё баги... поправлены

Цитата:

Цитата NickM
Извините, полагал, что описание в посте и комментарий в коде окажется достаточным »

Ну, номера форм для меня малоинформативны оказались... а код чужой разбирать... ну, это не очень продуктивно, учитывая, что автор кода мог иметь свой алгоритм для реализации задачи и по коду не всегда его можно легко определить.

Цитата:

Цитата NickM
ТЗ. »

Так гораздо понятнее!

Примерно так:
Код:

# Функция получения кода документа и периода (месяц/квартал)
function Get-NodeAttrDoc ($xml,$node,$enc){
    process{
        $n = $xml.selectnodes("//$node")
        [pscustomobject]@{'КНД' = $n.кнд;'Период' = $n.период}
    }
}

# Функция формирования выходных данных
function Get-NodeDataOut ($xml,$node,$pnode,$per,$dat,$fio,$enc,$knd){
    process{
        $tarr = $xml.selectnodes("//$node")
        $out = foreach($t in $tarr){
            $s,$sv,$tsv = @(@([double]0)*13),@(@([double]0)*3),$null
            if($pnode){
                $f,$inn,$sni = $t.$pnode.$fio,$t.$pnode.иннфл,$t.$pnode.снилс
            } else {
                $f,$inn,$sni = $t.$fio,$t.иннфл,$t.снилс
            }
            if (($i=[int]$per) -lt 13){$s[$i] = [double]$t.сумвыпл} else {
                $tsv = $t.getelementsbytagname($dat)
                if ($tsv){
                    foreach($it in $tsv){
                        $sv[([int]$it.месяц-1)] = [double]$it.сумвыпл
                    }
                }
                switch ($per){
                    $kv[0]{$s[1]=$sv[0];$s[2]=$sv[1];$s[3]=$sv[2]}
                    $kv[1]{$s[4]=$sv[0];$s[5]=$sv[1];$s[6]=$sv[2]}
                    $kv[2]{$s[7]=$sv[0];$s[8]=$sv[1];$s[9]=$sv[2]}
                    $kv[3]{$s[10]=$sv[0];$s[11]=$sv[1];$s[12]=$sv[2]}
                }
                $s[0] = ($s|measure -sum).sum
            }
            [pscustomobject]@{
                'КНД' = $knd
                'ФИО' = ($f.фамилия,$f.имя,$f.отчество) -join ' '
                'ИННФЛ' = $inn
                'СНИЛС' = $sni
                'СумГод' = $s[0]
                '01' = $s[1]
                '02' = $s[2]
                '03' = $s[3]
                '04' = $s[4]
                '05' = $s[5]
                '06' = $s[6]
                '07' = $s[7]
                '08' = $s[8]
                '09' = $s[9]
                '10' = $s[10]
                '11' = $s[11]
                '12' = $s[12]
            }
        }
    }
    end{return $out}
}

# Функция суммирования отдельных документов на единое лицо
function get-sumdoc1162 ($elem,$i){
    $b = $i|%{($elem.$_|measure -sum).sum}
    [pscustomobject]@{
        'КНД' = $elem[0].кнд
        'ФИО' = $elem[0].фио
        'ИННФЛ' = $elem[0].иннфл
        'СНИЛС' = $elem[0].снилс
        'СумГод' = ($b|measure -sum).sum
        '01' = $b[0]
        '02' = $b[1]
        '03' = $b[2]
        '04' = $b[3]
        '05' = $b[4]
        '06' = $b[5]
        '07' = $b[6]
        '08' = $b[7]
        '09' = $b[8]
        '10' = $b[9]
        '11' = $b[10]
        '12' = $b[11]
    }
}

# Инициализация переменных и сплаттинг
$path = "$psscriptroot\xml"
if ($host.version.major -gt 5) {
    $enc = 'windows-1251'
    $csv = @{
        Encoding = 'utf8'
        NoTypeInformation = $true
        UseQuotes = 'AsNeed'
    }
} else {
    $enc = 'default'
    $csv = @{
        Encoding = 'utf8'
        NoTypeInformation = $true
    }
}
$flt = 'NO_*.xml'
$nd = 'Документ'
$nd_pssl = 'ПерсСвСтрахЛиц'
$nd_dfl = 'ДанФЛПолуч'
$nd_svmk = 'СвВыплМК'
$nd_psfl = 'ПерсСвФЛ'
$fio = 'ФИО'
$kv = @('21','31','33','34')
$arr1162_i, $arr1111 = @(),@()

# Основной код
dir $path -filt $flt -file|%{
    $x = [xml](gc $_.fullname -enc $enc)
    $tmp = get-nodeattrdoc $x $nd $enc
    $knd = $tmp.кнд
    $per = $tmp.период
    $ndo = @{XML=$x;PER=$per;FIO=$fio;ENC=$enc;KND=$knd}
    if ($knd -eq '1151111'){
        $arr1111 += get-nodedataout @ndo -node $nd_pssl -pnode $nd_dfl -d $nd_svmk
    } else {
        $arr1162_i += get-nodedataout @ndo -node $nd_psfl
    }
}
#Получаем список кодов периодов помесячно:
$m = 1.. 12|%{"$_".padleft(2,'0')}
# Суммируем помесячные документы на одно лицо (единый ИННФЛ) в единую строку:
$arr1162 = $arr1162_i|group -prop 'иннфл'|%{get-sumdoc1162 $_.group $m}

# Экспорт в CSV файлы
$arr1162|sort 'ФИО'|export-csv '1162.csv' @csv
$arr1111|sort 'ФИО'|export-csv '1111.csv' @csv

# Вывод в консоль общей таблицы:
$arr1111+$arr1162|sort 'ФИО','КНД'|ft * -a -w

# Получение различий с индикаторами:
diff $arr1111 $arr1162 -prop "ФИО","ИННФЛ",'СумГод','01','02',
'03','04','05','06','07','08','09','10','11','12'|export-csv 'diff.csv' @csv

- подробно комментировать не стал, просто обозначил где что расположено.
Формируются два выходных файла с данными в CSV формате, плюс CSV-файл с различиями в данных, если таковые обнаружатся - файл хоть и один, но у каждой строки будет индикатор из какого массива получены данные: "<=" - ReferenceObject и "=>" - DifferenceObject

NickM 29-10-2023 18:44 3019136

Цитата:

Цитата YuS_2
- подробно комментировать не стал, просто обозначил где что расположено. »

Благодарю, код полностью читаем и понятен.

На выборочных данных работает в среднем на 100-150 миллисекунд быстрее (проверку СНИЛС в diff добавить не составило труда :) ).

YuS_2 29-10-2023 19:33 3019137

NickM, а, да, забыл совсем... есть ещё более наглядная визуализация табличных данных.
Замените код здесь:
Код:

$arr1111+$arr1162|sort 'ФИО','КНД'|ft * -a -w
на такой:
Код:

$arr1111+$arr1162|sort 'ФИО','КНД'|ogv

NickM 29-10-2023 19:37 3019139

Цитата:

Цитата YuS_2
есть ещё более наглядная визуализация табличных данных. »

Ага, отображение в гриде.

Спаcибо, но достаточно *.csv для табличного редактора "Excel".


Время: 19:13.

Время: 19:13.
© OSzone.net 2001-