powershell:将 foreach 循环数据从 csv 文件递增到 xml 输出文件
powershell : increment foreach loop datas from a csvfile to an xml output file
你能帮我实现一个计数器,以便生成一个 xml 文件,其中包含来自 csv 的多个元素吗?
这是csv文件
UCB63_DATENUM;U6618_FILENAME;UF6E8_CANAL;U65B8_IDRP
7/8/19 22:27;457E6659_ZN_LIQRLVPR_A_V_ML.pdf;ML;1367091
9/11/19 23:03;49453878_ZN_LIQRLVPR_A_V_ML.pdf;ML;106440
9/24/19 21:04;497E585B_ZN_LIQRLVPR_A_V_CS.pdf;CS;1536658
2/12/20 22:12;58453B75_ZN_LIQRLVPR_A_V_ML.pdf;ML;1406091
和代码
我在屏幕上的 return 很好,但由于我没有调用该值,因此无法递增。
目前我尝试过的所有事情都有一个坏问题(只有最后一个结果似乎每隔一个就会崩溃)
请帮帮我
#vARIABLES EN DUR
$FREQUENCE_DECOMPTE = 'Nom="FREQUENCE_DECOMPTE" Valeur="MENS"'
$LIBELLE_ORGANISME = 'Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"'
$MONTANT_TOTAL = 'Nom="MONTANT_TOTAL" Valeur="0"'
$POLE = 'Nom="POLE" Valeur="1ADP"'
$CODE_ORGANISME = 'Nom="CODE_ORGANISME" Valeur="1ADP"'
# Paramètre nombre item par xml VALEUR A MODIFIER A 5000
$maxItemsPerXml = 3
# Nombre de process restants
$restant = $liste.Count
# Paramétrage compteur
#Import du csv et création des différentes collections
$liste = Import-Csv -path 'c:\temp\testH.csv' -Delimiter ';'
[System.Collections.ArrayList] $DateErrors = @()
[System.Collections.ArrayList] $FileNameErrors = @()
[System.Collections.ArrayList] $CanalErrors = @()
[System.Collections.ArrayList] $NumAssureErrors = @()
#création fichier
$xmlFile = "C:\Temp\MIG_ERELEVE_MM_$(get-date -f dd-MM-yyyy)_{0:D3}.xml" -f $xmlFileCount
#En-tête
$output = @"
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
`n
"@
foreach($item in $liste)
{
#Initiation variables booléennes
$MyDateIsCorrect = $true
$MyFileNameIsCorrect = $true
$MyCanalIsCorrect = $true
$MyNumAssureIsCorrect = $true
#Transformations données
$date = $($item.UCB63_DATENUM -split " ")[0]
$renommage = [System.IO.Path]::GetFileNameWithoutExtension($item.U6618_FILENAME)
#Génération output XML
if($MyDateIsCorrect -and $MyFileNameIsCorrect -and $MyCanalIsCorrect -and $MyNumAssureIsCorrect){
$output += @"
<Document>
<Index Nom="TITLE" Valeur="$renommage"/>
<Index Nom="NO_ASSURE" Valeur="$($item.U65B8_IDRP)"/>
<Index Nom="DEBUT_PERIODE" Valeur="$RecupDateFinTraitement"/>
<Index Nom="FIN_PERIODE" Valeur="$RecupDateFin30"/>
<Index $FREQUENCE_DECOMPTE/>
<Index $LIBELLE_ORGANISME/>
<Index $MONTANT_TOTAL/>
<Index Nom="DATE_GENERATION_DECOMPTE"$RecupDateFinTraitement/>
<Index $POLE/>
<Index $CODE_ORGANISME/>
<Index Nom="ALERTE_MAIL" Valeur="$fin"/>
<Fichier Nom="$($item.U6618_FILENAME)"/>
</Document>`r`n
"@
}
}
$output += @"
`r`n</Documents>
"@
$output | Set-Content -Path $xmlFile -Encoding UTF8
$DateErrors.ToArray() | Export-Csv -Path c:\temp\DateErrors.csv -NoTypeInformation
$FileNameErrors.ToArray() | Export-Csv -Path c:\temp\FileNameErrors.csv -NoTypeInformation
$CanalErrors.ToArray() | Export-Csv -Path c:\temp\CanalErrors.csv -NoTypeInformation
$NumAssureErrors.ToArray() | Export-Csv -Path c:\temp\NumAssureErrors.csv -NoTypeInformation
我的输出看起来像这样,但我想在达到 3 个元素后立即创建一个新文件
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
<Document>
<Index Nom="TITLE" Valeur="457E6659_ZN_LIQRLVPR_A_V_ML"/>
<Index Nom="NO_ASSURE" Valeur="1367091"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="457E6659_ZN_LIQRLVPR_A_V_ML.pdf"/>
</Document>
<Document>
<Index Nom="TITLE" Valeur="49453878_ZN_LIQRLVPR_A_V_ML"/>
<Index Nom="NO_ASSURE" Valeur="106440"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="49453878_ZN_LIQRLVPR_A_V_ML.pdf"/>
</Document>
<Document>
<Index Nom="TITLE" Valeur="497E585B_ZN_LIQRLVPR_A_V_CS"/>
<Index Nom="NO_ASSURE" Valeur="1536658"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="497E585B_ZN_LIQRLVPR_A_V_CS.pdf"/>
</Document>
<Document>
<Index Nom="TITLE" Valeur="58453B75_ZN_LIQRLVPR_A_V_ML"/>
<Index Nom="NO_ASSURE" Valeur="1406091"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="58453B75_ZN_LIQRLVPR_A_V_ML.pdf"/>
</Document>
</Documents>
我修改了上次的代码以内置错误控制,因为我相信这就是您将 while
循环更改为 foreach
循环的原因。
下面的代码仍然使用 while 循环,因为对我来说,这样可以更轻松地处理计数器。
我确实更改了项目和文档模板在代码中的插入方式,因为 Here-Strings 往往会破坏代码格式,使其更难阅读。现在它使用 deferred 变量扩展,我借鉴了 .
通过这样做,模板在代码的早期定义而不会中断缩进,并在以后需要时扩展。
我还更改了您捕获可能错误的方式。下面我使用单个 List 对象通过在错误项前添加两个额外的列来捕获所有错误类型和项:ErrorType
和 ErrorDescription
.
$FREQUENCE_DECOMPTE = 'Nom="FREQUENCE_DECOMPTE" Valeur="MENS"'
$LIBELLE_ORGANISME = 'Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"'
$MONTANT_TOTAL = 'Nom="MONTANT_TOTAL" Valeur="0"'
$POLE = 'Nom="POLE" Valeur="1ADP"'
$CODE_ORGANISME = 'Nom="CODE_ORGANISME" Valeur="1ADP"'
# Create two template Here-Strings near the top of the code.
# The first one is a templete for every single item in the XML, the second one
# merges it together as a complete XML document.
# The Here-Strings use SINGLE quotes, so the variables inside are now NOT expanded.
# We'll do that later in the code using $ExecutionContext.InvokeCommand.ExpandString($itemTemplate)
$itemTemplate = @'
<Document>
<Index Nom="TITLE" Valeur="$renommage"/>
<Index Nom="NO_ASSURE" Valeur="$($item.U65B8_IDRP)"/>
<Index Nom="DEBUT_PERIODE" Valeur="$RecupDateFinTraitement"/>
<Index Nom="FIN_PERIODE" Valeur="$RecupDateFin30"/>
<Index $FREQUENCE_DECOMPTE/>
<Index $LIBELLE_ORGANISME/>
<Index $MONTANT_TOTAL/>
<Index Nom="DATE_GENERATION_DECOMPTE" Valeur="$RecupDateFinTraitement"/>
<Index $POLE/>
<Index $CODE_ORGANISME/>
<Index Nom="ALERTE_MAIL" Valeur="$alerte"/>
<Fichier Nom="$($item.U6618_FILENAME)"/>
</Document>
'@
$documentTemplate = @'
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
$($xmlItems -join "`r`n")
</Documents>
'@
# create a list object to capture any errors
$errorList = [System.Collections.Generic.List[object]]::new()
# older PowerShell versions use
# $errorList = New-Object -TypeName System.Collections.Generic.List[object]
# read the csv file
$liste = Import-Csv -path 'C:\temp\testH.csv' -Delimiter ';'
# get the total remaining records to process
$restant = $liste.Count
# set a maximum value of items for each resulting XML file.
# In real life, change this value to 5000
$maxItemsPerXml = 3
# set a xml output file counter and an item index counter
$xmlFileCount = 1
$currentItem = 0
# loop through all items
while ($restant -gt 0) {
$itemCount = [math]::Min($maxItemsPerXml, $restant)
$xmlItems = for ($i = 0; $i -lt $itemCount; $i++) {
$item = $liste[$i + $currentItem]
$errorsFound = $false
# test some of the fields
## UCB63_DATENUM
$date = Get-Date
# if no error, the date variable will be set to the date in this field
if (-not [datetime]::TryParseExact($item.UCB63_DATENUM, 'M/d/yy HH:mm', $null, 'None', [ref]$date)) {
# add an error object to the errorList
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadDate'}},
@{Name = 'ErrorDescription'; Expression = {'UCB63_DATENUM has invalid date format'}}, *))
$errorsFound = $true
}
## U6618_FILENAME
if ([System.IO.Path]::GetExtension($item.U6618_FILENAME) -ne '.pdf'){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadExtension'}},
@{Name = 'ErrorDescription'; Expression = {'U6618_FILENAME not a PDF file'}}, *))
$errorsFound = $true
}
## UF6E8_CANAL
if ([string]::IsNullOrWhiteSpace($item.UF6E8_CANAL)){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'UF6E8_CANAL is empty'}}, *))
$errorsFound = $true
}
## U65B8_IDRP
if ([string]::IsNullOrWhiteSpace($item.U65B8_IDRP)) {
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'U65B8_IDRP is empty'}}, *))
$errorsFound = $true
}
if (!$errorsFound) {
$alerte = if ($item.UF6E8_CANAL -eq "ML") {1} else {0}
$renommage = [System.IO.Path]::GetFileNameWithoutExtension($item.U6618_FILENAME)
$RecupDateFinTraitement = $date.ToString('dd/MM/yyyy')
$RecupDateFin30 = $date.AddDays(30).ToString('dd/MM/yyyy')
# output each item in xml-style by (deferred) expansion of the variables that are now known
$ExecutionContext.InvokeCommand.ExpandString($itemTemplate)
}
else {
# the item had error(s). Increment the $itemCount variable,
# but don't let it grow beyond the $restant number of items!
$itemCount = [math]::Min(($itemCount + 1), $restant)
}
}
# create a complete file path and name for the output xml
$xmlFile = "C:\Temp\MIG_ERELEVE_MM_{0:dd-MM-yyyy}_{1:D3}.xml" -f (Get-Date), $xmlFileCount
# create the XML content, complete with declaration and root node and write it to file
$ExecutionContext.InvokeCommand.ExpandString($documentTemplate) | Set-Content -Path $xmlFile -Encoding UTF8
# increment the xml FILE counter
$xmlFileCount++
# update the csv ITEM counters
$restant -= $itemCount
$currentItem += $itemCount
}
# output the errors encountered if any
if ($errorList.Count) {
$errorList | Export-Csv -Path 'C:\temp\Errors.csv' -Delimiter ';' -NoTypeInformation -Encoding UTF8
}
根据您的观察,PowerShell 4.0 显然不能很好地与 $ExecutionContext.InvokeCommand.ExpandString()
..
配合使用
因此,对于该版本(及更早版本),请改用此版本:
$FREQUENCE_DECOMPTE = 'Nom="FREQUENCE_DECOMPTE" Valeur="MENS"'
$LIBELLE_ORGANISME = 'Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"'
$MONTANT_TOTAL = 'Nom="MONTANT_TOTAL" Valeur="0"'
$POLE = 'Nom="POLE" Valeur="1ADP"'
$CODE_ORGANISME = 'Nom="CODE_ORGANISME" Valeur="1ADP"'
# create a list object to capture any errors
$errorList = New-Object -TypeName System.Collections.Generic.List[object]
$errorList = New-Object -TypeName System.Collections.Generic.List[object]
# read the csv file
$liste = Import-Csv -path 'C:\temp\testH.csv' -Delimiter ';'
# get the total remaining records to process
$restant = $liste.Count
# set a maximum value of items for each resulting XML file.
# In real life, change this value to 5000
$maxItemsPerXml = 3
# set a xml output file counter and an item index counter
$xmlFileCount = 1
$currentItem = 0
# loop through all items
while ($restant -gt 0) {
$itemCount = [math]::Min($maxItemsPerXml, $restant)
$xmlItems = for ($i = 0; $i -lt $itemCount; $i++) {
$item = $liste[$i + $currentItem]
$errorsFound = $false
# test some of the fields
## UCB63_DATENUM
$date = Get-Date
# if no error, the date variable will be set to the date in this field
if (-not [datetime]::TryParseExact($item.UCB63_DATENUM, 'M/d/yy HH:mm', $null, 'None', [ref]$date)) {
# add an error object to the errorList
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadDate'}},
@{Name = 'ErrorDescription'; Expression = {'UCB63_DATENUM has invalid date format'}}, *))
$errorsFound = $true
}
## U6618_FILENAME
if ([System.IO.Path]::GetExtension($item.U6618_FILENAME) -ne '.pdf'){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadExtension'}},
@{Name = 'ErrorDescription'; Expression = {'U6618_FILENAME not a PDF file'}}, *))
$errorsFound = $true
}
## UF6E8_CANAL
if ([string]::IsNullOrWhiteSpace($item.UF6E8_CANAL)){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'UF6E8_CANAL is empty'}}, *))
$errorsFound = $true
}
## U65B8_IDRP
if ([string]::IsNullOrWhiteSpace($item.U65B8_IDRP)) {
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'U65B8_IDRP is empty'}}, *))
$errorsFound = $true
}
if (!$errorsFound) {
$alerte = if ($item.UF6E8_CANAL -eq "ML") {1} else {0}
$renommage = [System.IO.Path]::GetFileNameWithoutExtension($item.U6618_FILENAME)
$RecupDateFinTraitement = $date.ToString('dd/MM/yyyy')
$RecupDateFin30 = $date.AddDays(30).ToString('dd/MM/yyyy')
# output each item in xml-style by (deferred) expansion of the variables that are now known
@"
<Document>
<Index Nom="TITLE" Valeur="$renommage"/>
<Index Nom="NO_ASSURE" Valeur="$($item.U65B8_IDRP)"/>
<Index Nom="DEBUT_PERIODE" Valeur="$RecupDateFinTraitement"/>
<Index Nom="FIN_PERIODE" Valeur="$RecupDateFin30"/>
<Index $FREQUENCE_DECOMPTE/>
<Index $LIBELLE_ORGANISME/>
<Index $MONTANT_TOTAL/>
<Index Nom="DATE_GENERATION_DECOMPTE" Valeur="$RecupDateFinTraitement"/>
<Index $POLE/>
<Index $CODE_ORGANISME/>
<Index Nom="ALERTE_MAIL" Valeur="$alerte"/>
<Fichier Nom="$($item.U6618_FILENAME)"/>
</Document>
"@
}
else {
# the item had error(s). Increment the $itemCount variable,
# but don't let it grow beyond the $restant number of items!
$itemCount = [math]::Min(($itemCount + 1), $restant)
}
}
# create a complete file path and name for the output xml
$xmlFile = "C:\Temp\MIG_ERELEVE_MM_{0:dd-MM-yyyy}_{1:D3}.xml" -f (Get-Date), $xmlFileCount
# create the XML content, complete with declaration and root node and write it to file
@"
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
$($xmlItems -join "`r`n")
</Documents>
"@ | Set-Content -Path $xmlFile -Encoding UTF8
# increment the xml FILE counter
$xmlFileCount++
# update the csv ITEM counters
$restant -= $itemCount
$currentItem += $itemCount
}
# output the errors encountered if any
if ($errorList.Count) {
$errorList | Export-Csv -Path 'C:\temp\Errors.csv' -Delimiter ';' -NoTypeInformation -Encoding UTF8
}
一些解释:
while ($restant -gt 0)
循环比 foreach($item in $liste)
简单得多,因为它会测试是否还有要处理的项目。
$itemCount = [math]::Min($maxItemsPerXml, $restant)
获取您在 $maxItemsPerXml
中设置的项目数,但绝不会超过剩余的项目数。
我们在下一个循环中使用那个 $itemCount
变量 $xmlItems = for ($i = 0; $i -lt $itemCount; $i++)
来迭代这个最大数量的项目,同时,我们捕获变量中循环输出的任何内容$xmlItems
在这个循环中,我们首先对每个项目的每个字段进行一些测试,如果测试失败,我们会在变量 $errorList
中报告。如果一个项目没有通过测试,它会从 XML 输出中被忽略,所以我们需要用 $itemCount = [math]::Min(($itemCount + 1), $restant)
调整变量 $itemCount
。
同样,我们使用 [math]::Min() 来确保我们永远不会超出剩余的项目数。
如果所有测试都通过,则该项目输出为XML <Document>..</Document>
节点并收集到$xmlItems
然后,如果我们完成了 for ($i = 0; $i -lt $itemCount; $i++)
循环,我们最多收集了 $maxItemsPerXml
xml 个节点,我们需要保存 XML .
保存后,我们需要在重新进入while循环之前调整各种计数器:
- 下一个文件的文件计数器增加
$xmlFileCount++
- 剩余项目数调整为
$restant -= $itemCount
- 索引号
$currentItem
设置为总数组中的下一个值 $currentItem += $itemCount
最后,我们检查 $errorList
中是否有任何内容,如果有,我们写一个 CSV 文件 C:\temp\Errors.csv
,其中包含我们发现的所有错误
全部完成!
你能帮我实现一个计数器,以便生成一个 xml 文件,其中包含来自 csv 的多个元素吗?
这是csv文件
UCB63_DATENUM;U6618_FILENAME;UF6E8_CANAL;U65B8_IDRP
7/8/19 22:27;457E6659_ZN_LIQRLVPR_A_V_ML.pdf;ML;1367091
9/11/19 23:03;49453878_ZN_LIQRLVPR_A_V_ML.pdf;ML;106440
9/24/19 21:04;497E585B_ZN_LIQRLVPR_A_V_CS.pdf;CS;1536658
2/12/20 22:12;58453B75_ZN_LIQRLVPR_A_V_ML.pdf;ML;1406091
和代码
我在屏幕上的 return 很好,但由于我没有调用该值,因此无法递增。 目前我尝试过的所有事情都有一个坏问题(只有最后一个结果似乎每隔一个就会崩溃)
请帮帮我
#vARIABLES EN DUR
$FREQUENCE_DECOMPTE = 'Nom="FREQUENCE_DECOMPTE" Valeur="MENS"'
$LIBELLE_ORGANISME = 'Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"'
$MONTANT_TOTAL = 'Nom="MONTANT_TOTAL" Valeur="0"'
$POLE = 'Nom="POLE" Valeur="1ADP"'
$CODE_ORGANISME = 'Nom="CODE_ORGANISME" Valeur="1ADP"'
# Paramètre nombre item par xml VALEUR A MODIFIER A 5000
$maxItemsPerXml = 3
# Nombre de process restants
$restant = $liste.Count
# Paramétrage compteur
#Import du csv et création des différentes collections
$liste = Import-Csv -path 'c:\temp\testH.csv' -Delimiter ';'
[System.Collections.ArrayList] $DateErrors = @()
[System.Collections.ArrayList] $FileNameErrors = @()
[System.Collections.ArrayList] $CanalErrors = @()
[System.Collections.ArrayList] $NumAssureErrors = @()
#création fichier
$xmlFile = "C:\Temp\MIG_ERELEVE_MM_$(get-date -f dd-MM-yyyy)_{0:D3}.xml" -f $xmlFileCount
#En-tête
$output = @"
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
`n
"@
foreach($item in $liste)
{
#Initiation variables booléennes
$MyDateIsCorrect = $true
$MyFileNameIsCorrect = $true
$MyCanalIsCorrect = $true
$MyNumAssureIsCorrect = $true
#Transformations données
$date = $($item.UCB63_DATENUM -split " ")[0]
$renommage = [System.IO.Path]::GetFileNameWithoutExtension($item.U6618_FILENAME)
#Génération output XML
if($MyDateIsCorrect -and $MyFileNameIsCorrect -and $MyCanalIsCorrect -and $MyNumAssureIsCorrect){
$output += @"
<Document>
<Index Nom="TITLE" Valeur="$renommage"/>
<Index Nom="NO_ASSURE" Valeur="$($item.U65B8_IDRP)"/>
<Index Nom="DEBUT_PERIODE" Valeur="$RecupDateFinTraitement"/>
<Index Nom="FIN_PERIODE" Valeur="$RecupDateFin30"/>
<Index $FREQUENCE_DECOMPTE/>
<Index $LIBELLE_ORGANISME/>
<Index $MONTANT_TOTAL/>
<Index Nom="DATE_GENERATION_DECOMPTE"$RecupDateFinTraitement/>
<Index $POLE/>
<Index $CODE_ORGANISME/>
<Index Nom="ALERTE_MAIL" Valeur="$fin"/>
<Fichier Nom="$($item.U6618_FILENAME)"/>
</Document>`r`n
"@
}
}
$output += @"
`r`n</Documents>
"@
$output | Set-Content -Path $xmlFile -Encoding UTF8
$DateErrors.ToArray() | Export-Csv -Path c:\temp\DateErrors.csv -NoTypeInformation
$FileNameErrors.ToArray() | Export-Csv -Path c:\temp\FileNameErrors.csv -NoTypeInformation
$CanalErrors.ToArray() | Export-Csv -Path c:\temp\CanalErrors.csv -NoTypeInformation
$NumAssureErrors.ToArray() | Export-Csv -Path c:\temp\NumAssureErrors.csv -NoTypeInformation
我的输出看起来像这样,但我想在达到 3 个元素后立即创建一个新文件
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
<Document>
<Index Nom="TITLE" Valeur="457E6659_ZN_LIQRLVPR_A_V_ML"/>
<Index Nom="NO_ASSURE" Valeur="1367091"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="457E6659_ZN_LIQRLVPR_A_V_ML.pdf"/>
</Document>
<Document>
<Index Nom="TITLE" Valeur="49453878_ZN_LIQRLVPR_A_V_ML"/>
<Index Nom="NO_ASSURE" Valeur="106440"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="49453878_ZN_LIQRLVPR_A_V_ML.pdf"/>
</Document>
<Document>
<Index Nom="TITLE" Valeur="497E585B_ZN_LIQRLVPR_A_V_CS"/>
<Index Nom="NO_ASSURE" Valeur="1536658"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="497E585B_ZN_LIQRLVPR_A_V_CS.pdf"/>
</Document>
<Document>
<Index Nom="TITLE" Valeur="58453B75_ZN_LIQRLVPR_A_V_ML"/>
<Index Nom="NO_ASSURE" Valeur="1406091"/>
<Index Nom="DEBUT_PERIODE" Valeur="09-07-2020"/>
<Index Nom="FIN_PERIODE" Valeur="08/08/2020"/>
<Index Nom="FREQUENCE_DECOMPTE" Valeur="MENS"/>
<Index Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"/>
<Index Nom="MONTANT_TOTAL" Valeur="0"/>
<Index Nom="DATE_GENERATION_DECOMPTE"09-07-2020/>
<Index Nom="POLE" Valeur="1ADP"/>
<Index Nom="CODE_ORGANISME" Valeur="1ADP"/>
<Index Nom="ALERTE_MAIL" Valeur="1"/>
<Fichier Nom="58453B75_ZN_LIQRLVPR_A_V_ML.pdf"/>
</Document>
</Documents>
我修改了上次的代码以内置错误控制,因为我相信这就是您将 while
循环更改为 foreach
循环的原因。
下面的代码仍然使用 while 循环,因为对我来说,这样可以更轻松地处理计数器。
我确实更改了项目和文档模板在代码中的插入方式,因为 Here-Strings 往往会破坏代码格式,使其更难阅读。现在它使用 deferred 变量扩展,我借鉴了
通过这样做,模板在代码的早期定义而不会中断缩进,并在以后需要时扩展。
我还更改了您捕获可能错误的方式。下面我使用单个 List 对象通过在错误项前添加两个额外的列来捕获所有错误类型和项:ErrorType
和 ErrorDescription
.
$FREQUENCE_DECOMPTE = 'Nom="FREQUENCE_DECOMPTE" Valeur="MENS"'
$LIBELLE_ORGANISME = 'Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"'
$MONTANT_TOTAL = 'Nom="MONTANT_TOTAL" Valeur="0"'
$POLE = 'Nom="POLE" Valeur="1ADP"'
$CODE_ORGANISME = 'Nom="CODE_ORGANISME" Valeur="1ADP"'
# Create two template Here-Strings near the top of the code.
# The first one is a templete for every single item in the XML, the second one
# merges it together as a complete XML document.
# The Here-Strings use SINGLE quotes, so the variables inside are now NOT expanded.
# We'll do that later in the code using $ExecutionContext.InvokeCommand.ExpandString($itemTemplate)
$itemTemplate = @'
<Document>
<Index Nom="TITLE" Valeur="$renommage"/>
<Index Nom="NO_ASSURE" Valeur="$($item.U65B8_IDRP)"/>
<Index Nom="DEBUT_PERIODE" Valeur="$RecupDateFinTraitement"/>
<Index Nom="FIN_PERIODE" Valeur="$RecupDateFin30"/>
<Index $FREQUENCE_DECOMPTE/>
<Index $LIBELLE_ORGANISME/>
<Index $MONTANT_TOTAL/>
<Index Nom="DATE_GENERATION_DECOMPTE" Valeur="$RecupDateFinTraitement"/>
<Index $POLE/>
<Index $CODE_ORGANISME/>
<Index Nom="ALERTE_MAIL" Valeur="$alerte"/>
<Fichier Nom="$($item.U6618_FILENAME)"/>
</Document>
'@
$documentTemplate = @'
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
$($xmlItems -join "`r`n")
</Documents>
'@
# create a list object to capture any errors
$errorList = [System.Collections.Generic.List[object]]::new()
# older PowerShell versions use
# $errorList = New-Object -TypeName System.Collections.Generic.List[object]
# read the csv file
$liste = Import-Csv -path 'C:\temp\testH.csv' -Delimiter ';'
# get the total remaining records to process
$restant = $liste.Count
# set a maximum value of items for each resulting XML file.
# In real life, change this value to 5000
$maxItemsPerXml = 3
# set a xml output file counter and an item index counter
$xmlFileCount = 1
$currentItem = 0
# loop through all items
while ($restant -gt 0) {
$itemCount = [math]::Min($maxItemsPerXml, $restant)
$xmlItems = for ($i = 0; $i -lt $itemCount; $i++) {
$item = $liste[$i + $currentItem]
$errorsFound = $false
# test some of the fields
## UCB63_DATENUM
$date = Get-Date
# if no error, the date variable will be set to the date in this field
if (-not [datetime]::TryParseExact($item.UCB63_DATENUM, 'M/d/yy HH:mm', $null, 'None', [ref]$date)) {
# add an error object to the errorList
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadDate'}},
@{Name = 'ErrorDescription'; Expression = {'UCB63_DATENUM has invalid date format'}}, *))
$errorsFound = $true
}
## U6618_FILENAME
if ([System.IO.Path]::GetExtension($item.U6618_FILENAME) -ne '.pdf'){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadExtension'}},
@{Name = 'ErrorDescription'; Expression = {'U6618_FILENAME not a PDF file'}}, *))
$errorsFound = $true
}
## UF6E8_CANAL
if ([string]::IsNullOrWhiteSpace($item.UF6E8_CANAL)){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'UF6E8_CANAL is empty'}}, *))
$errorsFound = $true
}
## U65B8_IDRP
if ([string]::IsNullOrWhiteSpace($item.U65B8_IDRP)) {
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'U65B8_IDRP is empty'}}, *))
$errorsFound = $true
}
if (!$errorsFound) {
$alerte = if ($item.UF6E8_CANAL -eq "ML") {1} else {0}
$renommage = [System.IO.Path]::GetFileNameWithoutExtension($item.U6618_FILENAME)
$RecupDateFinTraitement = $date.ToString('dd/MM/yyyy')
$RecupDateFin30 = $date.AddDays(30).ToString('dd/MM/yyyy')
# output each item in xml-style by (deferred) expansion of the variables that are now known
$ExecutionContext.InvokeCommand.ExpandString($itemTemplate)
}
else {
# the item had error(s). Increment the $itemCount variable,
# but don't let it grow beyond the $restant number of items!
$itemCount = [math]::Min(($itemCount + 1), $restant)
}
}
# create a complete file path and name for the output xml
$xmlFile = "C:\Temp\MIG_ERELEVE_MM_{0:dd-MM-yyyy}_{1:D3}.xml" -f (Get-Date), $xmlFileCount
# create the XML content, complete with declaration and root node and write it to file
$ExecutionContext.InvokeCommand.ExpandString($documentTemplate) | Set-Content -Path $xmlFile -Encoding UTF8
# increment the xml FILE counter
$xmlFileCount++
# update the csv ITEM counters
$restant -= $itemCount
$currentItem += $itemCount
}
# output the errors encountered if any
if ($errorList.Count) {
$errorList | Export-Csv -Path 'C:\temp\Errors.csv' -Delimiter ';' -NoTypeInformation -Encoding UTF8
}
根据您的观察,PowerShell 4.0 显然不能很好地与 $ExecutionContext.InvokeCommand.ExpandString()
..
配合使用
因此,对于该版本(及更早版本),请改用此版本:
$FREQUENCE_DECOMPTE = 'Nom="FREQUENCE_DECOMPTE" Valeur="MENS"'
$LIBELLE_ORGANISME = 'Nom="LIBELLE_ORGANISME" Valeur="HUMANIS CCN OG"'
$MONTANT_TOTAL = 'Nom="MONTANT_TOTAL" Valeur="0"'
$POLE = 'Nom="POLE" Valeur="1ADP"'
$CODE_ORGANISME = 'Nom="CODE_ORGANISME" Valeur="1ADP"'
# create a list object to capture any errors
$errorList = New-Object -TypeName System.Collections.Generic.List[object]
$errorList = New-Object -TypeName System.Collections.Generic.List[object]
# read the csv file
$liste = Import-Csv -path 'C:\temp\testH.csv' -Delimiter ';'
# get the total remaining records to process
$restant = $liste.Count
# set a maximum value of items for each resulting XML file.
# In real life, change this value to 5000
$maxItemsPerXml = 3
# set a xml output file counter and an item index counter
$xmlFileCount = 1
$currentItem = 0
# loop through all items
while ($restant -gt 0) {
$itemCount = [math]::Min($maxItemsPerXml, $restant)
$xmlItems = for ($i = 0; $i -lt $itemCount; $i++) {
$item = $liste[$i + $currentItem]
$errorsFound = $false
# test some of the fields
## UCB63_DATENUM
$date = Get-Date
# if no error, the date variable will be set to the date in this field
if (-not [datetime]::TryParseExact($item.UCB63_DATENUM, 'M/d/yy HH:mm', $null, 'None', [ref]$date)) {
# add an error object to the errorList
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadDate'}},
@{Name = 'ErrorDescription'; Expression = {'UCB63_DATENUM has invalid date format'}}, *))
$errorsFound = $true
}
## U6618_FILENAME
if ([System.IO.Path]::GetExtension($item.U6618_FILENAME) -ne '.pdf'){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'BadExtension'}},
@{Name = 'ErrorDescription'; Expression = {'U6618_FILENAME not a PDF file'}}, *))
$errorsFound = $true
}
## UF6E8_CANAL
if ([string]::IsNullOrWhiteSpace($item.UF6E8_CANAL)){
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'UF6E8_CANAL is empty'}}, *))
$errorsFound = $true
}
## U65B8_IDRP
if ([string]::IsNullOrWhiteSpace($item.U65B8_IDRP)) {
[void]$errorList.Add(($item | Select-Object @{Name = 'ErrorType'; Expression = {'EmptyField'}},
@{Name = 'ErrorDescription'; Expression = {'U65B8_IDRP is empty'}}, *))
$errorsFound = $true
}
if (!$errorsFound) {
$alerte = if ($item.UF6E8_CANAL -eq "ML") {1} else {0}
$renommage = [System.IO.Path]::GetFileNameWithoutExtension($item.U6618_FILENAME)
$RecupDateFinTraitement = $date.ToString('dd/MM/yyyy')
$RecupDateFin30 = $date.AddDays(30).ToString('dd/MM/yyyy')
# output each item in xml-style by (deferred) expansion of the variables that are now known
@"
<Document>
<Index Nom="TITLE" Valeur="$renommage"/>
<Index Nom="NO_ASSURE" Valeur="$($item.U65B8_IDRP)"/>
<Index Nom="DEBUT_PERIODE" Valeur="$RecupDateFinTraitement"/>
<Index Nom="FIN_PERIODE" Valeur="$RecupDateFin30"/>
<Index $FREQUENCE_DECOMPTE/>
<Index $LIBELLE_ORGANISME/>
<Index $MONTANT_TOTAL/>
<Index Nom="DATE_GENERATION_DECOMPTE" Valeur="$RecupDateFinTraitement"/>
<Index $POLE/>
<Index $CODE_ORGANISME/>
<Index Nom="ALERTE_MAIL" Valeur="$alerte"/>
<Fichier Nom="$($item.U6618_FILENAME)"/>
</Document>
"@
}
else {
# the item had error(s). Increment the $itemCount variable,
# but don't let it grow beyond the $restant number of items!
$itemCount = [math]::Min(($itemCount + 1), $restant)
}
}
# create a complete file path and name for the output xml
$xmlFile = "C:\Temp\MIG_ERELEVE_MM_{0:dd-MM-yyyy}_{1:D3}.xml" -f (Get-Date), $xmlFileCount
# create the XML content, complete with declaration and root node and write it to file
@"
<?xml version="1.0" encoding="utf-8"?>
<Documents Origine="ERELEVE_HUM">
$($xmlItems -join "`r`n")
</Documents>
"@ | Set-Content -Path $xmlFile -Encoding UTF8
# increment the xml FILE counter
$xmlFileCount++
# update the csv ITEM counters
$restant -= $itemCount
$currentItem += $itemCount
}
# output the errors encountered if any
if ($errorList.Count) {
$errorList | Export-Csv -Path 'C:\temp\Errors.csv' -Delimiter ';' -NoTypeInformation -Encoding UTF8
}
一些解释:
while ($restant -gt 0)
循环比 foreach($item in $liste)
简单得多,因为它会测试是否还有要处理的项目。
$itemCount = [math]::Min($maxItemsPerXml, $restant)
获取您在$maxItemsPerXml
中设置的项目数,但绝不会超过剩余的项目数。我们在下一个循环中使用那个
$itemCount
变量$xmlItems = for ($i = 0; $i -lt $itemCount; $i++)
来迭代这个最大数量的项目,同时,我们捕获变量中循环输出的任何内容$xmlItems
在这个循环中,我们首先对每个项目的每个字段进行一些测试,如果测试失败,我们会在变量
$errorList
中报告。如果一个项目没有通过测试,它会从 XML 输出中被忽略,所以我们需要用$itemCount = [math]::Min(($itemCount + 1), $restant)
调整变量$itemCount
。 同样,我们使用 [math]::Min() 来确保我们永远不会超出剩余的项目数。如果所有测试都通过,则该项目输出为XML
<Document>..</Document>
节点并收集到$xmlItems
然后,如果我们完成了
for ($i = 0; $i -lt $itemCount; $i++)
循环,我们最多收集了$maxItemsPerXml
xml 个节点,我们需要保存 XML .保存后,我们需要在重新进入while循环之前调整各种计数器:
- 下一个文件的文件计数器增加
$xmlFileCount++
- 剩余项目数调整为
$restant -= $itemCount
- 索引号
$currentItem
设置为总数组中的下一个值$currentItem += $itemCount
- 下一个文件的文件计数器增加
最后,我们检查
$errorList
中是否有任何内容,如果有,我们写一个 CSV 文件C:\temp\Errors.csv
,其中包含我们发现的所有错误
全部完成!