├── .gitignore
├── LICENSE
├── README.md
├── json.vb
└── monero.png
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Visual Studio 2015 cache/options directory
25 | .vs/
26 | # Uncomment if you have tasks that create the project's static files in wwwroot
27 | #wwwroot/
28 |
29 | # MSTest test Results
30 | [Tt]est[Rr]esult*/
31 | [Bb]uild[Ll]og.*
32 |
33 | # NUNIT
34 | *.VisualState.xml
35 | TestResult.xml
36 |
37 | # Build Results of an ATL Project
38 | [Dd]ebugPS/
39 | [Rr]eleasePS/
40 | dlldata.c
41 |
42 | # DNX
43 | project.lock.json
44 | artifacts/
45 |
46 | *_i.c
47 | *_p.c
48 | *_i.h
49 | *.ilk
50 | *.meta
51 | *.obj
52 | *.pch
53 | *.pdb
54 | *.pgc
55 | *.pgd
56 | *.rsp
57 | *.sbr
58 | *.tlb
59 | *.tli
60 | *.tlh
61 | *.tmp
62 | *.tmp_proj
63 | *.log
64 | *.vspscc
65 | *.vssscc
66 | .builds
67 | *.pidb
68 | *.svclog
69 | *.scc
70 |
71 | # Chutzpah Test files
72 | _Chutzpah*
73 |
74 | # Visual C++ cache files
75 | ipch/
76 | *.aps
77 | *.ncb
78 | *.opendb
79 | *.opensdf
80 | *.sdf
81 | *.cachefile
82 |
83 | # Visual Studio profiler
84 | *.psess
85 | *.vsp
86 | *.vspx
87 | *.sap
88 |
89 | # TFS 2012 Local Workspace
90 | $tf/
91 |
92 | # Guidance Automation Toolkit
93 | *.gpState
94 |
95 | # ReSharper is a .NET coding add-in
96 | _ReSharper*/
97 | *.[Rr]e[Ss]harper
98 | *.DotSettings.user
99 |
100 | # JustCode is a .NET coding add-in
101 | .JustCode
102 |
103 | # TeamCity is a build add-in
104 | _TeamCity*
105 |
106 | # DotCover is a Code Coverage Tool
107 | *.dotCover
108 |
109 | # NCrunch
110 | _NCrunch_*
111 | .*crunch*.local.xml
112 | nCrunchTemp_*
113 |
114 | # MightyMoose
115 | *.mm.*
116 | AutoTest.Net/
117 |
118 | # Web workbench (sass)
119 | .sass-cache/
120 |
121 | # Installshield output folder
122 | [Ee]xpress/
123 |
124 | # DocProject is a documentation generator add-in
125 | DocProject/buildhelp/
126 | DocProject/Help/*.HxT
127 | DocProject/Help/*.HxC
128 | DocProject/Help/*.hhc
129 | DocProject/Help/*.hhk
130 | DocProject/Help/*.hhp
131 | DocProject/Help/Html2
132 | DocProject/Help/html
133 |
134 | # Click-Once directory
135 | publish/
136 |
137 | # Publish Web Output
138 | *.[Pp]ublish.xml
139 | *.azurePubxml
140 | # TODO: Comment the next line if you want to checkin your web deploy settings
141 | # but database connection strings (with potential passwords) will be unencrypted
142 | *.pubxml
143 | *.publishproj
144 |
145 | # NuGet Packages
146 | *.nupkg
147 | # The packages folder can be ignored because of Package Restore
148 | **/packages/*
149 | # except build/, which is used as an MSBuild target.
150 | !**/packages/build/
151 | # Uncomment if necessary however generally it will be regenerated when needed
152 | #!**/packages/repositories.config
153 | # NuGet v3's project.json files produces more ignoreable files
154 | *.nuget.props
155 | *.nuget.targets
156 |
157 | # Microsoft Azure Build Output
158 | csx/
159 | *.build.csdef
160 |
161 | # Microsoft Azure Emulator
162 | ecf/
163 | rcf/
164 |
165 | # Microsoft Azure ApplicationInsights config file
166 | ApplicationInsights.config
167 |
168 | # Windows Store app package directory
169 | AppPackages/
170 | BundleArtifacts/
171 |
172 | # Visual Studio cache files
173 | # files ending in .cache can be ignored
174 | *.[Cc]ache
175 | # but keep track of directories ending in .cache
176 | !*.[Cc]ache/
177 |
178 | # Others
179 | ClientBin/
180 | ~$*
181 | *~
182 | *.dbmdl
183 | *.dbproj.schemaview
184 | *.pfx
185 | *.publishsettings
186 | node_modules/
187 | orleans.codegen.cs
188 |
189 | # RIA/Silverlight projects
190 | Generated_Code/
191 |
192 | # Backup & report files from converting an old project file
193 | # to a newer Visual Studio version. Backup files are not needed,
194 | # because we have git ;-)
195 | _UpgradeReport_Files/
196 | Backup*/
197 | UpgradeLog*.XML
198 | UpgradeLog*.htm
199 |
200 | # SQL Server files
201 | *.mdf
202 | *.ldf
203 |
204 | # Business Intelligence projects
205 | *.rdl.data
206 | *.bim.layout
207 | *.bim_*.settings
208 |
209 | # Microsoft Fakes
210 | FakesAssemblies/
211 |
212 | # GhostDoc plugin setting file
213 | *.GhostDoc.xml
214 |
215 | # Node.js Tools for Visual Studio
216 | .ntvs_analysis.dat
217 |
218 | # Visual Studio 6 build log
219 | *.plg
220 |
221 | # Visual Studio 6 workspace options file
222 | *.opt
223 |
224 | # Visual Studio LightSwitch build output
225 | **/*.HTMLClient/GeneratedArtifacts
226 | **/*.DesktopClient/GeneratedArtifacts
227 | **/*.DesktopClient/ModelManifest.xml
228 | **/*.Server/GeneratedArtifacts
229 | **/*.Server/ModelManifest.xml
230 | _Pvt_Extensions
231 |
232 | # Paket dependency manager
233 | .paket/paket.exe
234 |
235 | # FAKE - F# Make
236 | .fake/
237 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 dday9
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # .NET-JSON-Transformer
3 | A Visual Basic .NET (VB.NET) implementation that converts a JSON literal into a .NET XDocument
4 |
5 | ## Add to project
6 | The [json.vb](json.vb) code file is uncompiled. Follow these instructions to add the file to your project:
7 |
8 | 1. Project > Add Existing Item (shift + alt + a)
9 | 2. Select the file in the
10 | browse dialog
11 | 3. Add
12 |
13 | ## Json.Parse Method
14 | Creates a new [XDocument](https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xdocument) from a JSON literal
15 |
16 | ``` vb
17 | Public Shared Function Parse(ByVal source As String, Optional culuture As CultureInfo) As XDocument
18 | ```
19 |
20 | ### Parameters
21 | `source` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
22 | A string that contains JSON.
23 |
24 | `culture`
25 | And optional parameter to specify the culture. This is used for culture specific parsing (e.g. commas used as decimal place)
26 |
27 | ### Returns
28 | [XDocument](https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xdocument)
29 | An [XDocument](https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xdocument) populated from the string that contains JSON.
30 |
31 | ### Example
32 | The following example illustrates the Json.Parse method:
33 | ``` vb
34 | Const literal = "{ ""Property1"": 1, ""Property2"": false }"
35 | Dim parsedJson = Json.Parse(literal)
36 | Console.WriteLine(parsedJson.ToString())
37 |
38 | '
52 | ```
53 |
54 | ## Remarks
55 | * The parser ignores whitespace, essentially minfying the JSON. For example, if the JSON literal is:
56 | ``` json
57 | {
58 | "glossary": {
59 | "title": "example glossary",
60 | "GlossDiv": {
61 | "title": "S",
62 | "GlossList": {
63 | "GlossEntry": {
64 | "ID": "SGML",
65 | "SortAs": "SGML",
66 | "GlossTerm": "Standard Generalized Markup Language",
67 | "Acronym": "SGML",
68 | "Abbrev": "ISO 8879:1986",
69 | "GlossDef": {
70 | "para": "A meta-markup language, used to create markup languages such as DocBook.",
71 | "GlossSeeAlso": ["GML", "XML"]
72 | },
73 | "GlossSee": "markup"
74 | }
75 | }
76 | }
77 | }
78 | }
79 | ```
80 | Then it gets parsed as:
81 | ``` json
82 | {"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}}
83 | ```
84 |
85 | * The returned XML is a 1-to-1 translation from the JSON. Using the same example as above, the resulting XML would be:
86 | ```
87 |
187 | ```
188 |
189 | * The parser does not parse to the exact specifications of the EBNF found on http://www.json.org/ the following list the deviations in this parser:
190 | * Number: Checks if the number starts with either a positive sign or negative sign
191 | * Boolean: Checks for "true" or "false" based on case-insensitivity
192 | * Null: Checks for "null" based on case-insensitivity
193 | * String: Does not check for "\u" followed by 4 hexadecimal characters as an escape character
194 |
195 | ## Examples and Demo
196 | The following example demonstrates the Parse method.
197 |
198 | ``` vb.net
199 | Public Module Module1
200 |
201 | Public Sub Main()
202 | Const literal = "{
203 | ""glossary"": {
204 | ""title"": ""example glossary"",
205 | ""GlossDiv"": {
206 | ""title"": ""S"",
207 | ""GlossList"": {
208 | ""GlossEntry"": {
209 | ""ID"": ""SGML"",
210 | ""SortAs"": ""SGML"",
211 | ""GlossTerm"": ""Standard Generalized Markup Language"",
212 | ""Acronym"": ""SGML"",
213 | ""Abbrev"": ""ISO 8879:1986"",
214 | ""GlossDef"": {
215 | ""para"": ""A meta-markup language, used to create markup languages such as DocBook."",
216 | ""GlossSeeAlso"": [""GML"", ""XML""]
217 | },
218 | ""GlossSee"": ""markup""
219 | }
220 | }
221 | }
222 | }
223 | }"
224 | Dim parsedJson = Json.Parse(literal)
225 | Console.WriteLine(parsedJson.ToString())
226 | Console.ReadLine()
227 | End Sub
228 |
229 | End Module
230 | ```
231 | Fiddle: [https://dotnetfiddle.net/FqqPnW](https://dotnetfiddle.net/1YUHJo)
232 |
233 | ## Donate
234 | Show your support! Your (non-tax deductible) donation of Monero cryptocurrency is a sign of solidarity among web developers.
235 |
236 | Being self taught, I have come a long way over the years. I certainly do not intend on making a living from this free feature, but my hope is to earn a few dollars to validate all of my hard work.
237 |
238 | Monero Address: 447SPi8XcexZnF7kYGDboKB6mghWQzRfyScCgDP2r4f2JJTfLGeVcFpKEBT9jazYuW2YG4qn51oLwXpQJ3oEXkeXUsd6TCF
239 |
240 | 
241 |
--------------------------------------------------------------------------------
/json.vb:
--------------------------------------------------------------------------------
1 | Imports System.Globalization
2 |
3 | Public Class Json
4 |
5 | Public Const COLON As Char = ":"c
6 | Public Const COMMA As Char = ","c
7 | Public Const CLOSE_BRACE As Char = "}"c
8 | Public Const CLOSE_BRACKET As Char = "]"c
9 | Public Const DOUBLE_QUOTE As Char = """"c
10 | Public Const ESCAPED_CHARACTERS As String = DOUBLE_QUOTE & "\/bfnrt"
11 | Public Const NULL_LITERAL As String = "null"
12 | Public Const OPEN_BRACE As Char = "{"c
13 | Public Const OPEN_BRACKET As Char = "["c
14 |
15 | '''
16 | ''' Creates a new from a JSON literal
17 | '''
18 | ''' A string that contains JSON.
19 | '''
20 | ''' An populated from the string that contains JSON.
21 | Public Shared Function Parse(source As String, Optional culture As CultureInfo = Nothing) As XDocument
22 | 'Remove any whitespace
23 | source = source.Trim()
24 | If String.IsNullOrWhiteSpace(source) Then
25 | Return Nothing
26 | End If
27 |
28 | Dim value = ParseValue(source, 0, culture)
29 | Dim document = If(value IsNot Nothing, New XDocument(New XDeclaration("1.0", "utf-8", "yes"), value), Nothing)
30 |
31 | Return document
32 | End Function
33 |
34 | '''
35 | ''' Creates a new from a JSON literal at given index
36 | '''
37 | ''' A string that contains JSON.
38 | ''' The position of the JSON where the parsing will begin.
39 | ''' An populated from the string that contains JSON.
40 | ''' 1. will increment if the parse is successful.
41 | ''' 2. Nothing will be returned if the parse is not successful.
42 | Private Shared Function ParseValue(source As String, ByRef index As Integer, Optional culture As CultureInfo = Nothing) As XElement
43 | 'Declare a temporary placeholder and skip any whitespace
44 | Dim tempIndex = SkipWhitespace(source, index)
45 |
46 | 'Go through each available value until one returns something that isn't null
47 | Dim value = ParseObject(source, tempIndex, culture)
48 | If (value Is Nothing) Then
49 | value = ParseArray(source, tempIndex, culture)
50 | If (value Is Nothing) Then
51 | value = ParseString(source, tempIndex)
52 | If (value Is Nothing) Then
53 | value = ParseNumber(source, tempIndex, culture)
54 | If (value Is Nothing) Then
55 | value = ParseBoolean(source, tempIndex)
56 | If (value Is Nothing) Then
57 | value = ParseNull(source, tempIndex)
58 | End If
59 | End If
60 | End If
61 | End If
62 | End If
63 |
64 | 'Change the index
65 | index = tempIndex
66 |
67 | 'Return the value
68 | Return value
69 | End Function
70 |
71 | '''
72 | ''' Creates a new from a JSON literal at given index where the expected JSON type is an Object
73 | '''
74 | ''' A string that contains JSON.
75 | ''' The position of the JSON where the parsing will begin.
76 | ''' An populated from the string that contains JSON.
77 | ''' 1. will increment if the parse is successful.
78 | ''' 2. Nothing will be returned if the parse is not successful.
79 | Private Shared Function ParseObject(source As String, ByRef index As Integer, Optional culture As CultureInfo = Nothing) As XElement
80 | 'Declare a value to return
81 | Dim value As XElement = Nothing
82 |
83 | 'Declare a temporary placeholder
84 | Dim tempIndex = index
85 |
86 | 'Check for the starting opening curly bracket
87 | If source(tempIndex).Equals(OPEN_BRACE) Then
88 | 'Increment the index
89 | tempIndex += 1
90 |
91 | 'Declare a collection that will make up the nodes' value
92 | Dim nodes = New List(Of Tuple(Of String, XElement))
93 |
94 | 'Declare an XElement to store the key (aka - name) of the KeyValuePair
95 | Dim key As XElement
96 |
97 | 'Declare an XElement which will represent the value of the KeyValuePair
98 | Dim item As XElement
99 |
100 | 'Loop until we've reached the end of the source or until we've hit the ending bracket
101 | Do While (tempIndex < source.Length AndAlso Not source(tempIndex).Equals(CLOSE_BRACE))
102 | 'Increment the index and skip any unneeded whitespace
103 | tempIndex = SkipWhitespace(source, tempIndex)
104 |
105 | 'Attempt to parse the String
106 | key = ParseString(source, tempIndex)
107 |
108 | 'Check if the parse was successful
109 | If (key Is Nothing) Then
110 | Throw New Exception($"Expected a String instead of a '{source(tempIndex)}' at position: {tempIndex}.")
111 | Else
112 | 'Skip any unneeded whitespace
113 | tempIndex = SkipWhitespace(source, tempIndex)
114 |
115 | If (tempIndex < source.Length) Then
116 | 'Check if the currently iterated character is a object separator ':'
117 | If (source(tempIndex) = COLON) Then
118 | 'Increment the index and skip any unneeded whitespace
119 | tempIndex = SkipWhitespace(source, tempIndex + 1)
120 |
121 | If (tempIndex < source.Length) Then
122 | 'Assign the item to the parsed value
123 | item = ParseValue(source, tempIndex, culture)
124 |
125 | 'Check if the parse was successful
126 | If (item Is Nothing) Then
127 | Throw New Exception($"Unexpected character '{source(tempIndex)}' at position: {tempIndex}.")
128 | Else
129 | 'Add the item to the collection
130 | nodes.Add(New Tuple(Of String, XElement)(key.Value, item))
131 |
132 | 'Skip any unneeded whitespace
133 | tempIndex = SkipWhitespace(source, tempIndex)
134 |
135 | 'Check if we can continue
136 | If (tempIndex < source.Length) Then
137 | 'Check if the currently iterated character is either a item separator (comma) or ending curly bracket
138 | If (source(tempIndex).Equals(COMMA)) Then
139 | 'Increment the index and skip any unneeded whitespace
140 | tempIndex = SkipWhitespace(source, tempIndex + 1)
141 | ElseIf (source(tempIndex) <> CLOSE_BRACE) Then
142 | Throw New Exception($"Expected a ',' instead of a '{source(tempIndex)}' at position: {tempIndex}.")
143 | End If
144 | End If
145 | End If
146 | Else
147 | Throw New Exception("Expected an Object, Array, String, Number, Boolean, or Null instead I reached the end of the source code.")
148 | End If
149 | Else
150 | Throw New Exception($"Expected a ':' instead of a '{source(tempIndex)}' at position: {tempIndex}.")
151 | End If
152 | Else
153 | Throw New Exception("Expected a ',' instead I reached the end of the source code.")
154 | End If
155 | End If
156 | Loop
157 |
158 | 'Check if the currently iterated value is an ending curly bracket
159 | If (tempIndex < source.Length AndAlso source(tempIndex) = CLOSE_BRACE) Then
160 | 'Increment the index
161 | tempIndex += 1
162 |
163 | 'Set the new index
164 | index = tempIndex
165 |
166 | 'Create the Object
167 | value = New XElement("object")
168 |
169 | 'Iterate through each item in the nodes
170 | Dim objectItem, objectKey, objectValue As XElement
171 | For Each n As Tuple(Of String, XElement) In nodes
172 | objectKey = New XElement("key", n.Item1)
173 | objectValue = New XElement("value", n.Item2)
174 |
175 | objectItem = New XElement("item", {objectKey, objectValue})
176 | value.Add(objectItem)
177 | Next
178 | End If
179 | End If
180 |
181 | 'Return the value
182 | Return value
183 | End Function
184 |
185 | '''
186 | ''' Creates a new from a JSON literal at given index where the expected JSON type is an array
187 | '''
188 | ''' A string that contains JSON.
189 | ''' The position of the JSON where the parsing will begin.
190 | ''' An populated from the string that contains JSON.
191 | ''' 1. will increment if the parse is successful.
192 | ''' 2. Nothing will be returned if the parse is not successful.
193 | Private Shared Function ParseArray(source As String, ByRef index As Integer, Optional culture As CultureInfo = Nothing) As XElement
194 | 'Declare a value to return
195 | Dim value As XElement = Nothing
196 |
197 | 'Declare a temporary placeholder
198 | Dim tempIndex As Integer = index
199 |
200 | 'Check for the starting opening bracket
201 | If (source(tempIndex).Equals(OPEN_BRACKET)) Then
202 | 'Increment the index
203 | tempIndex += 1
204 |
205 | 'Declare a collection that will make up the nodes' value
206 | Dim nodes = New List(Of XElement)
207 |
208 | 'Declare an XElement which will represent the currently iterated item in the array
209 | Dim item As XElement
210 |
211 | 'Loop until we've reached the end of the source or until we've hit the ending bracket
212 | Do While (tempIndex < source.Length AndAlso Not source(tempIndex).Equals(CLOSE_BRACKET))
213 | 'Assign the item to the parsed value
214 | item = ParseValue(source, tempIndex, culture)
215 |
216 | 'Check if the parse was successful
217 | If (item Is Nothing) Then
218 | Throw New Exception($"Unexpected character '{source(tempIndex)}' at position: {tempIndex}.")
219 | Else
220 | 'Add the item to the collection
221 | nodes.Add(item)
222 |
223 | 'Skip any unneeded whitespace
224 | tempIndex = SkipWhitespace(source, tempIndex)
225 |
226 | 'Check if we can continue
227 | If (tempIndex < source.Length) Then
228 | 'Check if the currently iterated character is either a item separator (comma) or ending bracket
229 | If (source(tempIndex).Equals(COMMA)) Then
230 | 'Increment the index and skip any unneeded whitespace
231 | tempIndex = SkipWhitespace(source, tempIndex + 1)
232 | ElseIf (source(tempIndex) <> CLOSE_BRACKET) Then
233 | Throw New Exception($"Expected a ',' instead of a '{source(tempIndex)}' at position: {tempIndex}.")
234 | End If
235 | End If
236 | End If
237 | Loop
238 |
239 | 'Check if the currently iterated value is an ending bracket
240 | If (tempIndex < source.Length AndAlso source(tempIndex) = CLOSE_BRACKET) Then
241 | 'Increment the index
242 | tempIndex += 1
243 |
244 | 'Set the new index
245 | index = tempIndex
246 |
247 | 'Create the Array
248 | value = New XElement("array", nodes)
249 | End If
250 | End If
251 |
252 | Return value
253 | End Function
254 |
255 | '''
256 | ''' Creates a new from a JSON literal at given index where the expected JSON type is a String
257 | '''
258 | ''' A string that contains JSON.
259 | ''' The position of the JSON where the parsing will begin.
260 | ''' An populated from the string that contains JSON.
261 | ''' 1. will increment if the parse is successful.
262 | ''' 2. Nothing will be returned if the parse is not successful.
263 | ''' 3. The parser deviates from ECMA-404 by not checking for "\u" followed by 4 hexadecimal characters as an escape character
264 | Private Shared Function ParseString(source As String, ByRef index As Integer) As XElement
265 | 'Declare a value to return
266 | Dim value As XElement = Nothing
267 |
268 | 'Declare a temporary placeholder
269 | Dim tempIndex As Integer = index
270 |
271 | 'Check for the starting double-quote
272 | If (source(tempIndex).Equals(DOUBLE_QUOTE)) Then
273 | 'Increment the index
274 | tempIndex += 1
275 |
276 | 'Loop until we've reached the end of the source or until we've hit the ending double-quote
277 | Do While (tempIndex < source.Length AndAlso Not source(tempIndex).Equals(DOUBLE_QUOTE))
278 | 'Check if we're at an escaped character
279 | If (source(tempIndex) = "\"c AndAlso
280 | tempIndex + 1 < source.Length AndAlso
281 | ESCAPED_CHARACTERS.IndexOf(source(tempIndex + 1)) <> -1) Then
282 | tempIndex += 1
283 | ElseIf (source(tempIndex) = "\"c) Then
284 | Throw New Exception("Unescaped backslash in a String. Position: " & index)
285 | End If
286 |
287 | 'Increment the index
288 | tempIndex += 1
289 | Loop
290 |
291 | 'Check if the currently iterated character is a double-quote
292 | If (tempIndex < source.Length AndAlso source(tempIndex).Equals(DOUBLE_QUOTE)) Then
293 | 'Increment the index
294 | tempIndex += 1
295 |
296 | 'Create the String
297 | value = New XElement("string", source.Substring(index + 1, tempIndex - index - 2))
298 |
299 | 'Set the new index
300 | index = tempIndex
301 | End If
302 | End If
303 |
304 | Return value
305 | End Function
306 |
307 | '''
308 | ''' Creates a new from a JSON literal at given index where the expected JSON type is a number
309 | '''
310 | ''' A string that contains JSON.
311 | ''' The position of the JSON where the parsing will begin.
312 | ''' An populated from the string that contains JSON.
313 | ''' 1. will increment if the parse is successful.
314 | ''' 2. Nothing will be returned if the parse is not successful.
315 | ''' 3. The parser deviates from ECMA-404 by checking for an optional unary positive sign operator
316 | Private Shared Function ParseNumber(source As String, ByRef index As Integer, Optional culture As CultureInfo = Nothing) As XElement
317 | 'Get the current culture information
318 | If (culture Is Nothing) Then
319 | culture = CultureInfo.CurrentCulture
320 | End If
321 |
322 | 'Declare a temporary placeholder
323 | Dim tempIndex = index
324 |
325 | 'Check for the optional unary operator
326 | If (source.IndexOf(culture.NumberFormat.NegativeSign, tempIndex, StringComparison.OrdinalIgnoreCase) = tempIndex OrElse
327 | source.IndexOf(culture.NumberFormat.PositiveSign, tempIndex, StringComparison.OrdinalIgnoreCase) = tempIndex) Then
328 | tempIndex += 1
329 | End If
330 |
331 | 'Match one or more digits
332 | If (tempIndex < source.Length AndAlso Array.IndexOf(culture.NumberFormat.NativeDigits, source(tempIndex).ToString()) <> -1) Then
333 | Do While (tempIndex < source.Length AndAlso Array.IndexOf(culture.NumberFormat.NativeDigits, source(tempIndex).ToString()) <> -1)
334 | tempIndex += 1
335 | Loop
336 | Else
337 | Return Nothing
338 | End If
339 |
340 | 'Optionally match a decimal separator followed by one or more digits
341 | If (tempIndex + 1 < source.Length AndAlso
342 | source.IndexOf(culture.NumberFormat.NumberDecimalSeparator, tempIndex, StringComparison.OrdinalIgnoreCase) = tempIndex AndAlso
343 | Array.IndexOf(culture.NumberFormat.NativeDigits, source(tempIndex + 1).ToString()) <> -1) Then
344 |
345 | tempIndex += 1
346 | Do While (tempIndex < source.Length AndAlso Array.IndexOf(culture.NumberFormat.NativeDigits, source(tempIndex).ToString()) <> -1)
347 | tempIndex += 1
348 | Loop
349 | End If
350 |
351 | 'Optionally match an exponent, followed by an optional unary operator, followed by 1 or more digits
352 | If (tempIndex + 1 < source.Length AndAlso
353 | source.IndexOf("e", tempIndex, StringComparison.OrdinalIgnoreCase) = tempIndex) Then
354 |
355 | If (tempIndex + 2 < source.Length) AndAlso
356 | (source.IndexOf(culture.NumberFormat.NegativeSign, tempIndex + 1, StringComparison.OrdinalIgnoreCase) = tempIndex + 1 OrElse
357 | source.IndexOf(culture.NumberFormat.PositiveSign, tempIndex + 1, StringComparison.OrdinalIgnoreCase) = tempIndex + 1) AndAlso
358 | Array.IndexOf(culture.NumberFormat.NativeDigits, source(tempIndex + 2).ToString()) <> -1 Then
359 | tempIndex += 2
360 | ElseIf (tempIndex + 1 < source.Length AndAlso Array.IndexOf(culture.NumberFormat.NativeDigits, source(tempIndex + 1).ToString()) <> -1) Then
361 | tempIndex += 1
362 | End If
363 |
364 | Do While (tempIndex < source.Length AndAlso Array.IndexOf(culture.NumberFormat.NativeDigits, source(tempIndex).ToString()) <> -1)
365 | tempIndex += 1
366 | Loop
367 | End If
368 |
369 | 'Create the number
370 | Dim value = New XElement("number", source.Substring(index, tempIndex - index))
371 | index = tempIndex
372 |
373 | Return value
374 | End Function
375 |
376 | '''
377 | ''' Creates a new from a JSON literal at given index where the expected JSON type is a boolean
378 | '''
379 | ''' A string that contains JSON.
380 | ''' The position of the JSON where the parsing will begin.
381 | ''' An populated from the string that contains JSON.
382 | ''' 1. will increment if the parse is successful.
383 | ''' 2. Nothing will be returned if the parse is not successful.
384 | ''' 3. The parser deviates from ECMA-404 by ignoring the casing
385 | Private Shared Function ParseBoolean(source As String, ByRef index As Integer) As XElement
386 | Dim value As XElement = Nothing
387 |
388 | 'Literally match 'true' or 'false'
389 | If source.IndexOf(Boolean.TrueString, index, StringComparison.OrdinalIgnoreCase) = index Then
390 | value = New XElement("boolean", True)
391 | index += 4
392 | ElseIf source.IndexOf(Boolean.FalseString, index, StringComparison.OrdinalIgnoreCase) = index Then
393 | value = New XElement("boolean", False)
394 | index += 5
395 | End If
396 |
397 | Return value
398 | End Function
399 |
400 | '''
401 | ''' Creates a new from a JSON literal at given index where the expected JSON type is the literal "null"
402 | '''
403 | ''' A string that contains JSON.
404 | ''' The position of the JSON where the parsing will begin.
405 | ''' An populated from the string that contains JSON.
406 | ''' 1. will increment if the parse is successful.
407 | ''' 2. Nothing will be returned if the parse is not successful.
408 | ''' 3. The parser deviates from ECMA-404 by ignoring the casing
409 | Private Shared Function ParseNull(source As String, ByRef index As Integer) As XElement
410 | Dim value As XElement = Nothing
411 |
412 | 'Literally match 'null' in the source starting at the index
413 | If source.IndexOf(NULL_LITERAL, index, StringComparison.OrdinalIgnoreCase) = index Then
414 | value = New XElement(NULL_LITERAL)
415 | index += 4
416 | End If
417 |
418 | Return value
419 | End Function
420 |
421 | '''
422 | ''' Starting at a given index, skip any character that is whitespace
423 | '''
424 | ''' A string that contains JSON.
425 | ''' The position of the JSON where the whitespace check will begin
426 | ''' An Integer where the first character of , starting at , is not whitespace.
427 | Private Shared Function SkipWhitespace(source As String, ByRef index As Integer) As Integer
428 | Do While (index < source.Length AndAlso Char.IsWhiteSpace(source(index)))
429 | index += 1
430 | Loop
431 |
432 | Return index
433 | End Function
434 |
435 | End Class
436 |
437 |
--------------------------------------------------------------------------------
/monero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dday9/.NET-JSON-Transformer/4fb4722a73ccd5d73e66716351a55c62f5cc666d/monero.png
--------------------------------------------------------------------------------