Does anybody have a solution? The current output really doesn’t play well with diff engines.
It has to work in the new framework without plugins, which makes the task especially difficult. If there is an engine out there I could potentially port, I’d be interested, but I haven’t found one yet.
I have a plugin…
You could optionally use it to parse a JSON and output it formatted.
like this:
dim j as new JSONMBS("{""Hello"":1}")
MsgBox j.toString(true)
I wonder if you could do similar with some regex search & replaces.
Could you run it though the classic framework just for formatting?
It’s much too slow. Also means the behavior would be different between ios and non-ios.
Not sure if this is helpful, but I ported a C# JSON formatter a while back. It formats text so doesn’t depend on a framework:
https://blog.xojo.com/2015/08/14/format-json/
[quote=332429:@Paul Lefebvre]Not sure if this is helpful, but I ported a C# JSON formatter a while back. It formats text so doesn’t depend on a framework:
https://blog.xojo.com/2015/08/14/format-json/[/quote]
Exactly what I was hoping for. Assuming it’s fast enough, I’ll find out.
FYI, JSONFormatter.WriteCurrentLine uses EndOfLine which is a classic framework thing, so that should be changed. Luckily, that’s a piece of cake.
Damn. Looks like it’s too slow for my needs. Took over 2 minutes to convert the output.
Well, at the very least, I put in a feature request. <https://xojo.com/issue/48162>
Without having looked at the code Paul referenced, doing this in code is pretty easy. Shift the characters from the source to the destination according to these rules:
- Add quotes and everything between them (included escaped quotes) as-is.
- Ignore whitespace.
- Add “,” as “,” + EOL + indent.
- Add “:” as space + “:” + space.
- On “{” or “[”, increment the indent, then add the character + EOL + indent.
- On “}” or “]”, decrement the indent, then add EOL + indent + character.
- Add anything else as-is.
I have the code for this lying around somewhere and, as I recall, it was pretty quick.
Here it is as code:
Public Function JSONPrettyPrint(json As Text) as Text
const kBuffer as text = " "
const kEOL as text = &u0A
dim outArr() as text
dim indents( 0 ) as text
dim addAsIs as boolean
dim inQuote as boolean
for each char as text in json.Characters
if addAsIs then
outArr.Append char
addAsIs = false
elseif char = """" then
outArr.Append char
inQuote = not inQuote
elseif inQuote then
outArr.Append char
if char = "\" then
addAsIs = true
end if
elseif char = "{" or char = "[" then
indents.Append indents( indents.Ubound ) + kBuffer
outArr.Append char
outArr.Append kEOL
outArr.Append indents( indents.Ubound )
elseif char = "}" or char = "]" then
call indents.Pop
outArr.Append kEOL
outArr.Append indents( indents.Ubound )
outArr.Append char
elseif char = "," then
outArr.Append char
outArr.Append kEOL
outArr.Append indents( indents.Ubound )
elseif char = ":" then
outArr.Append " : "
elseif char = &u0A or char = &u0D or char = " " or char = &u09 then
//
// Skip it
//
else
outArr.Append char
end if
next
dim result as text = Text.Join( outArr, "" )
return result
End Function
5MB in about 2 seconds. I don’t think I’m going to see results better than that, except maybe once my feature request is implemented. Thank you very much Kem.
have you tried #pragma to disable background tasks.
and put json.Characters in a local variable first.
On a Mac, right? I expect it will be much slower than that on Windows/Linux. If this isn’t for iOS, convert to String and back.
[quote=332508:@Christian Schmitz]have you tried #pragma to disable background tasks.
and put json.Characters in a local variable first.
[/quote]
The way For Each works, I don’t think that matters.
Good point, I’ll need to test on Windows too. This is sometimes for iOS, so I try to avoid the classic framework whenever possible since Xojo hasn’t given us proper compilation constants to determine if the classic framework is available. We currently need to use #if Not TargetiOS, which is currently correct, but isn’t guaranteed to be in the future, such as when Android is released.
So for the record, when I tested on Windows, the result was impossibly slow. What would take about 2 seconds on Mac was taking longer than I could measure on Windows. Gave up waiting after what seemed like 10 minutes.
I finally got around to using a memoryblock. Times are now pretty consistent, with the time on Mac down to about 400ms and Windows to about 600ms.
[code]Function JSONPrettyPrint(json As Text) as Text
Const Indent = &h09
Const EndOfLine = &h0A
Dim Bytes() As UInt8
Dim Indents As UInteger
Dim AddAsIs, InQuote As Boolean
Dim Mem As Xojo.Core.MemoryBlock = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(JSON)
Dim Bound As UInteger = Mem.Size - 1
For Offset As UInteger = 0 To Bound
Dim Char As UInt8 = Mem.UInt8Value(Offset)
If AddAsIs Then
Bytes.Append(Char)
AddAsIs = False
ElseIf Char = &h22 Then
Bytes.Append(Char)
InQuote = Not InQuote
ElseIf InQuote Then
Bytes.Append(Char)
If Char = &h5C Then
AddAsIs = True
End If
ElseIf Char = &h7B Or Char = &h5B Then
Indents = Indents + 1
Bytes.Append(Char)
Bytes.Append(EndOfLine)
For I As UInteger = 1 To Indents
Bytes.Append(Indent)
Next
ElseIf Char = &h7D Or Char = &h5D Then
Indents = Indents - 1
Bytes.Append(EndOfLine)
For I As UInteger = 1 To Indents
Bytes.Append(Indent)
Next
Bytes.Append(Char)
ElseIf Char = &h2C Then
Bytes.Append(Char)
Bytes.Append(EndOfLine)
For I As UInteger = 1 To Indents
Bytes.Append(Indent)
Next
ElseIf Char = &h3A Then
Bytes.Append(Char)
Bytes.Append(&h20)
ElseIf Char = &h0A Or Char = &h0D Or Char = &h20 Or Char = &h09 Then
// Skip it
Else
Bytes.Append(Char)
End If
Next
Return Xojo.Core.TextEncoding.UTF8.ConvertDataToText(New Xojo.Core.MemoryBlock(Bytes))
End Function[/code]
Nice. You might gain a bit more if you access the bytes directly through the pointer rather than using the function. Store a reference to the pointer first, of course.
This is a nice project, but don’t understand why you need it.
I did a project with quite some json output last week and just used Notepadd++ with the Json plugin. All for free and perfect for the job. Think there must be a Mac tool somewhere too.
And, if you don’t want or have a tool locally, this one also does the job very well.
one reason :
MESSAGE
File size is not supported more 1MB
I need it happen dynamically.
The reason is my document format is JSON. But a single-line JSON string doesn’t work nicely with version control. So I’ve had users request a “pretty” version to solve that problem, which I think is a perfectly valid request. Telling them to bring it to a website after saving is not a solution.
Pointer stuff is an area I never really got into, so what you’re describing is foreign to me. If I had to guess, you mean something like
Dim Mem As Xojo.Core.MemoryBlock = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(JSON)
Dim Bound As UInteger = Mem.Size - 1
Dim Pointer As Ptr = Mem
For Offset As UInteger = 0 To Bound
Dim Char As UInt8 = Pointer.UInt8(Offset)
Next
But I can’t assign a Xojo.Core.MemoryBlock to a Ptr, though the docs tell me I should be able to.