Home > Uncategorized > Powershell, XML and XSLT as one big happy family

Powershell, XML and XSLT as one big happy family

I was scanning through my blog feeds today when I stumbled upon this video tutorial, showing how to use Visual Studio for XSLT development. I was impressed by the good support for XSLT and specifically by the great debugging capabilities. I wanted to try it out so I needed a problem that could be solved using XSLT. One thing that came to my mind was to transform the xml output from the ConvertTo-XML powershell commandlet. Given the following script:

$o = new-object psobject -property @{ Name=‘Peter’; Age=12 }
$o2 = new-object psobject -property @{ Name=‘Samuel’; Age=20 }
$o, $o2 | ConvertTo-Xml -As String

the resulting xml will be:

<?xml version="1.0"?>

<Objects>

  <Object Type="System.Management.Automation.PSCustomObject">

    <Property Name="Name" Type="System.String">Peter</Property>

    <Property Name="Age" Type="System.Int32">12</Property>

  </Object>

  <Object Type="System.Management.Automation.PSCustomObject">

    <Property Name="Name" Type="System.String">Samuel</Property>

    <Property Name="Age" Type="System.Int32">20</Property>

  </Object>

</Objects>

This xml document is not very convenient for powershell scripting. For example, accessing the age of Samuel would require the following line, assume that the xml document was stored in $data:

$data.Objects.Object[1].Property[1].‘#text’

Not that obvious, indeed. Using Visual Studio I was able to come up with the following XLST transform:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"

>

  <xsl:output method="xml" indent="yes"/>

 

  <xsl:template match="@* | node()">

    <xsl:copy>

      <xsl:apply-templates select="@* | node()"/>

    </xsl:copy>

  </xsl:template>

 

  <!– ref: http://www.dpawson.co.uk/xsl/sect2/N7240.html –>

  <xsl:template name="substring-after-last">

    <xsl:param name="string" />

    <xsl:param name="delimiter" />

    <xsl:choose>

      <xsl:when test="contains($string, $delimiter)">

        <xsl:call-template name="substring-after-last">

          <xsl:with-param name="string" select="substring-after($string, $delimiter)" />

          <xsl:with-param name="delimiter" select="$delimiter" />

        </xsl:call-template>

      </xsl:when>

      <xsl:otherwise>

        <xsl:value-of select="$string" />

      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>

 

  <xsl:template match="Object">

    <xsl:variable name="shortTypeName">

      <xsl:call-template name="substring-after-last">

        <xsl:with-param name="string" select="@Type" />

        <xsl:with-param name="delimiter" select="‘.’" />

      </xsl:call-template>

    </xsl:variable>

    <xsl:element name="{$shortTypeName}">

      <xsl:apply-templates select="node()"/>

    </xsl:element>

  </xsl:template>

 

  <xsl:template match="Property">

    <xsl:element name="{@Name}">

      <xsl:value-of select="./text()"/>

    </xsl:element>

  </xsl:template>

 

</xsl:stylesheet>

 

When applied to the xml document above it produces the following:

<?xml version="1.0" encoding="utf-8"?>

<Objects>

  <PSCustomObject>

    <Name>Peter</Name>

    <Age>12</Age>

  </PSCustomObject>

  <PSCustomObject>

    <Name>Samuel</Name>

    <Age>20</Age>

  </PSCustomObject>

</Objects>

This xml document allows a much more natural navigation. Samuels age can now be retrieved using:

$data.Objects.PSCustomObject[1].Age

Advertisements
Categories: Uncategorized
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: