XML validation against XSD

15/10/2012 12:55

 

 
Function Validate-Xml{ 
    param(     
        [Parameter( 
            Mandatory = $true, 
            Position = 0, 
            ValueFromPipeline = $true, 
            ValueFromPipelineByPropertyName = $true)] 
        [xml]$xml, 
        [Parameter( 
            Mandatory = $true, 
            Position = 1, 
            ValueFromPipeline = $false)] 
        [string]$schema 
        ) 
 
    #<c>Declare the array to hold our error objects</c> 
    
    [int]$errorCount=0;
         
    #<c>Check to see if we have defined our namespace cache variable, 
    #and create it if it doesnt exist. We do this in case we want to make 
    #lots and lots of calls to this function, to save on excessive file IO.</c> 
    if (-not $schemas){ ${GLOBAL:schemas} = @{} } 
     
     #Remove our schema from $scheams due to error it already exists
     if($schemas.ContainsKey($schema))
        {
            $schemas.Remove($schema)
        }
     
     
    #<c>Check to see if the namespace is already in the cache,if not then add it</c> 
    #<choose> 
    #<if test="Is schema in cache"> 
    if (-not $schemas[$schema]) { 
        #<c>Read in the schema file</c> 
        [xml]$xmlschema = Get-Content $schema 
        #<c>Extract the targetNamespace from the schema</c> 
        $namespace = $xmlschema.get_DocumentElement().targetNamespace 
        #<c>Add the schema/namespace entry to the global hashtable</c> 
        $schemas.Add($schema,$namespace) 
        #</if> 
    }
    else { 
        #<else> 
        #<c>Pull the namespace from the schema cache</c> 
        $namespace = $schemas[$schema] 
    } 
    #</else><choose> 
 
    #<c>Define the script block that will act as the validation event handler</c> 
$code = @'
   $errorCount++; 
   Write-Host $("`nError found in XML: " + $_.Message + "`n") -ForegroundColor Red
'@ 
    #<c>Convert the code block to as ScriptBlock</c> 
    $validationEventHandler = [scriptblock]::Create($code) 
     
    #<c>Create a new XmlReaderSettings object</c> 
    $rs = new-object System.Xml.XmlreaderSettings 
    #<c>Load the schema into the XmlReaderSettings object</c> 
    [Void]$rs.schemas.add($namespace,(new-object System.Xml.xmltextreader($schema))) 
    #<c>Instruct the XmlReaderSettings object to use Schema validation</c> 
    $rs.validationtype = "Schema" 
    $rs.ConformanceLevel = "Auto" 
    #<c>Add the scriptblock as the ValidationEventHandler</c> 
    $rs.add_ValidationEventHandler($validationEventHandler) 
     
    #<c>Create a temporary file and save the Xml into it</c> 
    $xmlfile = [System.IO.Path]::GetTempFileName() 
    $xml.Save($xmlfile) 
     
    #<c>Create the XmlReader object using the settings defined previously</c> 
    $reader = [System.Xml.XmlReader]::Create($xmlfile,$rs) 
     
    #<c>Temporarily set the ErrorActionPreference to SilentlyContinue, 
    #as we want to use our validation event handler to handle errors</c> 
    $previousErrorActionPreference = $ErrorActionPreference 
    $ErrorActionPreference = "SilentlyContinue" 
     
    #<c>Read the Xml using the XmlReader</c> 
    while ($reader.read()) {$null} 
    #<c>Close the reader</c> 
    $reader.close() 
     
    #<c>Delete the temporary file</c> 
    Remove-Item $xmlfile 
     
    #<c>Reset the ErrorActionPreference back to the previous value</c> 
    $ErrorActionPreference = $previousErrorActionPreference  
     
    #<c>Return the array of validation errors</c> 
    return $errorCount
#</body></function> 
 
################################################################ 
## Start script 
################################################################ 
 
#call function
 
$xmlFileName=$sourceFilePath #"c:\temp\TFSdefaultTasksXML.xml"
$schema = $XsdSchemaPath #"c:\temp\TFSdefaultTasksXML.xsd"
 
 
[xml]$xml = gc $xmlFileName
 
$result=0
$result = Validate-Xml $xml $schema 
 
#Show result in case of valid, $result is some strange type, so parse it.
if([int]::Parse($result) -eq 0)
{
    $IsValid=$true;
    #write-host "XML is valid."
}
else
{
    $IsValid=$false;
    #write-host "XML is not valid."
}