作爲我的開發的一部分,我希望能夠針對單個XSD文件驗證整個文件夾的XML文件的價值。一個PowerShell函數似乎是一個很好的候選人,因爲我可以像這樣管理一個文件列表:dir * .xml | Validate-Xml -Schema。\ MySchema.xsd如何使用PowerShell根據XSD驗證XML文件?
我考慮從Validating an Xml against Referenced XSD in C#問題移植C#代碼,但我不知道如何在PowerShell中添加處理程序。
作爲我的開發的一部分,我希望能夠針對單個XSD文件驗證整個文件夾的XML文件的價值。一個PowerShell函數似乎是一個很好的候選人,因爲我可以像這樣管理一個文件列表:dir * .xml | Validate-Xml -Schema。\ MySchema.xsd如何使用PowerShell根據XSD驗證XML文件?
我考慮從Validating an Xml against Referenced XSD in C#問題移植C#代碼,但我不知道如何在PowerShell中添加處理程序。
我寫一個PowerShell功能做到這一點:
用法:
DIR * .XML |測試的XML -schema「 \ MySchemaFile.xsd」 - 命名‘http://tempuri.org’
代碼:
function Test-Xml {
param(
$InputObject = $null,
$Namespace = $null,
$SchemaFile = $null
)
BEGIN {
$failCount = 0
$failureMessages = ""
$fileName = ""
}
PROCESS {
if ($InputObject -and $_) {
throw 'ParameterBinderStrings\AmbiguousParameterSet'
break
} elseif ($InputObject) {
$InputObject
} elseif ($_) {
$fileName = $_.FullName
$readerSettings = New-Object -TypeName System.Xml.XmlReaderSettings
$readerSettings.ValidationType = [System.Xml.ValidationType]::Schema
$readerSettings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessInlineSchema -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ProcessSchemaLocation -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings
$readerSettings.Schemas.Add($Namespace, $SchemaFile) | Out-Null
$readerSettings.add_ValidationEventHandler(
{
$failureMessages = $failureMessages + [System.Environment]::NewLine + $fileName + " - " + $_.Message
$failCount = $failCount + 1
});
$reader = [System.Xml.XmlReader]::Create($_, $readerSettings)
while ($reader.Read()) { }
$reader.Close()
} else {
throw 'ParameterBinderStrings\InputObjectNotBound'
}
}
END {
$failureMessages
"$failCount validation errors were found"
}
}
該腳本有錯誤。它沒有用於該功能的右大括號。 – OnesimusUnbound 2010-01-18 08:08:18
''閱讀器'應該在while循環後關閉。否則,在Finalizer-saftey-net啓動之前,您將無法編輯該文件。 – 2010-09-01 11:11:51
這似乎不起作用:PS D:\ projects \ svcs> dir * .xml | Test-Xml 術語'Test-Xml'不被識別爲cmdlet,函數,腳本文件或可操作程序的名稱。 – Chloe 2012-07-06 15:52:15
PowerShell Community Extensions有一個Test-Xml cmdlet。唯一的缺點是這些擴展沒有被更新一段時間,但是大多數擴展都在最新版本的PowerShell(包括Test-Xml)上工作。只要做一個Get-Childitem's並將該列表傳遞給一個foreach,每個調用Test-Xml。
v1.2已發佈,以支持PowerShell的v2版本。他們似乎都工作得很好,所以我不確定是否有任何缺點。 – 2010-01-21 03:25:54
我創建了可與聯架構參考XML的文件執行XSD驗證一個單獨的PowerShell文件。工作得很好。下載和howto可用於https://knowledge.zomers.eu/PowerShell/Pages/How-to-validate-XML-against-an-XSD-schema-using-PowerShell.aspx
我想評論說,在當前接受的答案中的腳本不驗證關於xs:sequence
元素的錯誤順序的錯誤。例如: 的test.xml
<addresses xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation='test.xsd'>
<address>
<street>Baker street 5</street>
<name>Joe Tester</name>
</address>
</addresses>
test.xsd
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>
<xs:element name="addresses">
<xs:complexType>
<xs:sequence>
<xs:element ref="address" minOccurs='1' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element ref="name" minOccurs='0' maxOccurs='1'/>
<xs:element ref="street" minOccurs='0' maxOccurs='1'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="name" type='xs:string'/>
<xs:element name="street" type='xs:string'/>
</xs:schema>
我寫了另一個版本,可以將此錯誤報告:
function Test-XmlFile
{
<#
.Synopsis
Validates an xml file against an xml schema file.
.Example
PS> dir *.xml | Test-XmlFile schema.xsd
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string] $SchemaFile,
[Parameter(ValueFromPipeline=$true, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
[alias('Fullname')]
[string] $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()
}
}
PS C:\ TEMP \實驗室的XML驗證> dir test.xml |試驗XMLFILE test.xsd
System.Xml.Schema.XmlSchemaValidationException: The element 'address' has invalid child element 'name'.
...
我使用這個簡單的代碼片段,總是工作,你並不需要複雜的功能。它這個例子中我加載XML配置與稍後用於部署和服務器配置數據:
# You probably don't need this, it's just my way
$script:Context = New-Object -TypeName System.Management.Automation.PSObject
Add-Member -InputObject $Context -MemberType NoteProperty -Name Configuration -Value ""
$ConfigurationPath = $(Join-Path -Path $PWD -ChildPath "Configuration")
# Load xml and its schema
$Context.Configuration = [xml](Get-Content -LiteralPath $(Join-Path -Path $ConfigurationPath -ChildPath "Configuration.xml"))
$Context.Configuration.Schemas.Add($null, $(Join-Path -Path $ConfigurationPath -ChildPath "Configuration.xsd")) | Out-Null
# Validate xml against schema
$Context.Configuration.Validate(
{
Write-Host "ERROR: The Configuration-File Configuration.xml is not valid. $($_.Message)" -ForegroundColor Red
exit 1
})
這是最簡單的(因此通常是最好的)解決方案。唯一的問題是它不適用於具有非空字符串的目標名稱空間的模式。要處理這種情況,您必須單獨加載XmlSchema對象。 – ssamuel 2013-05-28 23:45:23
(Flatliner DOA)的解決方案是工作好上PSV2,但不能在Server 2012的PSv3。
(wangzq)的解決方案正在PS2和PS3上工作!
人誰需要對PS3的XML驗證,可以使用這個(基於wangzq的功能)
function Test-Xml {
param (
[Parameter(ValueFromPipeline=$true, Mandatory=$true)]
[string] $XmlFile,
[Parameter(Mandatory=$true)]
[string] $SchemaFile
)
[string[]]$Script:XmlValidationErrorLog = @()
[scriptblock] $ValidationEventHandler = {
$Script:XmlValidationErrorLog += $args[1].Exception.Message
}
$xml = New-Object System.Xml.XmlDocument
$schemaReader = New-Object System.Xml.XmlTextReader $SchemaFile
$schema = [System.Xml.Schema.XmlSchema]::Read($schemaReader, $ValidationEventHandler)
$xml.Schemas.Add($schema) | Out-Null
$xml.Load($XmlFile)
$xml.Validate($ValidationEventHandler)
if ($Script:XmlValidationErrorLog) {
Write-Warning "$($Script:XmlValidationErrorLog.Count) errors found"
Write-Error "$Script:XmlValidationErrorLog"
}
else {
Write-Host "The script is valid"
}
}
Test-Xml -XmlFile $XmlFile -SchemaFile $SchemaFile
我重新寫了(我知道壞習慣中),但@Flatliner_DOA啓動腳本太很好完全丟棄。
function Test-Xml {
[cmdletbinding()]
param(
[parameter(mandatory=$true)]$InputFile,
$Namespace = $null,
[parameter(mandatory=$true)]$SchemaFile
)
BEGIN {
$failCount = 0
$failureMessages = ""
$fileName = ""
}
PROCESS {
if ($inputfile)
{
write-verbose "input file: $inputfile"
write-verbose "schemafile: $SchemaFile"
$fileName = (resolve-path $inputfile).path
if (-not (test-path $SchemaFile)) {throw "schemafile not found $schemafile"}
$readerSettings = New-Object -TypeName System.Xml.XmlReaderSettings
$readerSettings.ValidationType = [System.Xml.ValidationType]::Schema
$readerSettings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessIdentityConstraints -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ProcessSchemaLocation -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings
$readerSettings.Schemas.Add($Namespace, $SchemaFile) | Out-Null
$readerSettings.add_ValidationEventHandler(
{
try {
$detail = $_.Message
$detail += "`n" + "On Line: $($_.exception.linenumber) Offset: $($_.exception.lineposition)"
} catch {}
$failureMessages += $detail
$failCount = $failCount + 1
});
try {
$reader = [System.Xml.XmlReader]::Create($fileName, $readerSettings)
while ($reader.Read()) { }
}
#handler to ensure we always close the reader sicne it locks files
finally {
$reader.Close()
}
} else {
throw 'no input file'
}
}
END {
if ($failureMessages)
{ $failureMessages}
write-verbose "$failCount validation errors were found"
}
}
#example calling/useage code follows:
$erroractionpreference = 'stop'
Set-strictmode -version 2
$valid = @(Test-Xml -inputfile $inputfile -schemafile $XSDPath)
write-host "Found ($($valid.count)) errors"
if ($valid.count) {
$valid |write-host -foregroundcolor red
}
功能不再管道作爲替代使用文件路徑,這是一個複雜這個用例並不需要。隨意破解開始/進程/結束處理程序。
我意識到這是一個老問題,但我嘗試了所提供的答案,無法讓他們在Powershell中成功運行。
我已經創建了以下使用此處描述的一些技術的函數。我發現它非常可靠。
我不得不在不同時間驗證XML文檔,但是我總是發現行號爲0.看來XmlSchemaException.LineNumber
只會在加載文檔時可用。
如果你這樣做以後使用Validate()
方法上XmlDocument
驗證則LineNumber上/ LinePosition將始終爲0
相反,你應該做的驗證,同時使用XmlReader
並添加驗證事件處理程序腳本塊讀。
Function Test-Xml()
{
[CmdletBinding(PositionalBinding=$false)]
param (
[Parameter(ValueFromPipeline=$true, Mandatory=$true)]
[string] [ValidateScript({Test-Path -Path $_})] $Path,
[Parameter(Mandatory=$true)]
[string] [ValidateScript({Test-Path -Path $_})] $SchemaFilePath,
[Parameter(Mandatory=$false)]
$Namespace = $null
)
[string[]]$Script:XmlValidationErrorLog = @()
[scriptblock] $ValidationEventHandler = {
$Script:XmlValidationErrorLog += "`n" + "Line: $($_.Exception.LineNumber) Offset: $($_.Exception.LinePosition) - $($_.Message)"
}
$readerSettings = New-Object -TypeName System.Xml.XmlReaderSettings
$readerSettings.ValidationType = [System.Xml.ValidationType]::Schema
$readerSettings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessIdentityConstraints -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ProcessSchemaLocation -bor
[System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings
$readerSettings.Schemas.Add($Namespace, $SchemaFilePath) | Out-Null
$readerSettings.add_ValidationEventHandler($ValidationEventHandler)
try
{
$reader = [System.Xml.XmlReader]::Create($Path, $readerSettings)
while ($reader.Read()) { }
}
#handler to ensure we always close the reader sicne it locks files
finally
{
$reader.Close()
}
if ($Script:XmlValidationErrorLog)
{
[string[]]$ValidationErrors = $Script:XmlValidationErrorLog
Write-Warning "Xml file ""$Path"" is NOT valid according to schema ""$SchemaFilePath"""
Write-Warning "$($Script:XmlValidationErrorLog.Count) errors found"
}
else
{
Write-Host "Xml file ""$Path"" is valid according to schema ""$SchemaFilePath"""
}
Return ,$ValidationErrors #The comma prevents powershell from unravelling the collection http://bit.ly/1fcZovr
}
爲什麼你需要它是PowerShell只是因爲你正在閱讀標準輸入文件列表? – 2009-05-05 02:25:08
我希望能夠輕鬆地將其集成到自動構建腳本中。不想編譯一個應用程序只是爲了做到這一點。一個PowerShell腳本似乎很適合這種事情。擴展的 – 2009-05-05 03:33:17