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."
}