<commit_before>#requires -version 2.0
# Version History:
# v 0.5 - First Public version
# v 1.0 - Made ConvertFrom-Json work with arbitrary JSON 
#       - switched to xsl style sheets for ConvertTo-JSON
# v 1.1 - Changed ConvertFrom-Json to handle single item results
# v 1.2 - CodeSigned to make a fellow geek happy
# v 1.3 - Changed ConvertFrom-Json to handle zero item results (I hope)
# v 1.4 - Added -File parmeter set to ConvertFrom-Json
#       - Cleaned up some error messages
# v 1.5 - Corrected handling of arrays
# v 1.6 - Corrected pipeline binding on ConvertFrom-Json
# v 1.7 - Added a New-Json which converts simple hashtables...
#
#  There is no help (yet) because I keep forgetting that I haven't written help yet.
#  Full RoundTrip capability:
#
#  > ls | ConvertTo-Json | ConvertFrom-Json
#  > ps | ConvertTo-Json | Convert-JsonToXml | Convert-XmlToJson | convertFrom-Json
#
#  You may frequently want to use the DEPTH or NoTypeInformation parameters:
#
#  > ConvertTo-Json -Depth 2 -NoTypeInformation
#
#  But then you have to specify the type when you reimport (and you can't do that for deep objects).  
#  This problem also occurs if you convert the result of a SELECT statement (ie: PSCustomObject).
#  For Example:
#
#  > PS | Select PM, WS, CPU, ID, ProcessName |
#  >> ConvertTo-json -NoType |
#  >> convertfrom-json -Type System.Diagnostics.Process
#
#  However, you *can* use PSOjbect as your type when re-importing:
#
#  > $Json = Get-Process | 
#  >> Select PM, WS, CPU, ID, ProcessName, @{n="SnapshotTime";e={Get-Date}} | 
#  >> ConvertTo-Json -NoType 
#  
#  > $Json | ConvertFrom-json -Type PSObject


Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization
$utf8 = [System.Text.Encoding]::UTF8

function Write-Stream {
PARAM(
   [Parameter(Position=0)]$stream,
   [Parameter(ValueFromPipeline=$true)]$string
)
PROCESS {
  $bytes = $utf8.GetBytes($string)
  $stream.Write( $bytes, 0, $bytes.Length )
}  
}


function Read-Stream {
PARAM(
   [Parameter(Position=0,ValueFromPipeline=$true)]$Stream
)
process {
   $bytes = $Stream.ToArray()
   [System.Text.Encoding]::UTF8.GetString($bytes,0,$bytes.Length)
}}


function Convert-JsonToXml {
PARAM([Parameter(ValueFromPipeline=$true)][string[]]$json)
BEGIN { 
   $mStream = New-Object System.IO.MemoryStream 
}
PROCESS {
   $json | Write-Stream -Stream $mStream
}
END {
   $mStream.Position = 0
   try
   {
      $jsonReader = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonReader($mStream,[System.Xml.XmlDictionaryReaderQuotas]::Max)
      $xml = New-Object Xml.XmlDocument
      $xml.Load($jsonReader)
      $xml
   }
   finally
   {
      $jsonReader.Close()
      $mStream.Dispose()
   }
}
}
 
function Convert-XmlToJson {
PARAM([Parameter(ValueFromPipeline=$true)][Xml]$xml)
PROCESS {
   $mStream = New-Object System.IO.MemoryStream
   $jsonWriter = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonWriter($mStream)
   try
   {
     $xml.Save($jsonWriter)
     $bytes = $mStream.ToArray()
     [System.Text.Encoding]::UTF8.GetString($bytes,0,$bytes.Length)
   }
   finally
   {
     $jsonWriter.Close()
     $mStream.Dispose()
   }
}
}

function New-Json {
[CmdletBinding()]
param([Parameter(ValueFromPipeline=$true)][HashTable]$InputObject) 
begin { 
   $ser = @{}
   $jsona = @()
}
process {
   $jsoni = 
   foreach($input in $InputObject.GetEnumerator() | Where { $_.Value } ) {
      if($input.Value -is [Hashtable]) {
         '"'+$input.Key+'": ' + (New-JSon $input.Value)
      } else {
         $type = $input.Value.GetType()
         if(!$Ser.ContainsKey($Type)) {
            $Ser.($Type) = New-Object System.Runtime.Serialization.Json.DataContractJsonSerializer $type
         }
         $stream = New-Object System.IO.MemoryStream
         $Ser.($Type).WriteObject( $stream, $Input.Value )
         '"'+$input.Key+'": ' + (Read-Stream $stream)
      }
   }

   $jsona += "{`n" +($jsoni -join ",`n")+ "`n}"
}
end { 
   if($jsona.Count -gt 1) {
      "[$($jsona -join ",`n")]" 
   } else {
      $jsona
   }
}}


## Rather than rewriting ConvertTo-Xml ...
Function ConvertTo-Json {
[CmdletBinding()]
Param(
   [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true)]$InputObject
,
   [Parameter(Mandatory=$false)][Int]$Depth=1
,
   [Switch]$NoTypeInformation
)
END { 
   ## You must output ALL the input at once 
   ## ConvertTo-Xml outputs differently if you just have one, so your results would be different
   $input | ConvertTo-Xml -Depth:$Depth -NoTypeInformation:$NoTypeInformation -As Document | Convert-CliXmlToJson
}
}

Function Convert-CliXmlToJson {
PARAM(
   [Parameter(ValueFromPipeline=$true)][Xml.XmlNode]$xml
)
BEGIN {
   $xmlToJsonXsl = @"
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--
  CliXmlToJson.xsl

  Copyright (c) 2006,2008 <NAME><commit_msg>(MODULES-4370) Remove typeinformation generation in JSON<commit_after>#requires -version 2.0
# Version History:
# v 0.5 - First Public version
# v 1.0 - Made ConvertFrom-Json work with arbitrary JSON 
#       - switched to xsl style sheets for ConvertTo-JSON
# v 1.1 - Changed ConvertFrom-Json to handle single item results
# v 1.2 - CodeSigned to make a fellow geek happy
# v 1.3 - Changed ConvertFrom-Json to handle zero item results (I hope)
# v 1.4 - Added -File parmeter set to ConvertFrom-Json
#       - Cleaned up some error messages
# v 1.5 - Corrected handling of arrays
# v 1.6 - Corrected pipeline binding on ConvertFrom-Json
# v 1.7 - Added a New-Json which converts simple hashtables...
#
#  There is no help (yet) because I keep forgetting that I haven't written help yet.
#  Full RoundTrip capability:
#
#  > ls | ConvertTo-Json | ConvertFrom-Json
#  > ps | ConvertTo-Json | Convert-JsonToXml | Convert-XmlToJson | convertFrom-Json
#
#  You may frequently want to use the DEPTH or NoTypeInformation parameters:
#
#  > ConvertTo-Json -Depth 2 -NoTypeInformation
#
#  But then you have to specify the type when you reimport (and you can't do that for deep objects).  
#  This problem also occurs if you convert the result of a SELECT statement (ie: PSCustomObject).
#  For Example:
#
#  > PS | Select PM, WS, CPU, ID, ProcessName |
#  >> ConvertTo-json -NoType |
#  >> convertfrom-json -Type System.Diagnostics.Process
#
#  However, you *can* use PSOjbect as your type when re-importing:
#
#  > $Json = Get-Process | 
#  >> Select PM, WS, CPU, ID, ProcessName, @{n="SnapshotTime";e={Get-Date}} | 
#  >> ConvertTo-Json -NoType 
#  
#  > $Json | ConvertFrom-json -Type PSObject


Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization
$utf8 = [System.Text.Encoding]::UTF8

function Write-Stream {
PARAM(
   [Parameter(Position=0)]$stream,
   [Parameter(ValueFromPipeline=$true)]$string
)
PROCESS {
  $bytes = $utf8.GetBytes($string)
  $stream.Write( $bytes, 0, $bytes.Length )
}  
}


function Read-Stream {
PARAM(
   [Parameter(Position=0,ValueFromPipeline=$true)]$Stream
)
process {
   $bytes = $Stream.ToArray()
   [System.Text.Encoding]::UTF8.GetString($bytes,0,$bytes.Length)
}}


function Convert-JsonToXml {
PARAM([Parameter(ValueFromPipeline=$true)][string[]]$json)
BEGIN { 
   $mStream = New-Object System.IO.MemoryStream 
}
PROCESS {
   $json | Write-Stream -Stream $mStream
}
END {
   $mStream.Position = 0
   try
   {
      $jsonReader = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonReader($mStream,[System.Xml.XmlDictionaryReaderQuotas]::Max)
      $xml = New-Object Xml.XmlDocument
      $xml.Load($jsonReader)
      $xml
   }
   finally
   {
      $jsonReader.Close()
      $mStream.Dispose()
   }
}
}
 
function Convert-XmlToJson {
PARAM([Parameter(ValueFromPipeline=$true)][Xml]$xml)
PROCESS {
   $mStream = New-Object System.IO.MemoryStream
   $jsonWriter = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonWriter($mStream)
   try
   {
     $xml.Save($jsonWriter)
     $bytes = $mStream.ToArray()
     [System.Text.Encoding]::UTF8.GetString($bytes,0,$bytes.Length)
   }
   finally
   {
     $jsonWriter.Close()
     $mStream.Dispose()
   }
}
}

function New-Json {
[CmdletBinding()]
param([Parameter(ValueFromPipeline=$true)][HashTable]$InputObject) 
begin { 
   $ser = @{}
   $jsona = @()
}
process {
   $jsoni = 
   foreach($input in $InputObject.GetEnumerator() | Where { $_.Value } ) {
      if($input.Value -is [Hashtable]) {
         '"'+$input.Key+'": ' + (New-JSon $input.Value)
      } else {
         $type = $input.Value.GetType()
         if(!$Ser.ContainsKey($Type)) {
            $Ser.($Type) = New-Object System.Runtime.Serialization.Json.DataContractJsonSerializer $type
         }
         $stream = New-Object System.IO.MemoryStream
         $Ser.($Type).WriteObject( $stream, $Input.Value )
         '"'+$input.Key+'": ' + (Read-Stream $stream)
      }
   }

   $jsona += "{`n" +($jsoni -join ",`n")+ "`n}"
}
end { 
   if($jsona.Count -gt 1) {
      "[$($jsona -join ",`n")]" 
   } else {
      $jsona
   }
}}


## Rather than rewriting ConvertTo-Xml ...
Function ConvertTo-Json {
[CmdletBinding()]
Param(
   [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true)]$InputObject
,
   [Parameter(Mandatory=$false)][Int]$Depth=1
)
END { 
   ## You must output ALL the input at once 
   ## ConvertTo-Xml outputs differently if you just have one, so your results would be different
   $NoTypeInformation = $true

   $input | ConvertTo-Xml -Depth:$Depth -NoTypeInformation:$NoTypeInformation -As Document | Convert-CliXmlToJson
}
}

Function Convert-CliXmlToJson {
PARAM(
   [Parameter(ValueFromPipeline=$true)][Xml.XmlNode]$xml
)
BEGIN {
   $xmlToJsonXsl = @"
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--
  CliXmlToJson.xsl

  Copyright (c) 2006,2008 <NAME>
{'fraction_non_alphanumeric': 0.14387031408308004, 'fraction_numerical': 0.011144883485309016, 'mean_word_length': 3.59757801583605, 'pattern_counts': {'":': 4, '<': 11, '<?xml version=': 2, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 18}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2768675', 'n_tokens_mistral': 3379, 'n_tokens_neox': 3262, 'n_words': 769}