A thing of beauty is a joy for ever
So - I've been using the Windows Powershell for the odd bit of Tridion work. You knew that.
And you probably also knew that very often the Tridion API hands you back a string representing an XML document, and that it's very convenient to "cast" this to a .NET XmlDocument using the [xml] operator. Just search on this blog for "powershell" and you'll find enough examples. But still - there's a missing piece in the puzzle. So today I wanted to look at the output from the .GetTridionWebSchemaXMl() method on a Tridion Object Model Schema object. (Don't worry - I am weaning myself off the TOM; I wanted to compare this API with the ReadSchemaFields() method on the core service client API.)
Anyway - for what it's worth, here's what the raw string looks like:
> $tdse.GetObject("tcm:21-509-8",1).GetTridionWebSchemaXML(1919,$true)<tcm:TridionWebSchema ID="tcm:21-509-8" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0"><tcm:Context xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:transform-ext="urn:tridion:transform-ext"><tcm:Publication xlink:type="simple" xlink:title="Synchroniser tests" xlink:href="tcm:0-21-1" /><tcm:OrganizationalItem xlink:type="simple" xlink:title="TestSchemaOne" xlink:href="tcm:21-50-2" /></tcm:Context><tcm:Info xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:transform-ext="urn:tridion:transform-ext"><tcm:LocationInfo><tcm:WebDAVURL>/webdav/Synchroniser%20tests/Building%20Blocks/TestSchemaOne/TestSchemaCategories.xsd</tcm:WebDAVURL><tcm:Path>\Synchroniser tests\Building Blocks\TestSchemaOne</tcm:Path></tcm:LocationInfo><tcm:BluePrintInfo><tcm:OwningPublication xlink:type="simple" xlink:title="Synchroniser tests" xlink:href="tcm:0-21-1" /><tcm:IsShared>false</tcm:IsShared><tcm:IsLocalized>false</tcm:IsLocalized></tcm:BluePrintInfo><tcm:VersionInfo><tcm:Version>3</tcm:Version><tcm:Revision>0</tcm:Revision><tcm:CreationDate>2012-07-07T18:28:23</tcm:CreationDate><tcm:RevisionDate>2012-07-09T20:18:21</tcm:RevisionDate><tcm:Creator xlink:type="simple" xlink:title="TRIDIONDEV\Administrator" xlink:href="tcm:0-11-65552" /><tcm:Revisor xlink:type="simple" xlink:title="TRIDIONDEV\Administrator" xlink:href="tcm:0-11-65552" /><tcm:ItemLock Title="No lock" Type="0" /><tcm:IsNew>false</tcm:IsNew></tcm:VersionInfo><tcm:AllowedActions><tcm:Actions Allow="1173513" Deny="102" Managed="0" /></tcm:AllowedActions></tcm:Info><tcm:Data xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:transform-ext="urn:tridion:transform-ext"><tcm:Title>TestSchemaCategories</tcm:Title><tcm:Description>TestSchemaCategories</tcm:Description><tcm:Purpose>Component</tcm:Purpose><tcm:NamespaceURI>uuid:f14d60ed-0f7c-4d1f-a2e3-97d1dfeb1a1f</tcm:NamespaceURI><tcm:RootElementName>Content</tcm:RootElementName><tcm:Fields><tcm:KeywordField><tcm:Name>ColoursOne</tcm:Name><tcm:Description>ColoursOne</tcm:Description><tcm:MinOccurs>1</tcm:MinOccurs><tcm:MaxOccurs>unbounded</tcm:MaxOccurs><tcm:Category xlink:type="simple" xlink:title="Colours" xlink:href="tcm:21-59-512" /><tcm:Size>1</tcm:Size><tcm:List Type="tree" /><tcm:ExtensionXml xmlns="http://www.sdltridion.com/ContentManager/R6" /></tcm:KeywordField><tcm:SingleLineTextField><tcm:Name>Animals</tcm:Name><tcm:Description>Test field with locally declared list</tcm:Description><tcm:MinOccurs>1</tcm:MinOccurs><tcm:MaxOccurs>1</tcm:MaxOccurs><tcm:Size>1</tcm:Size><tcm:List Type="select"><tcm:Entry>Horse</tcm:Entry><tcm:Entry>Haddock</tcm:Entry><tcm:Entry>Weasel</tcm:Entry></tcm:List><tcm:ExtensionXml xmlns="http://www.sdltridion.com/ContentManager/R6" /></tcm:SingleLineTextField></tcm:Fields><tcm:MetadataFields /><tcm:AllowedMultimediaTypes /><tcm:ComponentProcess xlink:type="simple" xlink:title="" xlink:href="tcm:0-0-0" /></tcm:Data></tcm:TridionWebSchema>
Yeah - erm ... Okaayyyy. Great.
OK - so how about we do the cast?
> [xml]$tdse.GetObject("tcm:21-509-8",1).GetTridionWebSchemaXML(1919,$true)
TridionWebSchema
----------------
TridionWebSchema
Well - at least you can read it.. but seriously - also not super helpful if you just want to scan the XML with good-old-fashioned human eyeballs.
So what can we do? Well I got to the point where I actually typed the following into Google:
powershell pretty print xml
and the first hit was on Keith Hill's blog. Keith had written a nice little function that looks like this:
function XmlPrettyPrint([string]$xml) {
$tr = new-object System.IO.StringReader($xml)
$settings = new-object System.Xml.XmlReaderSettings
$settings.CloseInput = $true
$settings.IgnoreWhitespace = $true
$reader = [System.Xml.XmlReader]::Create($tr, $settings)
$sw = new-object System.IO.StringWriter
$settings = new-object System.Xml.XmlWriterSettings
$settings.CloseOutput = $true
$settings.Indent = $true
$writer = [System.Xml.XmlWriter]::Create($sw, $settings)
while (!$reader.EOF) {
$writer.WriteNode($reader, $false)
}
$writer.Flush()
$result = $sw.ToString()
$reader.Close()
$writer.Close()
$result
}
A minute later, this function was in my Powershell profile (and I slightly altered the name and added an alias) so now I can do the following:
> ppx ([xml]$tdse.GetObject("tcm:21-509-8",1).GetTridionWebSchemaXML(1919,$true)).OuterXml
<?xml version="1.0" encoding="utf-16"?>
<tcm:TridionWebSchema ID="tcm:21-509-8" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
<tcm:Context xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:transform-ext="urn:tridion:transform-ext">
<tcm:Publication xlink:type="simple" xlink:title="Synchroniser tests" xlink:href="tcm:0-21-1" />
<tcm:OrganizationalItem xlink:type="simple" xlink:title="TestSchemaOne" xlink:href="tcm:21-50-2" />
</tcm:Context>
<tcm:Info xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:transform-ext="urn:tridion:transform-ext">
<tcm:LocationInfo>
<tcm:WebDAVURL>/webdav/Synchroniser%20tests/Building%20Blocks/TestSchemaOne/TestSchemaCategories.xsd</tcm:WebDAVURL>
<tcm:Path>\Synchroniser tests\Building Blocks\TestSchemaOne</tcm:Path>
</tcm:LocationInfo>
<tcm:BluePrintInfo>
<tcm:OwningPublication xlink:type="simple" xlink:title="Synchroniser tests" xlink:href="tcm:0-21-1" />
<tcm:IsShared>false</tcm:IsShared>
<tcm:IsLocalized>false</tcm:IsLocalized>
</tcm:BluePrintInfo>
<tcm:VersionInfo>
<tcm:Version>3</tcm:Version>
<tcm:Revision>0</tcm:Revision>
<tcm:CreationDate>2012-07-07T18:28:23</tcm:CreationDate>
<tcm:RevisionDate>2012-07-09T20:18:21</tcm:RevisionDate>
<tcm:Creator xlink:type="simple" xlink:title="TRIDIONDEV\Administrator" xlink:href="tcm:0-11-65552" />
<tcm:Revisor xlink:type="simple" xlink:title="TRIDIONDEV\Administrator" xlink:href="tcm:0-11-65552" />
<tcm:ItemLock Title="No lock" Type="0" />
<tcm:IsNew>false</tcm:IsNew>
</tcm:VersionInfo>
<tcm:AllowedActions>
<tcm:Actions Allow="1173513" Deny="102" Managed="0" />
</tcm:AllowedActions>
</tcm:Info>
<tcm:Data xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:transform-ext="urn:tridion:transform-ext"> <tcm:Title>TestSchemaCategories</tcm:Title>
<tcm:Description>TestSchemaCategories</tcm:Description>
<tcm:Purpose>Component</tcm:Purpose>
<tcm:NamespaceURI>uuid:f14d60ed-0f7c-4d1f-a2e3-97d1dfeb1a1f</tcm:NamespaceURI>
<tcm:RootElementName>Content</tcm:RootElementName>
<tcm:Fields>
<tcm:KeywordField>
<tcm:Name>ColoursOne</tcm:Name>
<tcm:Description>ColoursOne</tcm:Description>
<tcm:MinOccurs>1</tcm:MinOccurs>
<tcm:MaxOccurs>unbounded</tcm:MaxOccurs>
<tcm:Category xlink:type="simple" xlink:title="Colours" xlink:href="tcm:21-59-512" />
<tcm:Size>1</tcm:Size>
<tcm:List Type="tree" />
<tcm:ExtensionXml xmlns="http://www.sdltridion.com/ContentManager/R6" />
</tcm:KeywordField>
<tcm:SingleLineTextField>
<tcm:Name>Animals</tcm:Name>
<tcm:Description>Test field with locally declared list</tcm:Description>
<tcm:MinOccurs>1</tcm:MinOccurs>
<tcm:MaxOccurs>1</tcm:MaxOccurs>
<tcm:Size>1</tcm:Size>
<tcm:List Type="select">
<tcm:Entry>Horse</tcm:Entry>
<tcm:Entry>Haddock</tcm:Entry>
<tcm:Entry>Weasel</tcm:Entry>
</tcm:List>
<tcm:ExtensionXml xmlns="http://www.sdltridion.com/ContentManager/R6" />
</tcm:SingleLineTextField>
</tcm:Fields>
<tcm:MetadataFields />
<tcm:AllowedMultimediaTypes />
<tcm:ComponentProcess xlink:type="simple" xlink:title="" xlink:href="tcm:0-0-0" />
</tcm:Data>
</tcm:TridionWebSchema>
So what's my point? Well I have a couple:
- The Internet is great (by which I mean, the people of the Internet are great.). I could have written that function myself in about half an hour. But in practice I might not have had the energy to do so at 10pm on a working Monday. Thanks to Keith's willingness to share, I had my solution inside a minute - working and tested. How cool is that?
- Somehow, this has just taken a little bit of the friction out of my working day, not to mention my so-called free time. I can now pull data straight out of a method that returns string, and get human-readable XML. This stuff makes a difference.
Thanks Keith - and all the other Keith's out there.
P.S. Maybe even nicely formatted XML will never be a thing of beauty, so apologies to Keats.