4

I want to create a function in my custom toolbox-module that uses a custom xml file to provide instructions (passed on using a $xmlpath parameter). How can I validate that the provided xml is using the correct xml type/syntax/format(correct elements, root-node etc.)?

If I use a schema-file: How do I validate xml against it using ex. Test-XML (PSCX cmdlet)? Do I store the xsd file online and specify it's path in the xml-document? Do I store it in my modules-folder and hard-code it into the script? If so, how do I specify schema-path? Codesample:

#Stored in ..\Modules\MyModule\Process-Config.psm1)
function Process-Config
{
    param($xmlpath)
    #Test that file is xml
    try{ $xml = [xml](Get-Content $xmlpath) } catch {}

    #Test that xml-file is valid against schema in Module-folder (Modules\MyModule\xmlschema.xsd)
    #Using Test-XML PSCX cmdlet
    Test-XML -Path $xmlpath -SchemaPath #Schemapath#

}

EDIT: I found out that $PSScriptRoot gives module-location so I can use $PSScriptRoot\Schemas\MySchema.xsd as path. I thought it just worked on scripts, but seems functions work too. Do I specify schema in xml for a local file like this or publish the xsd online with schema-address in the xml file?

4 Answers 4

10

If you want a basic test of an XML-File (without validating XML Schemata or a dependency on an external module), you could use the function Test-XMLFile from Jonathan Medd:

function Test-XMLFile {
    <#
        .SYNOPSIS
        Test the validity of an XML file
    #>
    [CmdletBinding()]
    param (
        [parameter(mandatory=$true)][ValidateNotNullorEmpty()][string]$xmlFilePath
    )

    # Check the file exists
    if (!(Test-Path -Path $xmlFilePath)){
        throw "$xmlFilePath is not valid. Please provide a valid path to the .xml fileh"
    }
    # Check for Load or Parse errors when loading the XML file
    $xml = New-Object System.Xml.XmlDocument
    try {
        $xml.Load((Get-ChildItem -Path $xmlFilePath).FullName)
        return $true
    }
    catch [System.Xml.XmlException] {
        Write-Verbose "$xmlFilePath : $($_.toString())"
        return $false
    }
}

and if you want to check a lot of XML-Files, you could use something like

gci -recurse *.xml |% {
 $outcome = Test-XMLFile $_.FullName -Verbose
}

which will show you which XML-File has what problem.

1
  • I'm curious how |% differs from just | in your example for multiple files. I've never seen that before.
    – GarThor
    Commented Oct 16, 2023 at 19:53
3

This is not tested, but based on a utility I wrote to check XML against the schemas it declares it uses. At its core it creates an XmlReader configured to perform XSD based validation and allowed to load referenced schemas.

$readerSettings = New-Object 'System.Xml.XmlReaderSettings';
$readerSettings.ValidationFlags = [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessInlineSchema -bor
                                  [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessSchemaLocation -bor
                                  [System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings -bor
                                  [System.Xml.Schema.XmlSchemaValidationFlags]::ProcessIdentityConstraints;
$readerSettings.ValidationType = [System.Xml.ValidationType]::Schema;

$results = @()

$valHandler = [System.Xml.Schema.ValidationEventHandler]{
  # $_ is the second argument of type System.Xml.ValidationEventArgs
  $script:results += "{0}: {1}" -f $_.Severity, $_.Message;
}

$readerSettings.add_ValidationEventHandler($valHandler)

$reader = [System.Xml.XmlReader]::Create($xmlFileName, $readerSettings);

while ($reader.Read()) {
  # Do nothing...
}

$results;  # Return the array of validation errors and warnings.

Note:

  • There are a number of exceptions that can be thrown, both when creating the reader and while processing the XML (eg. invalid XML, can't find a referenced schema).
  • There is a lot more control available than shown here, going through the documentation for XmlReaderSettings and ValidationEventArgs (for a start) will be beneficial.
  • The common way to specify the schema (XSD) for a file is the use of a schemaLocation attribute (from the http://www.w3.org/2001/XMLSchema-instance namespace) which contains a list of {namespace, XSD-schmea} pairs. However XmlReaderSettings.Schemas can also be used to specify schema outside the document.
4
  • That's pretty nice. Does it work with local paths in the scehmalocation?(ex "$PSScriptRoot\schema.xsd") or does it have to be an online address. Don't have a computer to test on atm :-)
    – Frode F.
    Commented Jan 21, 2013 at 7:02
  • @Graimer schemaLocation, if I recall correctly, can have paths relative to the XML document (strictly: to the referencing document as one XSD can then reference another XSD(. It certainly cannot contain PowerShell variables (XML wouldn't know what to do with them). So xsi:schemaLocation='urn:t-test:mydoc MySchema.xsd' would reference a schema in the same location as the XML.
    – Richard
    Commented Jan 21, 2013 at 8:49
  • Okey. I guess Keith's answer fits me better then. +1 Thanks for taking the time. Will find a use for this one too later :). Btw, does it download the schema if schemalocation is an URL online?
    – Frode F.
    Commented Jan 21, 2013 at 9:01
  • 1
    @Graimer: Yes it will download from remove locations (unless the option [System.Xml.XmlSchemaValidationFlags]::ProcessSchemaLocation is removed). There is also the XmlResolver option – a custom class able to take over converting a URN into a .NET object (Stream, XmlDocument, … usable by the XML parser; but I don't think implementing one is possible in PSH directly).
    – Richard
    Commented Jan 21, 2013 at 11:19
1

Specify the file path to XSD file, preferably via a relative path unless the XSD is stored in a well known path on each PC you plan to run the script. For relative path, yeah use $PSScriptRoot e.g.

$xsd = $PSScriptRoot\schema.xsd
Test-Xml -XmlPath $xmlPath -SchemaPath $xsd
1
  • do I need to specify the xsd schema in the xml file or is that optional?
    – Frode F.
    Commented Jan 21, 2013 at 7:01
1

I'm not quite sure if you mean to check XML validity as a function of a program, or from a service.

First of all, there are a lot of things to learn in XML, I found a resource that I'm working through: learn XML in a weekend. You might find this helpful. You don't have to know everything in it, in one go.

Here is an online service which will check the validity of an XML document.

If you want a program to be able to do that, I think you need some kind of xml lint, maybe something like: xmlint.

Finally, if you want to write a program that uses an xml lint like API, then you should specify which programming language you are using. I hope this helps a little. CHEERS!

4
  • 1
    thanks for the link to learn xml, will look into it when I got time. What I mean is that I want my Cmdlet/function in PS to validate it's input(path to xml file) before it starts processing it. To make sure it contains ex. Cars, and not books. This can be done by using ex. schema and a some powerhsell/.net code(I have seen the code), but how can I supply the XSD file with my module. Imagine my modulefolder contains: mymodule.psm1, myxmslchema.xsd. If I use ex. Test-XML(PSCX cmdlet) to test it against schema. What will my schema-path be when it resides in the modulefolder?
    – Frode F.
    Commented Jan 20, 2013 at 13:17
  • 1
    Ahh, my bad. I don't have windows 8, so I didn't quite grasp what you meant by powershell. Now I get it, but I'm not sure how to go any further without some further research. CHEERS Commented Jan 20, 2013 at 13:39
  • 1
    :) Updated question to try and make it clearer. Btw, powershell was available for XP and Vista ^^
    – Frode F.
    Commented Jan 20, 2013 at 13:40
  • 1
    Yeah, I'm a mac and linux user. My wife has Vista, but I don't get on it very often. Commented Jan 20, 2013 at 13:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.