Summary: Learn how to use the [XML] type accelerator to explore XML documents.
Microsoft Scripting Guy, Ed Wilson, is here. The Scripting Wife bought me a pound of English Breakfast tea that she found online somewhere. It is long leaf, robust, and has a hint of earth tones in the bouquet. It makes a wonderfully rich pot of tea. It was a complete surprise when the box showed up on the door step. I added a cinnamon stick, like I normally do, but I thought I would try this tea basically unaltered to get a sense of what it has to offer. In a way, the tea is similar to today’s excursion into XML.
Note This is the second in a series of posts about XML. Yesterday, I talked about using XML Notepad in Creating an XML Document for Admins. You might want to explore that post before continuing with today’s.
There are several tools that can be used to explore an XML document. I can simply double-click the XML document and view it in Internet Explorer (assuming that is the default file association with XML). The following image provides an example of the output:
To be honest, Internet Explorer (or any browser for that matter) is not a very good XML viewer. I would rather view it in Notepad than Internet Explorer. On my system, the default application for XML files is not Internet Explorer, but rather XML Notepad, which in addition to being lightweight, actually has facilities for dealing with XML. So the Users.xml file looks like this in XML Notepad:
The way I prefer to look at XML documents, however, is via Windows PowerShell.
Use PowerShell to peruse XML docs
Using Windows PowerShell to open an XML document is so easy that people have a tendency to lock up. At its most basic, an XML document is a text file. What do I use to open a text file in Windows PowerShell? I use the Get-Content cmdlet. And that is the same cmdlet I use for XML. The only difference is that I use the [XML] type accelerator to convert the plain text into an XML document. This is really easy. Because when I use Get-Content to read a text file, most of the time I store the resulting text in a variable. This is the same thing I do with XML. The technique is shown here:
[XML]$users = Get-Content C:\fso\users.xml
I now have an XMLDocument object. The object members are shown here:
PS C:\> $users | Get-Member
TypeName: System.Xml.XmlDocument
Name MemberType Definition
---- ---------- ----------
ToString CodeMethod static string XmlNode(psobject insta...
AppendChild Method System.Xml.XmlNode AppendChild(Syste...
Clone Method System.Xml.XmlNode Clone(), System.O...
CloneNode Method System.Xml.XmlNode CloneNode(bool deep)
CreateAttribute Method System.Xml.XmlAttribute CreateAttrib...
CreateCDataSection Method System.Xml.XmlCDataSection CreateCDa...
CreateComment Method System.Xml.XmlComment CreateComment(...
CreateDocumentFragment Method System.Xml.XmlDocumentFragment Creat...
CreateDocumentType Method System.Xml.XmlDocumentType CreateDoc...
CreateElement Method System.Xml.XmlElement CreateElement(...
CreateEntityReference Method System.Xml.XmlEntityReference Create...
CreateNavigator Method System.Xml.XPath.XPathNavigator Crea...
CreateNode Method System.Xml.XmlNode CreateNode(System...
CreateProcessingInstruction Method System.Xml.XmlProcessingInstruction ...
CreateSignificantWhitespace Method System.Xml.XmlSignificantWhitespace ...
CreateTextNode Method System.Xml.XmlText CreateTextNode(st...
CreateWhitespace Method System.Xml.XmlWhitespace CreateWhite...
CreateXmlDeclaration Method System.Xml.XmlDeclaration CreateXmlD...
Equals Method bool Equals(System.Object obj)
GetElementById Method System.Xml.XmlElement GetElementById...
GetElementsByTagName Method System.Xml.XmlNodeList GetElementsBy...
GetEnumerator Method System.Collections.IEnumerator GetEn...
GetHashCode Method int GetHashCode()
GetNamespaceOfPrefix Method string GetNamespaceOfPrefix(string p...
GetPrefixOfNamespace Method string GetPrefixOfNamespace(string n...
GetType Method type GetType()
ImportNode Method System.Xml.XmlNode ImportNode(System...
InsertAfter Method System.Xml.XmlNode InsertAfter(Syste...
InsertBefore Method System.Xml.XmlNode InsertBefore(Syst...
Load Method void Load(string filename), void Loa...
LoadXml Method void LoadXml(string xml)
Normalize Method void Normalize()
PrependChild Method System.Xml.XmlNode PrependChild(Syst...
ReadNode Method System.Xml.XmlNode ReadNode(System.X...
RemoveAll Method void RemoveAll()
RemoveChild Method System.Xml.XmlNode RemoveChild(Syste...
ReplaceChild Method System.Xml.XmlNode ReplaceChild(Syst...
Save Method void Save(string filename), void Sav...
SelectNodes Method System.Xml.XmlNodeList SelectNodes(s...
SelectSingleNode Method System.Xml.XmlNode SelectSingleNode(...
Supports Method bool Supports(string feature, string...
Validate Method void Validate(System.Xml.Schema.Vali...
WriteContentTo Method void WriteContentTo(System.Xml.XmlWr...
WriteTo Method void WriteTo(System.Xml.XmlWriter w)
Item ParameterizedProperty System.Xml.XmlElement Item(string na...
Users Property System.Xml.XmlElement Users {get;}
xml Property string xml {get;set;}
I can see from the previous output that there are a lot of methods for dealing with XMLDocument objects via the .NET Framework. I can look up the System.XML.XMLDocument object on MSDN and find additional information about each of these methods. Today, I am interested in the properties. There are two properties: Users and XML. There is also a parameterized property called Item. Other than that, everything is a method of some sort.
To look at the values of the two properties, all I need to do is to look at the variable. I type the $users variable in the Windows PowerShell console and press ENTER. The output is less than impressive. It is shown here:
PS C:\> $users
xml Users
--- -----
version="1.0" encoding="utf-8" Users
I decide to look at what is in the XML property first:
PS C:\> $users.xml
version="1.0" encoding="utf-8"
Is there anything else? When I pipe it to Get-Member, I see that I have a System.String:
PS C:\> $users.xml | gm
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object
CompareTo Method int CompareTo(System.Object value),
Contains Method bool Contains(string value)
CopyTo Method void CopyTo(int sourceIndex, char[]
EndsWith Method bool EndsWith(string value), bool En
Equals Method bool Equals(System.Object obj), bool
GetEnumerator Method System.CharEnumerator GetEnumerator(
GetHashCode Method int GetHashCode()
<output truncated>
When I look at the Users property, I receive a series of user objects:
PS C:\> $users.Users
User
----
{User, User, User, User...}
So, I continue to drill down.
The User node:
PS C:\> $users.Users.User
ID UserName Address
-- -------- -------
0 UserName Address
0 UserName Address
0 UserName Address
0 UserName Address
0 UserName Address
The UserName node:
PS C:\> $users.Users.User.username
FirstName LastName #text Password
--------- -------- ----- --------
Bob Smith BobSmith password
Bob Smith BobSmith password
Bob Smith BobSmith password
Bob Smith BobSmith password
Bob Smith BobSmith password
And finally, the #Text property that contains the actual user name:
PS C:\> $users.Users.User.username."#text"
BobSmith
BobSmith
BobSmith
BobSmith
BobSmith
PS C:\>
Dude, all these look like the same thing. Is this right?
As a matter of a fact, it is—because all I did yesterday was duplicate each of the user objects. I did not go to the trouble of modifying any of the values. I can easily prove this by opening the XML document in XML Notepad and expanding a few of the nodes. This is shown here:
That is all there is to parsing XML. XML Week will continue tomorrow when I will talk about more cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy