How do I use PowerShell to Validate XML files against an XSD?

前端 未结 8 1873
小鲜肉
小鲜肉 2020-12-05 02:26

As a part of my development I\'d like to be able to validate an entire folder\'s worth of XML files against a single XSD file. A PowerShell function seems like a good candid

相关标签:
8条回答
  • 2020-12-05 03:00

    I have created a separate PowerShell file which can perform XSD validation on XML files with an inline schema reference. Works really well. Download and howto are available on https://knowledge.zomers.eu/PowerShell/Pages/How-to-validate-XML-against-an-XSD-schema-using-PowerShell.aspx

    0 讨论(0)
  • 2020-12-05 03:01

    I am using this simple snippet, always works and you don't need complicated functions. It this example I am loading configuration xml with data which are used later for deployment and server configuration:

    # 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
        })
    
    0 讨论(0)
  • 2020-12-05 03:06

    the solution of (Flatliner DOA) is working good on PSv2, but not on Server 2012 PSv3.

    the solution of (wangzq) is working on PS2 and PS3!!

    anyone who needs an xml validation on PS3, can use this (based on wangzq's function)

    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
    
    0 讨论(0)
  • 2020-12-05 03:12

    I want to comment that the script in current accepted answer doesn't validate errors about incorrect orders of elements of xs:sequence. For example: 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>
    

    I wrote another version that can report this error:

    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\lab-xml-validation> dir test.xml | Test-XmlFile test.xsd

    System.Xml.Schema.XmlSchemaValidationException: The element 'address' has invalid child element 'name'.
    ...
    
    0 讨论(0)
  • 2020-12-05 03:12

    I wrote a PowerShell function to do this:

    Usage:

    dir *.xml | Test-Xml -Schema ".\MySchemaFile.xsd" -Namespace "http://tempuri.org"

    Code:

    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"
    }
    }
    
    0 讨论(0)
  • 2020-12-05 03:16

    I realise this is an old question however I tried the answers provided and could not get them to work successfully in Powershell.

    I have created the following function which uses some of the techniques described here. I have found it very reliable.

    I had to validate XML documents before at various times however I always found the line number to be 0. It appears the XmlSchemaException.LineNumber will only be available while loading the document.

    If you do validation afterwards using the Validate() method on an XmlDocument then LineNumber/LinePosition will always be 0.

    Instead you should do validation while reading using an XmlReader and adding a validation event handler to a block of script.

    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
    }
    
    0 讨论(0)
提交回复
热议问题