I'm trying to use HJSON C# library for PowerShell: https://github.com/hjson/hjson-cs I've successfully compiled the dll, put it into a folder and added the type via standard procedure:
#LOAD
$scriptRoot = Split-Path $script:psEditor.GetEditorContext().CurrentFile.Path
$FilePath = ( Get-Item .\Hjson.dll ).FullName
[System.Reflection.Assembly]::LoadFrom("$FilePath")
[Hjson.IJsonReader]::new()
[Hjson.hjson]::Load("$scriptRoot\test.hjson")
I'm trying to follow examples to get the basics:
Read method: https://github.com/hjson/hjson-cs#read
# var jsonObject = HjsonValue.Load(filePath).Qo();
$jsonTempData = [Hjson.HjsonValue]::Load("$scriptRoot\test.hjson")
$jsonObject = [Hjson.JsonUtil]::Qo($jsonTempData)
$jsonObject
but the output is missing values:
PS D:\OneDrive\PS-HJSON> $jsonObject
Key Value
--- -----
hello
text
quote
otherwise
abc-123
commas
but
trailing
multiline
number
negative
yes
no
null
array
array2
PS D:\OneDrive\PS-HJSON>
So I can't see values. Why it doesn't work like JSON objects?
And when I try to iterate through keys:
foreach ( $item in $jsonObject) {
$item.Key, $item.Value
}
I got this:
The following exception occurred while trying to enumerate the collection: "The operation is invalid due to the current state of the object. "
I'm sure I'm missing something, but I don't know c# enough to know what to do.
The library is just written in a way that doesn't work great with how PowerShell displays data it doesn't have format information for.
JsonValue
(the type emitted by Hjson.Load
) is more or less a dictionary of string
to JsonPrimitive
(or more JsonValue
for nesting).
The reason you don't see any values when you output the variable is because PowerShell by default just converts objects to a string. The JsonValue
to string conversion is just an empty string, so it appears like a null value, but it's a full object.
The reason it throws the InvalidOperationException
referencing enumeration is because PowerShell tries to enumerate anything that implements IEnumerable
. But, JsonPrimitive
will throw when you try to enumerate it if the real value of the object isn't an array.
If you want to get an individual value, you can call the JsonPrimitive.ToValue
method. This will convert the JsonPrimitive
to the equivalent .NET type.
$jsonObject = [Hjson.HjsonValue]::Load("myFile.hjson")
$jsonObject['MyKey'].ToValue()
The problem with this is it will only work on keys you know are primitives. That means to do a full conversion to a normal displayable type you would have to enumerate the JsonValue
, check if it's a JsonPrimitive
or JsonObject
, then either call ToValue
or recurse into the nested object.
A simpler approach might be to just convert it to json as PowerShell is a lot better at handling that
$jsonObject = [Hjson.HjsonValue]::Load("myFile.hjson")
$stringWriter = [System.IO.StringWriter]::new()
$jsonObject.Save($stringWriter, [Hjson.Stringify]::Plain)
$hjsonAsPSObject = $stringWriter.GetStringBuilder().ToString() | ConvertFrom-Json
The Save
method takes a path, a stream, or a TextWriter
. The StringWriter
object is just an easy way to get a string from something that accepts a TextWriter
.
If you're ever faced with an object that you think should have a value but displays like it doesn't have a value, there's a solid chance it just doesn't display right in PowerShell. In this scenario, the easiest way you could have tested would be trying some of these:
# Shows you the objects type, or if it really is $null it will throw
$jsonObject['jsonKey'].GetType()
# This will tell you the properties and methods available on an object
# but in this case it would throw due to the enumeration funk.
$jsonObject['jsonKey'] | Get-Member
# This gets around the enumeration issue. Because there's no pipeline,
# Get-Member gives you the members for the type before enumeration.
Get-Member -InputObject ($jsonObject['jsonKey'])