Last modified at 11/2/2013 9:13 PM by Koen Zomers

​PowerShell is handy for a lot of things. One of those being verifying if an XML file is valid according to its inline specified Xml Schema Definition (XSD). This article shows how to do this.

There are various ways of assigning a schema to a XML file. One of them being directly mentioning the XSD file. This can be done by utilizing the noNamespaceSchemaLocation attribute available within the XMLSchema-instance namespace:

   <?xml version="1.0" encoding="utf-8"?>
<MyXmlFile 
   
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="MySchema.xsd">
  <Contents>
    ...

This will look for the file MySchema.xsd in the same folder as your XML resides and use that to verify if the XML contents meet the specifications defined in the XSD.

The following PowerShell script "ValidateSchema.ps1" can perform this XSD validation against the XML file by simply providing only the filepath to the XML file you want to verify:

# Validate Schema
#
# Description
# -----------
# Validates an XML file against its inline provided schema reference
#
# Command line arguments
# ----------------------
# xmlFileName: Filename of the XML file to validate
param([string]$xmlFileName)

# Check if the provided file exists
if((Test-Path -Path $xmlFileName) -eq $false)
{
    Write-Host "XML validation not possible since no XML file found at '$xmlFileName'"
    exit 2
}

# Get the file
$XmlFile = Get-Item($xmlFileName)

# Keep count of how many errors there are in the XML file
$script:errorCount = 0

# Perform the XSD Validation
$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
$readerSettings.add_ValidationEventHandler(
{
    # Triggered each time an error is found in the XML file
    Write-Host $("`nError found in XML: " + $_.Message + "`n") -ForegroundColor Red
    $script:errorCount++
});
$reader = [System.Xml.XmlReader]::Create($XmlFile.FullName, $readerSettings)
while ($reader.Read()) { }
$reader.Close()

# Verify the results of the XSD validation
if($script:errorCount -gt 0)
{
    # XML is NOT valid
    exit 1
}
else
{
    # XML is valid
    exit 0
}

Running this script will provide an exit code which indicates the successfulness of the schema validation. If no errors are found in the XML, it will return exit code 0, if errors are found it returns 1 and if the XML file could not be found it returns 2. This exit code can easily be queried by checking the value of $LASTEXITCODE.

Let's see how this works in practice. Let's say we have a XML file "KoenZomers.xml" which has the following contents:

   <?xml version="1.0" encoding="utf-8" ?>
<Books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="KoenZomers.xsd">
  <Book>
    <Title>Learning PowerShell in 24 hours</Title>
    <Author>Koen Zomers</Author>
  </Book>
  <Book>
    <Title>Learning PowerShell in 24 hours</Title>
  </Book>  
</Books>

And lets say our "KoenZomers.xsd" schema file has the following contents:

   <?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Books">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="Book">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Title" type="xs:string" />
              <xs:element name="Author" type="xs:string" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

This schema allows multiple book entries which each must have a title and an author childnode. As you can see in the above XML sample, our first book does match this criteria, but the second doesn't. Let's run the PowerShell script to verify its outcome:

PowerShell-XML-XSD-Validation-Sample.png

As you can see it finds that one of our Book elements is missing an Author childnode. $LASTEXITCODE has the value 1 after running the script which indicates that the validation was not successful.

Download the sample files here (1,4 KB)

Update 30 November 2012: Stefan Hübner contacted me and informed me that the script actually contained a small bug causing the $LASTEXITCODE always to return 0 instead of its supposed value. I have updated the scripts to reflect this fix. Thanks for this correction Stefan!