PoshCode Logo PowerShell Code Repository

JSON 1.5 by Joel Bennett 17 months ago (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/2098"></script>download | new post

In this JSON module, I have a full set of tools for exporting, importing, and converting Json objects (including arbitrary objects). See comments in script header for usage examples, but basically, you can do things like:

ls | ConvertTo-Json -Depth 2
ls | Select FullName, Length | ConvertTo-JSon -NoType

You can do full round-trips, even with partial data, as long as you specify the Type when converting back from JSON:

PS | Select PM, WS, CPU, ID, ProcessName | ConvertTo-Json -NoType | ConvertFrom-Json -Type System.Diagnostics.Process

PS | Select PM, WS, CPU, ID, ProcessName, @{n="SnapshotTime";e={Get-Date}} | ConvertTo-Json | ConvertFrom-Json -Type PSObject

FIXED IN THIS VERSION:
Pipeline binding on ConvertFrom-JSON
Call out PSObject support on ConvertFrom-JSON

  1. #requires -version 2.0
  2. # Version History:
  3. # v 0.5 - First Public version
  4. # v 1.0 - Made ConvertFrom-Json work with arbitrary JSON
  5. #       - switched to xsl style sheets for ConvertTo-JSON
  6. # v 1.1 - Changed ConvertFrom-Json to handle single item results
  7. # v 1.2 - CodeSigned to make a fellow geek happy
  8. # v 1.3 - Changed ConvertFrom-Json to handle zero item results (I hope)
  9. # v 1.4 - Added -File parmeter set to ConvertFrom-Json
  10. #       - Cleaned up some error messages
  11. # v 1.5 - Corrected handling of arrays
  12. # v 1.6 - Corrected pipeline binding on ConvertFrom-Json
  13. #
  14. #  There is no help (yet) because I keep forgetting that I haven't written help yet.
  15. #  Full RoundTrip capability:
  16. #
  17. #  > ls | ConvertTo-Json | ConvertFrom-Json
  18. #  > ps | ConvertTo-Json | Convert-JsonToXml | Convert-XmlToJson | convertFrom-Json
  19. #
  20. #  You may frequently want to use the DEPTH or NoTypeInformation parameters:
  21. #
  22. #  > ConvertTo-Json -Depth 2 -NoTypeInformation
  23. #
  24. #  But then you have to specify the type when you reimport (and you can't do that for deep objects).  
  25. #  This problem also occurs if you convert the result of a SELECT statement (ie: PSCustomObject).
  26. #  For Example:
  27. #
  28. #  > PS | Select PM, WS, CPU, ID, ProcessName |
  29. #  >> ConvertTo-json -NoType |
  30. #  >> convertfrom-json -Type System.Diagnostics.Process
  31. #
  32. #  However, you *can* use PSOjbect as your type when re-importing:
  33. #
  34. #  > $Json = Get-Process |
  35. #  >> Select PM, WS, CPU, ID, ProcessName, @{n="SnapshotTime";e={Get-Date}} |
  36. #  >> ConvertTo-Json -NoType
  37. #  
  38. #  > $Json | ConvertFrom-json -Type PSObject
  39.  
  40.  
  41. Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization
  42. $utf8 = [System.Text.Encoding]::UTF8
  43.  
  44. function Write-String {
  45. PARAM(
  46.    [Parameter()]$stream,
  47.    [Parameter(ValueFromPipeline=$true)]$string
  48. )
  49. PROCESS {
  50.   $bytes = $utf8.GetBytes($string)
  51.   $stream.Write( $bytes, 0, $bytes.Length )
  52. }  
  53. }
  54.  
  55. function Convert-JsonToXml {
  56. PARAM([Parameter(ValueFromPipeline=$true)][string[]]$json)
  57. BEGIN {
  58.    $mStream = New-Object System.IO.MemoryStream
  59. }
  60. PROCESS {
  61.    $json | Write-String -stream $mStream
  62. }
  63. END {
  64.    $mStream.Position = 0
  65.    try
  66.    {
  67.       $jsonReader = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonReader($mStream,[System.Xml.XmlDictionaryReaderQuotas]::Max)
  68.       $xml = New-Object Xml.XmlDocument
  69.       $xml.Load($jsonReader)
  70.       $xml
  71.    }
  72.    finally
  73.    {
  74.       $jsonReader.Close()
  75.       $mStream.Dispose()
  76.    }
  77. }
  78. }
  79.  
  80. function Convert-XmlToJson {
  81. PARAM([Parameter(ValueFromPipeline=$true)][Xml]$xml)
  82. PROCESS {
  83.    $mStream = New-Object System.IO.MemoryStream
  84.    $jsonWriter = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonWriter($mStream)
  85.    try
  86.    {
  87.      $xml.Save($jsonWriter)
  88.      $bytes = $mStream.ToArray()
  89.      [System.Text.Encoding]::UTF8.GetString($bytes,0,$bytes.Length)
  90.    }
  91.    finally
  92.    {
  93.      $jsonWriter.Close()
  94.      $mStream.Dispose()
  95.    }
  96. }
  97. }
  98.  
  99. ## Rather than rewriting ConvertTo-Xml ...
  100. Function ConvertTo-Json {
  101. [CmdletBinding()]
  102. Param(
  103.    [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true)]$InputObject
  104. ,
  105.    [Parameter(Mandatory=$false)][Int]$Depth=1
  106. ,
  107.    [Switch]$NoTypeInformation
  108. )
  109. END {
  110.    ## You must output ALL the input at once
  111.    ## ConvertTo-Xml outputs differently if you just have one, so your results would be different
  112.    $input | ConvertTo-Xml -Depth:$Depth -NoTypeInformation:$NoTypeInformation -As Document | Convert-CliXmlToJson
  113. }
  114. }
  115.  
  116. Function Convert-CliXmlToJson {
  117. PARAM(
  118.    [Parameter(ValueFromPipeline=$true)][Xml.XmlNode]$xml
  119. )
  120. BEGIN {
  121.    $xmlToJsonXsl = @'
  122. <?xml version="1.0" encoding="UTF-8"?>
  123. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  124. <!--
  125.  CliXmlToJson.xsl
  126.  
  127.  Copyright (c) 2006,2008 Doeke Zanstra
  128.  Copyright (c) 2009 Joel Bennett
  129.  All rights reserved.
  130.  
  131.  Redistribution and use in source and binary forms, with or without modification,
  132.  are permitted provided that the following conditions are met:
  133.  
  134.  Redistributions of source code must retain the above copyright notice, this
  135.  list of conditions and the following disclaimer. Redistributions in binary
  136.  form must reproduce the above copyright notice, this list of conditions and the
  137.  following disclaimer in the documentation and/or other materials provided with
  138.  the distribution.
  139.  
  140.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  141.  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  142.  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  143.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  144.  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  145.  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  146.  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  147.  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  148.  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  149.  THE POSSIBILITY OF SUCH DAMAGE.
  150. -->
  151.  
  152.  <xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8" media-type="text/x-json"/>
  153.         <xsl:strip-space elements="*"/>
  154.  <!--contant-->
  155.  <xsl:variable name="d">0123456789</xsl:variable>
  156.  
  157.  <!-- ignore document text -->
  158.  <xsl:template match="text()[preceding-sibling::node() or following-sibling::node()]"/>
  159.  
  160.  <!-- string -->
  161.  <xsl:template match="text()">
  162.    <xsl:call-template name="escape-string">
  163.      <xsl:with-param name="s" select="."/>
  164.    </xsl:call-template>
  165.  </xsl:template>
  166.  
  167.  <!-- Main template for escaping strings; used by above template and for object-properties
  168.       Responsibilities: placed quotes around string, and chain up to next filter, escape-bs-string -->
  169.  <xsl:template name="escape-string">
  170.    <xsl:param name="s"/>
  171.    <xsl:text>"</xsl:text>
  172.    <xsl:call-template name="escape-bs-string">
  173.      <xsl:with-param name="s" select="$s"/>
  174.    </xsl:call-template>
  175.    <xsl:text>"</xsl:text>
  176.  </xsl:template>
  177.  
  178.  <!-- Escape the backslash (\) before everything else. -->
  179.  <xsl:template name="escape-bs-string">
  180.    <xsl:param name="s"/>
  181.    <xsl:choose>
  182.      <xsl:when test="contains($s,'\')">
  183.        <xsl:call-template name="escape-quot-string">
  184.          <xsl:with-param name="s" select="concat(substring-before($s,'\'),'\\')"/>
  185.        </xsl:call-template>
  186.        <xsl:call-template name="escape-bs-string">
  187.          <xsl:with-param name="s" select="substring-after($s,'\')"/>
  188.        </xsl:call-template>
  189.      </xsl:when>
  190.      <xsl:otherwise>
  191.        <xsl:call-template name="escape-quot-string">
  192.          <xsl:with-param name="s" select="$s"/>
  193.        </xsl:call-template>
  194.      </xsl:otherwise>
  195.    </xsl:choose>
  196.  </xsl:template>
  197.  
  198.  <!-- Escape the double quote ("). -->
  199.  <xsl:template name="escape-quot-string">
  200.    <xsl:param name="s"/>
  201.    <xsl:choose>
  202.      <xsl:when test="contains($s,'&quot;')">
  203.        <xsl:call-template name="encode-string">
  204.          <xsl:with-param name="s" select="concat(substring-before($s,'&quot;'),'\&quot;')"/>
  205.        </xsl:call-template>
  206.        <xsl:call-template name="escape-quot-string">
  207.          <xsl:with-param name="s" select="substring-after($s,'&quot;')"/>
  208.        </xsl:call-template>
  209.      </xsl:when>
  210.      <xsl:otherwise>
  211.        <xsl:call-template name="encode-string">
  212.          <xsl:with-param name="s" select="$s"/>
  213.        </xsl:call-template>
  214.      </xsl:otherwise>
  215.    </xsl:choose>
  216.  </xsl:template>
  217.  
  218.  <!-- Replace tab, line feed and/or carriage return by its matching escape code. Can't escape backslash
  219.        or double quote here, because they don't replace characters (&#x0; becomes \t), but they prefix
  220.       characters (\ becomes \\). Besides, backslash should be seperate anyway, because it should be
  221.       processed first. This function can't do that. -->
  222.   <xsl:template name="encode-string">
  223.     <xsl:param name="s"/>
  224.     <xsl:choose>
  225.       <!-- tab -->
  226.       <xsl:when test="contains($s,'&#x9;')">
  227.         <xsl:call-template name="encode-string">
  228.           <xsl:with-param name="s" select="concat(substring-before($s,'&#x9;'),'\t',substring-after($s,'&#x9;'))"/>
  229.         </xsl:call-template>
  230.       </xsl:when>
  231.       <!-- line feed -->
  232.       <xsl:when test="contains($s,'&#xA;')">
  233.         <xsl:call-template name="encode-string">
  234.           <xsl:with-param name="s" select="concat(substring-before($s,'&#xA;'),'\n',substring-after($s,'&#xA;'))"/>
  235.         </xsl:call-template>
  236.       </xsl:when>
  237.       <!-- carriage return -->
  238.       <xsl:when test="contains($s,'&#xD;')">
  239.         <xsl:call-template name="encode-string">
  240.           <xsl:with-param name="s" select="concat(substring-before($s,'&#xD;'),'\r',substring-after($s,'&#xD;'))"/>
  241.         </xsl:call-template>
  242.       </xsl:when>
  243.       <xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise>
  244.     </xsl:choose>
  245.   </xsl:template>
  246.  
  247.   <!-- number (no support for javascript mantise) -->
  248.   <xsl:template match="text()[not(string(number())='NaN' or
  249.                       (starts-with(.,'0' ) and . != '0'))]">
  250.     <xsl:value-of select="."/>
  251.   </xsl:template>
  252.  
  253.   <!-- boolean, case-insensitive -->
  254.   <xsl:template match="text()[translate(.,'TRUE','true')='true']">true</xsl:template>
  255.   <xsl:template match="text()[translate(.,'FALSE','false')='false']">false</xsl:template>
  256.  
  257.   <!-- root object(s) -->
  258.   <xsl:template match="*" name="base">
  259.     <xsl:if test="not(preceding-sibling::*)">
  260.       <xsl:choose>
  261.         <xsl:when test="count(../*)>1"><xsl:text>[</xsl:text></xsl:when>
  262.         <xsl:otherwise><xsl:text>{</xsl:text></xsl:otherwise>
  263.       </xsl:choose>
  264.     </xsl:if>
  265.     <xsl:call-template name="escape-string">
  266.       <xsl:with-param name="s" select="name()"/>
  267.     </xsl:call-template>
  268.     <xsl:text>:</xsl:text>
  269.     <!-- check type of node -->
  270.     <xsl:choose>
  271.       <!-- null nodes -->
  272.       <xsl:when test="count(child::node())=0">null</xsl:when>
  273.       <!-- other nodes -->
  274.       <xsl:otherwise>
  275.         <xsl:apply-templates select="child::node()"/>
  276.       </xsl:otherwise>
  277.     </xsl:choose>
  278.     <!-- end of type check -->
  279.     <xsl:if test="following-sibling::*">,</xsl:if>
  280.     <xsl:if test="not(following-sibling::*)">
  281.       <xsl:choose>
  282.         <xsl:when test="count(../*)>1"><xsl:text>]</xsl:text></xsl:when>
  283.         <xsl:otherwise><xsl:text>}</xsl:text></xsl:otherwise>
  284.       </xsl:choose>
  285.     </xsl:if>
  286.   </xsl:template>
  287.  
  288.   <!-- properties of objects -->
  289.   <xsl:template match="*[count(../*[name(../*)=name(.)])=count(../*) and count(../*)&gt;1]">
  290.     <xsl:variable name="inArray" select="translate(local-name(),'OBJECT','object')='object' or ../@Type[starts-with(.,'System.Collections') or contains(.,'[]') or (contains(.,'[') and contains(.,']'))]"/>
  291.     <xsl:if test="not(preceding-sibling::*)">
  292.        <xsl:choose>
  293.          <xsl:when test="$inArray"><xsl:text>[</xsl:text></xsl:when>
  294.          <xsl:otherwise>
  295.             <xsl:text>{</xsl:text>
  296.             <xsl:if test="../@Type">
  297.                <xsl:text>"__type":</xsl:text>      
  298.                <xsl:call-template name="escape-string">
  299.                  <xsl:with-param name="s" select="../@Type"/>
  300.                </xsl:call-template>
  301.                <xsl:text>,</xsl:text>      
  302.              </xsl:if>
  303.          </xsl:otherwise>
  304.        </xsl:choose>
  305.     </xsl:if>
  306.     <xsl:choose>
  307.       <xsl:when test="not(child::node())">
  308.         <xsl:call-template name="escape-string">
  309.           <xsl:with-param name="s" select="@Name"/>
  310.         </xsl:call-template>
  311.         <xsl:text>:null</xsl:text>
  312.       </xsl:when>
  313.       <xsl:when test="$inArray">
  314.         <xsl:apply-templates select="child::node()"/>
  315.       </xsl:when>
  316.       <!--
  317.       <xsl:when test="not(@Name) and not(@Type)">
  318.         <xsl:call-template name="escape-string">
  319.           <xsl:with-param name="s" select="local-name()"/>
  320.         </xsl:call-template>
  321.         <xsl:text>:</xsl:text>      
  322.         <xsl:apply-templates select="child::node()"/>
  323.       </xsl:when>
  324.       -->
  325.       <xsl:when test="not(@Name)">
  326.         <xsl:call-template name="escape-string">
  327.           <xsl:with-param name="s" select="local-name()"/>
  328.         </xsl:call-template>
  329.         <xsl:text>:</xsl:text>      
  330.         <xsl:apply-templates select="child::node()"/>
  331.       </xsl:when>
  332.       <xsl:otherwise>
  333.         <xsl:call-template name="escape-string">
  334.           <xsl:with-param name="s" select="@Name"/>
  335.         </xsl:call-template>
  336.         <xsl:text>:</xsl:text>
  337.         <xsl:apply-templates select="child::node()"/>
  338.       </xsl:otherwise>
  339.     </xsl:choose>
  340.     <xsl:if test="following-sibling::*">,</xsl:if>
  341.     <xsl:if test="not(following-sibling::*)">      
  342.       <xsl:choose>
  343.         <xsl:when test="$inArray"><xsl:text>]</xsl:text></xsl:when>
  344.         <xsl:otherwise><xsl:text>}</xsl:text></xsl:otherwise>
  345.       </xsl:choose>
  346.     </xsl:if>
  347.   </xsl:template>
  348.  
  349.  
  350.   <!-- convert root element to an anonymous container -->
  351.   <xsl:template match="/">
  352.     <xsl:apply-templates select="node()"/>
  353.   </xsl:template>    
  354. </xsl:stylesheet>
  355. '@
  356. }
  357. PROCESS {
  358.   if(Get-Member -InputObject $xml -Name root) {
  359.      Write-Verbose "Ripping to Objects"
  360.      $xml = $xml.root.Objects
  361.   } else {
  362.      Write-Verbose "Was already Objects"
  363.   }
  364.   Convert-Xml -Xml $xml -Xsl $xmlToJsonXsl
  365. }
  366. }
  367.  
  368. Function ConvertFrom-Xml {
  369.   [CmdletBinding(DefaultParameterSetName="AutoType")]
  370.   PARAM(
  371.      [Parameter(ValueFromPipeline=$true,Mandatory=$true,Position=1)]
  372.      [Xml.XmlNode]
  373.      $xml
  374.      ,
  375.      [Parameter(Mandatory=$true,ParameterSetName="ManualType")]
  376.      [Type]$Type
  377.      ,
  378.      [Switch]$ForceType
  379.   )
  380.   PROCESS{
  381.      if(Get-Member -InputObject $xml -Name root) {
  382.         return $xml.root.Objects | ConvertFrom-Xml
  383.      } elseif(Get-Member -InputObject $xml -Name Objects) {
  384.         return $xml.Objects | ConvertFrom-Xml
  385.      }
  386.      $propbag = @{}
  387.      foreach($name in Get-Member -InputObject $xml -MemberType Properties | Where-Object{$_.Name -notmatch "^__|type"} | Select-Object -ExpandProperty name) {
  388.         Write-Verbose "$Name Type: $($xml.$Name.type)"
  389.         $propbag."$Name" = Convert-Properties $xml."$name"
  390.      }
  391.      if(!$Type -and $xml.HasAttribute("__type")) { $Type = $xml.__Type }
  392.      if($ForceType -and $Type) {
  393.         try {
  394.            $output = New-Object $Type -Property $propbag
  395.         } catch {
  396.            $output = New-Object PSObject -Property $propbag
  397.            $output.PsTypeNames.Insert(0, $xml.__type)
  398.         }
  399.      } else {
  400.         $output = New-Object PSObject -Property $propbag
  401.         if($Type) {
  402.            $output.PsTypeNames.Insert(0, $Type)
  403.         }
  404.      }
  405.      Write-Output $output
  406.   }
  407. }
  408.  
  409. Function Convert-Properties {
  410. param($InputObject)
  411.   switch( $InputObject.type ) {
  412.      "object" {
  413.         return (ConvertFrom-Xml -Xml $InputObject)
  414.         break
  415.      }
  416.      "string" {
  417.         $MightBeADate = $InputObject.get_InnerText() -as [DateTime]
  418.         ## Strings that are actually dates (*grumble* JSON is crap)              
  419.         if($MightBeADate -and $propbag."$Name" -eq $MightBeADate.ToString("G")) {
  420.            return $MightBeADate
  421.         } else {
  422.            return $InputObject.get_InnerText()
  423.         }
  424.         break
  425.      }
  426.      "number" {
  427.         $number = $InputObject.get_InnerText()
  428.         if($number -eq ($number -as [int])) {
  429.            return $number -as [int]
  430.         } elseif($number -eq ($number -as [double])) {
  431.            return $number -as [double]
  432.         } else {
  433.            return $number -as [decimal]
  434.         }
  435.         break
  436.      }
  437.      "boolean" {
  438.         return [bool]::parse($InputObject.get_InnerText())
  439.      }
  440.      "null" {
  441.         return $null
  442.      }
  443.      "array" {
  444.         [object[]]$Items = $( foreach( $item in $InputObject.GetEnumerator() ) {
  445.            Convert-Properties $item
  446.         } )
  447.         return $Items
  448.      }
  449.      default {
  450.         return $InputObject
  451.         break
  452.      }
  453.   }
  454.  
  455. }
  456.  
  457.  
  458.  
  459. Function ConvertFrom-Json {
  460.   [CmdletBinding(DefaultParameterSetName="StringInput")]
  461. PARAM(
  462.   [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="File")]
  463.   [Alias("PSPath")]
  464.   [string]$File
  465. ,
  466.   [Parameter(ValueFromPipeline=$true,Mandatory=$true,Position=1,ParameterSetName="StringInput")]
  467.   [string]$InputObject
  468. ,
  469.   [Parameter(Mandatory=$true)]
  470.   [Type]$Type
  471.   ,
  472.   [Switch]$ForceType
  473. )
  474. BEGIN {
  475.   [bool]$AsParameter = $PSBoundParameters.ContainsKey("File") -or $PSBoundParameters.ContainsKey("InputObject")
  476. }
  477. PROCESS {
  478.   if($PSCmdlet.ParameterSetName -eq "File") {
  479.      [string]$InputObject = @(Get-Content $File) -Join "`n"
  480.      $null = $PSBoundParameters.Remove("File")
  481.   }
  482.   else
  483.   {
  484.      $null = $PSBoundParameters.Remove("InputObject")
  485.   }
  486.   [Xml.XmlElement]$xml = (Convert-JsonToXml $InputObject).Root
  487.   if($xml) {
  488.      if($xml.Objects) {
  489.         $xml.Objects.Item.GetEnumerator() | ConvertFrom-Xml @PSBoundParameters
  490.      }elseif($xml.Item -and $xml.Item -isnot [System.Management.Automation.PSParameterizedProperty]) {
  491.         $xml.Item | ConvertFrom-Xml @PSBoundParameters
  492.      }else {
  493.         $xml | ConvertFrom-Xml @PSBoundParameters
  494.      }
  495.   } else {
  496.      Write-Error "Failed to parse JSON with JsonReader"
  497.   }
  498. }
  499. }
  500.  
  501. #########
  502. ### The JSON library is dependent on Convert-Xml from my Xml script module
  503.  
  504. function Convert-Node {
  505. param(
  506. [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  507. [System.Xml.XmlReader]$XmlReader,
  508. [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
  509. [System.Xml.Xsl.XslCompiledTransform]$StyleSheet
  510. )
  511. PROCESS {
  512.   $output = New-Object IO.StringWriter
  513.   $StyleSheet.Transform( $XmlReader, $null, $output )
  514.   Write-Output $output.ToString()
  515. }
  516. }
  517.  
  518. function Convert-Xml {
  519. #.Synopsis
  520. #  The Convert-XML function lets you use Xslt to transform XML strings and documents.
  521. #.Description
  522. #.Parameter Content
  523. #  Specifies a string that contains the XML to search. You can also pipe strings to Select-XML.
  524. #.Parameter Namespace
  525. #   Specifies a hash table of the namespaces used in the XML. Use the format @{<namespaceName> = <namespaceUri>}.
  526. #.Parameter Path
  527. #   Specifies the path and file names of the XML files to search.  Wildcards are permitted.
  528. #.Parameter Xml
  529. #  Specifies one or more XML nodes to search.
  530. #.Parameter Xsl
  531. #  Specifies an Xml StyleSheet to transform with...
  532. [CmdletBinding(DefaultParameterSetName="Xml")]
  533. PARAM(
  534.   [Parameter(Position=1,ParameterSetName="Path",Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
  535.   [ValidateNotNullOrEmpty()]
  536.   [Alias("PSPath")]
  537.   [String[]]$Path
  538. ,
  539.   [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  540.   [ValidateNotNullOrEmpty()]
  541.   [Alias("Node")]
  542.   [System.Xml.XmlNode[]]$Xml
  543. ,
  544.   [Parameter(ParameterSetName="Content",Mandatory=$true,ValueFromPipeline=$true)]
  545.   [ValidateNotNullOrEmpty()]
  546.   [String[]]$Content
  547. ,
  548.   [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
  549.   [ValidateNotNullOrEmpty()]
  550.   [Alias("StyleSheet")]
  551.   [String[]]$Xslt
  552. )
  553. BEGIN {
  554.   $StyleSheet = New-Object System.Xml.Xsl.XslCompiledTransform
  555.   if(Test-Path @($Xslt)[0] -ErrorAction 0) {
  556.      Write-Verbose "Loading Stylesheet from $(Resolve-Path @($Xslt)[0])"
  557.      $StyleSheet.Load( (Resolve-Path @($Xslt)[0]) )
  558.   } else {
  559.      Write-Verbose "$Xslt"
  560.      $StyleSheet.Load(([System.Xml.XmlReader]::Create((New-Object System.IO.StringReader ($Xslt -join "`n")))))
  561.   }
  562.   [Text.StringBuilder]$XmlContent = [String]::Empty
  563. }
  564. PROCESS {
  565.   switch($PSCmdlet.ParameterSetName) {
  566.      "Content" {
  567.         $null = $XmlContent.AppendLine( $Content -Join "`n" )
  568.      }
  569.      "Path" {
  570.         foreach($file in Get-ChildItem $Path) {
  571.            Convert-Node -Xml ([System.Xml.XmlReader]::Create((Resolve-Path $file))) $StyleSheet
  572.         }
  573.      }
  574.      "Xml" {
  575.         foreach($node in $Xml) {
  576.            Convert-Node -Xml (New-Object Xml.XmlNodeReader $node) $StyleSheet
  577.         }
  578.      }
  579.   }
  580. }
  581. END {
  582.   if($PSCmdlet.ParameterSetName -eq "Content") {
  583.      [Xml]$Xml = $XmlContent.ToString()
  584.      Convert-Node -Xml $Xml $StyleSheet
  585.   }
  586. }
  587. }
  588.  
  589.  
  590. New-Alias fromjson ConvertFrom-Json
  591. New-Alias tojson ConvertTo-Json
  592.  
  593. #New-Alias ipjs Import-Json
  594. #New-Alias epjs Export-Json
  595. #Import-Json, Export-Json,
  596.  
  597. Export-ModuleMember -Function ConvertFrom-Json, ConvertTo-Json, Convert-JsonToXml, Convert-XmlToJson, Convert-CliXmlToJson -Alias *
  598.  
  599. # SIG # Begin signature block
  600. # MIIIDQYJKoZIhvcNAQcCoIIH/jCCB/oCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
  601. # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
  602. # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVOSNLwCk5kgVZvSmrZS8eSHh
  603. # enegggUrMIIFJzCCBA+gAwIBAgIQKQm90jYWUDdv7EgFkuELajANBgkqhkiG9w0B
  604. # AQUFADCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
  605. # IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
  606. # VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VS
  607. # Rmlyc3QtT2JqZWN0MB4XDTEwMDUxNDAwMDAwMFoXDTExMDUxNDIzNTk1OVowgZUx
  608. # CzAJBgNVBAYTAlVTMQ4wDAYDVQQRDAUwNjg1MDEUMBIGA1UECAwLQ29ubmVjdGlj
  609. # dXQxEDAOBgNVBAcMB05vcndhbGsxFjAUBgNVBAkMDTQ1IEdsb3ZlciBBdmUxGjAY
  610. # BgNVBAoMEVhlcm94IENvcnBvcmF0aW9uMRowGAYDVQQDDBFYZXJveCBDb3Jwb3Jh
  611. # dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMfUdxwiuWDb8zId
  612. # KuMg/jw0HndEcIsP5Mebw56t3+Rb5g4QGMBoa8a/N8EKbj3BnBQDJiY5Z2DGjf1P
  613. # n27g2shrDaNT1MygjYfLDntYzNKMJk4EjbBOlR5QBXPM0ODJDROg53yHcvVaXSMl
  614. # 498SBhXVSzPmgprBJ8FDL00o1IIAAhYUN3vNCKPBXsPETsKtnezfzBg7lOjzmljC
  615. # mEOoBGT1g2NrYTq3XqNo8UbbDR8KYq5G101Vl0jZEnLGdQFyh8EWpeEeksv7V+YD
  616. # /i/iXMSG8HiHY7vl+x8mtBCf0MYxd8u1IWif0kGgkaJeTCVwh1isMrjiUnpWX2NX
  617. # +3PeTmsCAwEAAaOCAW8wggFrMB8GA1UdIwQYMBaAFNrtZHQUnBQ8q92Zqb1bKE2L
  618. # PMnYMB0GA1UdDgQWBBTK0OAaUIi5wvnE8JonXlTXKWENvTAOBgNVHQ8BAf8EBAMC
  619. # B4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzARBglghkgBhvhC
  620. # AQEEBAMCBBAwRgYDVR0gBD8wPTA7BgwrBgEEAbIxAQIBAwIwKzApBggrBgEFBQcC
  621. # ARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLm5ldC9DUFMwQgYDVR0fBDswOTA3oDWg
  622. # M4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0
  623. # LmNybDA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNv
  624. # bW9kb2NhLmNvbTAhBgNVHREEGjAYgRZKb2VsLkJlbm5ldHRAWGVyb3guY29tMA0G
  625. # CSqGSIb3DQEBBQUAA4IBAQAEss8yuj+rZvx2UFAgkz/DueB8gwqUTzFbw2prxqee
  626. # zdCEbnrsGQMNdPMJ6v9g36MRdvAOXqAYnf1RdjNp5L4NlUvEZkcvQUTF90Gh7OA4
  627. # rC4+BjH8BA++qTfg8fgNx0T+MnQuWrMcoLR5ttJaWOGpcppcptdWwMNJ0X6R2WY7
  628. # bBPwa/CdV0CIGRRjtASbGQEadlWoc1wOfR+d3rENDg5FPTAIdeRVIeA6a1ZYDCYb
  629. # 32UxoNGArb70TCpV/mTWeJhZmrPFoJvT+Lx8ttp1bH2/nq6BDAIvu0VGgKGxN4bA
  630. # T3WE6MuMS2fTc1F8PCGO3DAeA9Onks3Ufuy16RhHqeNcMYICTDCCAkgCAQEwgaow
  631. # gZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtl
  632. # IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMY
  633. # aHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0
  634. # LU9iamVjdAIQKQm90jYWUDdv7EgFkuELajAJBgUrDgMCGgUAoHgwGAYKKwYBBAGC
  635. # NwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
  636. # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUEW0DtdE/
  637. # JxK83G70qiWwclaBOkswDQYJKoZIhvcNAQEBBQAEggEAj4Uojbc96AZ7aKOLgkfP
  638. # E+qkrMWAuGijIacClwgOcUGOzdkNDQAdbvvLJTWafE7uBDFdEuxL7MZDvPDLFPJ0
  639. # U95AjfVwhf7FTEMHL3UOGJS5Lo/JAsnIz6Fza4faLv4kilXyRRME1iBqH/vxllNj
  640. # mGV8Rm0Yg8EZ4ClYLonHuGFT2+XqOA1wbjncZbUfqg/8ybD+TVh/19BJoqSRNoL9
  641. # /TKQTgBoOVSB3pJmvoFfKjxPrS/1fPiVOGi0HfP4JhzAYRy9PDHCmxat0IE+ev9w
  642. # LAjR2YUQ0xJRYIa1rQfJaohi45wMyIoeur3Z3zHL9sk+MbkQvyMO2Qsmi5fU309e
  643. # 1g==
  644. # SIG # End signature block

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me