Я использую Powershell для проверки нескольких файлов XML на наличие нескольких XSD;эта часть кода работает, как и ожидалось, однако мне также нужно переместить любой XML, который не удается проверить, в папку «Invalid».Я пытаюсь перебрать эти файлы с помощью ForEach, а затем - с помощью оператора If - переместить любой файл с ошибкой.Моя проблема в том, что все файлы перемещаются, независимо от того, ошиблись они или нет.
Я написал этот цикл так много разных способов, как только мог представить, но я не получаю ожидаемого результата.(Я также искал в Интернете несколько дней, чтобы найти ответ.) Мне нужно, чтобы ForEach применял код к каждому файлу по одному.Это проблема с моим синтаксисом?Возможно, я упускаю что-то очень очевидное, но сейчас я в растерянности.
Я использую эту функцию (найденную в Stack Overflow и, как показано здесь, слегка подправленную) для проверки XML.
function Test-XmlFile
{
<#
.Synopsis
Validates an xml file against an xml schema file.
.Example
PS> dir *.xml | Test-XmlFile schema.xsd
#>
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline=$true, Mandatory=$true)]
[SupportsWildcards()]
$SchemaFile,
[Parameter(ValueFromPipeline=$true, Mandatory=$true)]
[SupportsWildcards()]
[alias('Fullname')]
$XmlFile,
[scriptblock] $ValidationEventHandler = { Write-Error $args[1].Exception }
)
begin {
$schemaReader = New-Object System.Xml.XmlTextReader $SchemaFile
$schema = [System.Xml.Schema.XmlSchema]::Read($schemaReader, $ValidationEventHandler)
}
process {
$ret = $true
try {
$xml = New-Object System.Xml.XmlDocument
$xml.Schemas.Add($schema) | Out-Null
$xml.Load($XmlFile)
$xml.Validate({
throw ([PsCustomObject] @{
SchemaFile = $SchemaFile
XmlFile = $XmlFile
Exception = $args[1].Exception
})
})
} catch {
Write-Error $_
$ret = $false
}
$ret
}
end {
$schemaReader.Close()
}
}
А вот как я выбираю XML для проверки на соответствие их заданным схемам.
$allfiles = "..\Schema Validation\XMLs\*.xml"
$xml1 = Get-ChildItem $allfiles -Recurse | Select-String "<UniqueElement>" -List | Resolve-Path
$xml2 = Get-ChildItem $allfiles -Recurse | Select-String "<UniqueElement>" -List | Resolve-Path
$xsd1 = "..\Schema Validation\Schemas\Schema1.xsd"
$xsd2 = "..\Schema Validation\Schemas\Schema2.xsd"
А вот цикл ForEach, который у меня не работает.(В его текущей конфигурации, хотя я написал это дюжиной различных способов.)
ForEach ($xml in $xml1) {
$xml | Test-XmlFile $xsd1
If ($Error) {
$Error[0].Exception, "`r" | Out-File "..\Schema Validation\Results\log.txt"
Move-Item $xml -Destination "..\Schema Validation\Invalid"
}}
Приведенный выше цикл ForEach также повторяется для переменных $ xml2 и $ xsd2.(И, как вы можете видеть из Out-File, я также записываю сообщение об исключении в текстовый файл для своего рода журнала.)
Я ожидал, что только те XML-файлы, в которых произошла ошибка и возникнет исключение, будутпереместился из-за оператора If ($ Error) и того факта, что я пытаюсь перебирать файлы по одному;однако происходит то, что любой XML, который содержит уникальную строку, которая идентифицирует его как часть группы $ xml1 или $ xml2, перемещается в папку Invalid, ошибка или нет ошибки.Так что же до боли очевидная вещь, которую я пропускаю ??(Между прочим, текст исключения заполняет журнал ошибок, как и ожидалось, поэтому, по крайней мере, эта часть работает, как я надеялся.)
РЕДАКТИРОВАТЬ: Если подумать, я не должен говорить, что текст исключения заполняет журнал "как и ожидалось".Он заполняет журнал, но записывает сообщение в файл журнала один раз для каждого файла, включенного в переменную (например, для каждого файла в $ xml1), независимо от того, был ли файл действительно ошибочным.Таким образом, если в $ xml1 есть два файла, но только один является недействительным, сообщение об одном исключении для этого одного недопустимого файла будет записано в журнал дважды.Так что он пишет что-то для каждого зацикленного файла, независимо от правильности или ошибок.Надеюсь, что это имеет смысл.