PowerShell How-To

How To Validate XML Documents Using PowerShell and XSD

The tiniest mistake could throw your whole list off.

One way to store information in a hierarchical way is in a XML file. XML provides a great way to store objects and their attributes in a plain-text file. Although plain text, XML isn't just some unstructured mess of data. It follows a purposeful structure and thus information can be expected to be where you think it is. For example, you might have a XML file where you have all of your baseball cards stored in. You might have a XML file that looks something like this:

<Cards>
<Card>
<Player>
<Name> Yogi Berra </Name>
<Team> Reds </Team>
</Player>
<Year> 1989 </Year>
<CardCompany> Topps </CardCompany>
</Card>
<Card>
<Player>
<Name> Don Mattingly </Name>
<Team> Yankees </Team>
</Player>
<Year> 1993 </Year>
<CardCompany> Fleer </CardCompany>
</Card>
</Cards>

This XML file contains two cards with various tags associated with each. Now let's say you want to read this XML file with PowerShell. To do this, I'll use the [xml] type accelerator and Get-Content to pull out all the text and convert it to XML.

Figure 1.

Now I'd like to see all of the player names. Using dot notation I can drill down into the hierarchy and find each of the players. I can do the same thing for all of the other nodes as well.

Figure 2.

This works great if the XML file follows the same structure for each tag representing a card having a Card tag. Inside that with the Player tag, the Name, Team, Year and CardCompany all within the appropriate level.

<Card>
<Player>
<Name> Yogi Berra </Name>
<Team> Reds </Team>
</Player>
<Year> 1989 </Year>
<CardCompany> Topps </CardCompany>
</Card>

However, what if I'm inputting a card and make a typo? I've got this awesome new Mickey Mantle rookie card and I can't wait to get it into my inventory and the new Card entry results in something like this:

<Card>
<Player>
<Team> Reds </Team>
</Player>
<Name> Mickey Mantle </Name>
<Year> 1989 </Year>
<CardCompany> Topps </CardCompany>
</Card>

I accidently didn't include the Name tag as a child of the Player tag but rather made the Name tag a child of the Card tag. Whoops! I try to get all of the player names again but this time I get something that looks like this:

Figure 3.

That's not right! I expect Mickey Mantle to be where Player is. This could have been prevented if we would have validated the XML file using a XSD file before assigning it to the $Cards value.

Every XML has a schema. The schema is the structure of the XML file and how it should laid out. It's not mandatory but you can always create a schema definition file known as a XSD file to validate the XML file against a particular schema. By doing so, this enforces the XML to meet certain criteria before it is read by PowerShell.

Let's say I want to ensure each of the Player tags always follow the schema I want. To do that, I typically start by creating an XSD file using an online tool. To use this tool, I'll copy the contents of my XML file in there and then copy and paste out the XSD file generated.

<xs:schema attributeFormDefault="unqualified"  elementFormDefault="qualified"  xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Cards">
<xs:complexType>
<xs:sequence>
<xs:element name="Card" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="Player">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="Name"/>
<xs:element type="xs:string" name="Team"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element type="xs:float" name="Year"/>
<xs:element type="xs:string" name="CardCompany"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

You can now save this XSD file onto your computer. I then recommend downloading the PowerShell Community Extensions module where you'll find the Test-Xml function. This is a function that easily allows you to compare a XML with with a XSD schema file.

Let's see if my cards.xml file validates against this schema with the messed up Mickey Mantle card entry.

Figure 4.
VERBOSE: Error: The element 'Player' has invalid child element  'Team'. List of possible elements expected: 'Name'. Line 20, Position 2.
VERBOSE: Error: The element 'Card' has invalid child element 'Name'. List of possible elements expected: 'Year'. Line 22, Position 2.

Nope, you'll see it found the errors. You'll then find once you fix the error and make that Mickey Mantle card look like all the others Test-Xml will then return a True value indicating that the XML file does, indeed, match the XSD.

This can be a complicated topic so if you'd like to learn more about validating XML files with XSD I highly recommend checking out this w3schools article.

About the Author

Adam Bertram is a 20-year veteran of IT. He's an automation engineer, blogger, consultant, freelance writer, Pluralsight course author and content marketing advisor to multiple technology companies. Adam also founded the popular TechSnips e-learning platform. He mainly focuses on DevOps, system management and automation technologies, as well as various cloud platforms mostly in the Microsoft space. He is a Microsoft Cloud and Datacenter Management MVP who absorbs knowledge from the IT field and explains it in an easy-to-understand fashion. Catch up on Adam's articles at adamtheautomator.com, connect on LinkedIn or follow him on Twitter at @adbertram or the TechSnips Twitter account @techsnips_io.


comments powered by Disqus
Most   Popular