├── .gitignore ├── LICENSE ├── README.md ├── README_CN.md ├── Src ├── STLib.Json.Test │ ├── Program.cs │ ├── STJsonTestObject.cs │ └── STLib.Json.Test.csproj ├── STLib.Json.sln ├── STLib.Json │ ├── DevLog.txt │ ├── Extensions │ │ ├── STJson.Static.Extensions.cs │ │ ├── STJsonAggregateException.cs │ │ ├── STJsonCreator.cs │ │ └── STJsonExtensions.cs │ ├── STJson │ │ ├── Attributes │ │ │ ├── STJsonAttribute.cs │ │ │ ├── STJsonConverterAttribute.cs │ │ │ └── STJsonPropertyAttribute.cs │ │ ├── Converter │ │ │ ├── FPInfo.cs │ │ │ ├── ObjectToSTJson.cs │ │ │ ├── ObjectToString.cs │ │ │ ├── STJsonBuildInConverter.cs │ │ │ ├── STJsonConverter.cs │ │ │ └── STJsonToObject.cs │ │ ├── Entities │ │ │ ├── Enums │ │ │ │ ├── STJsonSerializeMode.cs │ │ │ │ └── STJsonValueType.cs │ │ │ └── Structures │ │ │ │ └── STJsonTypeMapInfo.cs │ │ ├── Exceptions │ │ │ ├── STJsonCastException.cs │ │ │ ├── STJsonException.cs │ │ │ ├── STJsonParseException.cs │ │ │ └── STJsonWriterException.cs │ │ ├── Parser │ │ │ ├── Entities │ │ │ │ ├── Enums │ │ │ │ │ └── STJsonTokenType.cs │ │ │ │ └── Structures │ │ │ │ │ └── STJsonToken.cs │ │ │ ├── STJsonParser.cs │ │ │ ├── STJsonTokenReader.cs │ │ │ └── STJsonTokenizer.cs │ │ ├── Parser_backup │ │ │ ├── STJsonParserOld.cs │ │ │ └── STJsonTokenizerOld.cs │ │ ├── STJson.Static.cs │ │ ├── STJson.cs │ │ ├── STJsonReader.cs │ │ ├── STJsonReaderItem.cs │ │ ├── STJsonSetting.cs │ │ └── STJsonWriter.cs │ ├── STJsonPath │ │ ├── Exceptions │ │ │ ├── STJsonPathException.cs │ │ │ └── STJsonPathParseException.cs │ │ ├── STJsonPath.DataType.cs │ │ ├── STJsonPath.Static.cs │ │ ├── STJsonPath.cs │ │ ├── STJsonPathBuildInFunctions.cs │ │ ├── STJsonPathExpressParser.cs │ │ ├── STJsonPathExpression.cs │ │ ├── STJsonPathItem.cs │ │ ├── STJsonPathParser.cs │ │ └── STJsonPathTokenizer.cs │ └── STLib.Json.csproj └── sources │ ├── LICENSE │ ├── README.md │ └── STJson.icon.png └── docs ├── css ├── index.css └── stdoc.css ├── favicon.png ├── images ├── STJson.icon.png ├── banner.jpg ├── good.webp └── st_logo.svg ├── index.html ├── js ├── jquery-1.10.2.min.js └── stdoc.js ├── tutorial_cn.html ├── tutorial_cn.txt ├── tutorial_en.html └── tutorial_en.txt /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 DebugST 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 | [简体中文](./README_CN.md) [English](./README.md) 2 | 3 | # Introduction 4 | 5 | `STJson` is a `Json` parsing library based on the `MIT` open source protocol . The library is purely native implementation does not rely on any library , so it is very light and convenient , and powerful . 6 | 7 | HOME: [https://DebugST.github.io/STJson](https://DebugST.github.io/STJson) 8 | 9 | NuGet: [https://www.nuget.org/packages/STLib.Json](https://www.nuget.org/packages/STLib.Json) 10 | 11 | Unlike other `Json` libraries, `STJson` not has objects similar to `JObject` and `JArray`. Just `STJson`. which can be either `Object` or `Array`. `STJson` has two indexers: `STJson[int]` and `STJson[string]`. The type of the current `Json` object can be determined by `STJson.ValueType`. 12 | 13 | ```cs 14 | var json_1 = new STJson(); 15 | Console.WriteLine("[json_1] - " + json_1.IsNullValue + " - " + json_1.ValueType); 16 | 17 | var json_2 = STJson.New(); 18 | json_2.SetItem("key", "value"); 19 | Console.WriteLine("[json_2] - " + json_2.IsNullValue + " - " + json_2.ValueType); 20 | 21 | var json_3 = new STJson(); 22 | json_3.Append(1, 2, 3); 23 | Console.WriteLine("[json_3] - " + json_3.IsNullValue + " - " + json_3.ValueType); 24 | 25 | var json_4 = new STJson(); 26 | json_4.SetValue(DateTime.Now); 27 | Console.WriteLine("[json_4] - " + json_4.IsNullValue + " - " + json_4.ValueType); 28 | 29 | var json_5 = STJson.CreateArray(); // made by static function 30 | Console.WriteLine("[json_5] - " + json_5.IsNullValue + " - " + json_5.ValueType); 31 | 32 | var json_6 = STJson.CreateObject(); // made by static function 33 | Console.WriteLine("[json_6] - " + json_6.IsNullValue + " - " + json_6.ValueType); 34 | 35 | var json_7 = STJson.FromObject(12); // made by static function 36 | Console.WriteLine("[json_3] - " + json_7.IsNullValue + " - " + json_7.ValueType); 37 | /******************************************************************************* 38 | * [output] * 39 | *******************************************************************************/ 40 | [json_1] - True - Undefined 41 | [json_2] - False - Object 42 | [json_3] - False - Array 43 | [json_4] - False - Datetime 44 | [json_5] - False - Array 45 | [json_6] - False - Object 46 | [json_7] - False - Long 47 | ``` 48 | 49 | # STJson 50 | 51 | `STJson` is an intermediate data type that is a bridge between `string` and `object` and is very convenient to use, e.g: 52 | 53 | ```cs 54 | var st_json = new STJson() 55 | .SetItem("number", 0) // The function returns itself so it can be operated continuously. 56 | .SetItem("boolean", true) 57 | .SetItem("string", "this is string") 58 | .SetItem("datetime", DateTime.Now) 59 | .SetItem("array_1", STJson.CreateArray(123, true, "string")) 60 | .SetItem("array_2", STJson.FromObject(new object[] { 123, true, "string" })) 61 | .SetItem("object", new { key = "this is a object" }) 62 | .SetItem("null", obj: null); 63 | st_json.SetKey("key").SetValue("this is a test"); 64 | Console.WriteLine(st_json.ToString(4)); // 4 -> indentation space count 65 | /******************************************************************************* 66 | * [output] * 67 | *******************************************************************************/ 68 | { 69 | "number": 0, 70 | "boolean": true, 71 | "string": "this is string", 72 | "datetime": "2023-04-22T21:12:30.6109410+08:00", 73 | "array_1": [ 74 | 123, true, "string" 75 | ], 76 | "array_2": [ 77 | 123, true, "string" 78 | ], 79 | "object": { 80 | "key": "this is a object" 81 | }, 82 | "null": null, 83 | "key": "this is a test" 84 | } 85 | ``` 86 | 87 | # Serialize 88 | 89 | By the above example maybe you already know how to convert an object to `string`, by `STJson.FromObject(object).ToString(+n)`, but is it possible that it actually doesn't need to be so troublesome? For example: `STJson.Serialize(+n)` will do? 90 | 91 | In fact `STJson.Serialize(+n)` would be more efficient because it converts the object directly to a string, rather than converting it to `STJson` and then to a string. 92 | 93 | ```cs 94 | Console.WriteLine(STJson.Serialize(new { key = "this is test" })); 95 | /******************************************************************************* 96 | * [output] * 97 | *******************************************************************************/ 98 | {"key":"this is test"} 99 | ``` 100 | 101 | Of course you can have a more friendly output format: 102 | 103 | ```cs 104 | Console.WriteLine(STJson.Serialize(new { key = "this is test" }, 4)); 105 | /******************************************************************************* 106 | * [output] * 107 | *******************************************************************************/ 108 | { 109 | "key": "this is test" 110 | } 111 | ``` 112 | 113 | In fact formatting the output is done by calling the static function `STJson.Format(+n)`. If you don't like the author's built-in formatting style, you can write a formatting function of your own. Or go modify the source file `STJson.Statics.cs:Format(string,int)`. 114 | 115 | # Deserialize 116 | 117 | The code doesn't actually convert `string` to `object` directly. It has to parse the string to make sure it's a properly formatted `Json` before it does that. But by the time this is done, you'll already have an `STJson` object. Finally, `STJson` is converted to `object` again. 118 | 119 | So you will see the following files in the source code `STLib.Json.Converter`: 120 | 121 | `ObjectToSTJson.cs` `ObjectToString.cs` `STJsonToObject.cs` `StringToSTJson.cs` 122 | 123 | There is no `StringToObject.cs` file inside, and the source code of `STJson.Deserialize(+n)` is as follows: 124 | 125 | ```cs 126 | public static T Deserialize(string strJson, +n) { 127 | var json = StringToSTJson.Get(strJson, +n); 128 | return STJsonToObject.Get(json, +n); 129 | } 130 | ``` 131 | 132 | How to convert strings to objects, I believe the author does not need to explain the reader should know how to handle, but here it is worth explaining that `STJson` can be attached to objects to achieve local updates. 133 | 134 | ```cs 135 | public class TestClass { 136 | public int X; 137 | public int Y; 138 | } 139 | 140 | TestClass tc = new TestClass() { 141 | X = 10, 142 | Y = 20 143 | }; 144 | STJson json_test = new STJson().SetItem("Y", 100); 145 | STJson.Deserialize(json_test, tc); 146 | Console.WriteLine(STJson.Serialize(tc)); 147 | /******************************************************************************* 148 | * [output] * 149 | *******************************************************************************/ 150 | {"X":10,"Y":100} 151 | ``` 152 | 153 | # STJsonPath 154 | 155 | Test data: `test.json`: 156 | 157 | ```cs 158 | [{ 159 | "name": "Tom", "age": 16, "gender": 0, 160 | "hobby": [ 161 | "cooking", "sing" 162 | ] 163 | },{ 164 | "name": "Tony", "age": 16, "gender": 0, 165 | "hobby": [ 166 | "game", "dance" 167 | ] 168 | },{ 169 | "name": "Andy", "age": 20, "gender": 1, 170 | "hobby": [ 171 | "draw", "sing" 172 | ] 173 | },{ 174 | "name": "Kun", "age": 26, "gender": 1, 175 | "hobby": [ 176 | "sing", "dance", "rap", "basketball" 177 | ] 178 | }] 179 | // Load it: 180 | var json_src = STJson.Deserialize(System.IO.File.ReadAllText("./test.json")); 181 | ``` 182 | An `STJsonPath` can be constructed by: 183 | ```cs 184 | // var jp = new STJsonPath("$[0]name"); 185 | // var jp = new STJsonPath("$[0].name"); 186 | var jp = new STJsonPath("[0]'name'"); // All of the above can be used, but $ is not required. 187 | Console.WriteLine(jp.Select(json_src)); 188 | /******************************************************************************* 189 | * [output] * 190 | *******************************************************************************/ 191 | ["Tom"] 192 | ``` 193 | Of course `STJsonPath` is already integrated in the extension functions in `STJson` and can be used directly by the following: 194 | ```cs 195 | // var jp = new STJsonPath("[0].name"); 196 | // Console.WriteLine(json_src.Select(jp)); 197 | Console.WriteLine(json_src.Select("[0].name")); // 内部动态构建 STJsonPath 198 | /******************************************************************************* 199 | * [output] * 200 | *******************************************************************************/ 201 | ["Tom"] 202 | ``` 203 | 204 | Normal mode (default mode): 205 | ```cs 206 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.ItemOnly).ToString(4)); 207 | /******************************************************************************* 208 | * [output] * 209 | *******************************************************************************/ 210 | [ 211 | "Tom", "Tony", "Andy", "Kun" 212 | ] 213 | ``` 214 | Path mode: 215 | ```cs 216 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.ItemWithPath).ToString(4)); 217 | /******************************************************************************* 218 | * [output] * 219 | *******************************************************************************/ 220 | [ 221 | { 222 | "path": [ 223 | 0, "name" 224 | ], 225 | "item": "Tom" 226 | }, { 227 | "path": [ 228 | 1, "name" 229 | ], 230 | "item": "Tony" 231 | }, { 232 | "path": [ 233 | 2, "name" 234 | ], 235 | "item": "Andy" 236 | }, { 237 | "path": [ 238 | 3, "name" 239 | ], 240 | "item": "Kun" 241 | } 242 | ] 243 | ``` 244 | Keep Structure: 245 | ```cs 246 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.KeepStructure).ToString(4)); 247 | /******************************************************************************* 248 | * [output] * 249 | *******************************************************************************/ 250 | [ 251 | { 252 | "name": "Tom" 253 | }, { 254 | "name": "Tony" 255 | }, { 256 | "name": "Andy" 257 | }, { 258 | "name": "Kun" 259 | } 260 | ] 261 | ``` 262 | 263 | Of course the above is just an introduction to the basic usage, there are many rich features are not introduced to. If you have enough time you can read the tutorial directly at 264 | 265 | CN: [https://DebugST.github.io/STJson/tutorial_cn.html](https://DebugST.github.io/STJson/tutorial_cn.html) 266 | 267 | EN: [https://DebugST.github.io/STJson/tutorial_en.html](https://DebugST.github.io/STJson/tutorial_en.html) 268 | 269 | # Contact Author 270 | 271 | * TG: DebugST 272 | * QQ: 2212233137 273 | * Mail: 2212233137@qq.com -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | [简体中文](./README_CN.md) [English](./README.md) 2 | 3 | # 简介 4 | 5 | `STJson`是一款基于`MIT`开源协议的`Json`解析库。该库纯原生实现不依赖任何库,所以非常轻量便捷,且功能强大。 6 | 7 | 主页: [https://DebugST.github.io/STJson](https://DebugST.github.io/STJson) 8 | 9 | NuGet: [https://www.nuget.org/packages/STLib.Json](https://www.nuget.org/packages/STLib.Json) 10 | 11 | `STJson`不同与其他`Json`库拥有类似与`JObject`和`JArray`的对象。在`STJson`中仅一个`STJson`对象,它既可以是`Object`,也可以是`Array`。`STJson`拥有两个索引器:`STJson[int]`和`STJson[string]`。可通过`STJson.ValueType`确定当前`Json`对象的类型。 12 | 13 | ```cs 14 | var json_1 = new STJson(); 15 | Console.WriteLine("[json_1] - " + json_1.IsNullValue + " - " + json_1.ValueType); 16 | 17 | var json_2 = STJson.New(); 18 | json_2.SetItem("key", "value"); 19 | Console.WriteLine("[json_2] - " + json_2.IsNullValue + " - " + json_2.ValueType); 20 | 21 | var json_3 = new STJson(); 22 | json_3.Append(1, 2, 3); 23 | Console.WriteLine("[json_3] - " + json_3.IsNullValue + " - " + json_3.ValueType); 24 | 25 | var json_4 = new STJson(); 26 | json_4.SetValue(DateTime.Now); 27 | Console.WriteLine("[json_4] - " + json_4.IsNullValue + " - " + json_4.ValueType); 28 | 29 | var json_5 = STJson.CreateArray(); // made by static function 30 | Console.WriteLine("[json_5] - " + json_5.IsNullValue + " - " + json_5.ValueType); 31 | 32 | var json_6 = STJson.CreateObject(); // made by static function 33 | Console.WriteLine("[json_6] - " + json_6.IsNullValue + " - " + json_6.ValueType); 34 | 35 | var json_7 = STJson.FromObject(12); // made by static function 36 | Console.WriteLine("[json_3] - " + json_7.IsNullValue + " - " + json_7.ValueType); 37 | /******************************************************************************* 38 | * [output] * 39 | *******************************************************************************/ 40 | [json_1] - True - Undefined 41 | [json_2] - False - Object 42 | [json_3] - False - Array 43 | [json_4] - False - Datetime 44 | [json_5] - False - Array 45 | [json_6] - False - Object 46 | [json_7] - False - Long 47 | ``` 48 | 49 | # STJson 50 | 51 | `STJson`是一个中间数据类型,它是`string`与`object`之间的桥梁,使用非常便捷,比如: 52 | 53 | ```cs 54 | var st_json = new STJson() 55 | .SetItem("number", 0) // 函数返回自身 所以可以连续操作 56 | .SetItem("boolean", true) 57 | .SetItem("string", "this is string") 58 | .SetItem("datetime", DateTime.Now) 59 | .SetItem("array_1", STJson.CreateArray(123, true, "string")) 60 | .SetItem("array_2", STJson.FromObject(new object[] { 123, true, "string" })) 61 | .SetItem("object", new { key = "this is a object" }) 62 | .SetItem("null", obj: null); 63 | st_json.SetKey("key").SetValue("this is a test"); 64 | Console.WriteLine(st_json.ToString(4)); // 4 -> indentation space count 65 | /******************************************************************************* 66 | * [output] * 67 | *******************************************************************************/ 68 | { 69 | "number": 0, 70 | "boolean": true, 71 | "string": "this is string", 72 | "datetime": "2023-04-22T21:12:30.6109410+08:00", 73 | "array_1": [ 74 | 123, true, "string" 75 | ], 76 | "array_2": [ 77 | 123, true, "string" 78 | ], 79 | "object": { 80 | "key": "this is a object" 81 | }, 82 | "null": null, 83 | "key": "this is a test" 84 | } 85 | ``` 86 | 87 | # 序列化 88 | 89 | 通过上面的例子或许你已经知道怎么将一个对象转换为`string`,通过`STJson.FromObject(object).ToString(+n)`即可,但是有没有可能,其实不用这么麻烦的?比如:`STJson.Serialize(+n)`就可以了??? 90 | 91 | 事实上`STJson.Serialize(+n)`的效率会更好,因为它是直接将对象转换为字符串,而不是转换成`STJson`再转换成字符串。 92 | 93 | ```cs 94 | Console.WriteLine(STJson.Serialize(new { key = "this is test" })); 95 | /******************************************************************************* 96 | * [output] * 97 | *******************************************************************************/ 98 | {"key":"this is test"} 99 | ``` 100 | 101 | 当然你可以有个更友好的输出格式: 102 | 103 | ```cs 104 | Console.WriteLine(STJson.Serialize(new { key = "this is test" }, 4)); 105 | /******************************************************************************* 106 | * [output] * 107 | *******************************************************************************/ 108 | { 109 | "key": "this is test" 110 | } 111 | ``` 112 | 113 | 事实上格式化输出是通过调用静态函数`STJson.Format(+n)`完成的。如果你觉得不喜欢作者内置的格式化风格,完全可以自己写一个格式化的函数。或者去修改源码文件`STJson.Statics.cs:Format(string,int)`。 114 | 115 | # 反序列化 116 | 117 | 事实上代码并不会直接将`string`转换为`object`。因为在那之前必须先对字符串进行解析,确保它是一个正确格式的`Json`。但是做完这个过程的时候已经得到一个`STJson`对象了。最后将`STJson`再转换为`object`。 118 | 119 | 所以你会在源代码`STLib.Json.Converter`中看到如下文件: 120 | 121 | `ObjectToSTJson.cs` `ObjectToString.cs` `STJsonToObject.cs` `StringToSTJson.cs` 122 | 123 | 里面并没有`StringToObject.cs`文件,而`STJson.Deserialize(+n)`的源码如下: 124 | 125 | ```cs 126 | public static T Deserialize(string strJson, +n) { 127 | var json = StringToSTJson.Get(strJson, +n); 128 | return STJsonToObject.Get(json, +n); 129 | } 130 | ``` 131 | 132 | 如何将字符串转换为对象,相信作者不用说明读者也应该知道如何处理,但是这里值得说明的是,`STJson`可以附加到对象中,实现局部更新。 133 | 134 | ```cs 135 | public class TestClass { 136 | public int X; 137 | public int Y; 138 | } 139 | 140 | TestClass tc = new TestClass() { 141 | X = 10, 142 | Y = 20 143 | }; 144 | STJson json_test = new STJson().SetItem("Y", 100); 145 | STJson.Deserialize(json_test, tc); 146 | Console.WriteLine(STJson.Serialize(tc)); 147 | /******************************************************************************* 148 | * [output] * 149 | *******************************************************************************/ 150 | {"X":10,"Y":100} 151 | ``` 152 | 153 | # STJsonPath 154 | 155 | 测试数据`test.json`: 156 | 157 | ```cs 158 | [{ 159 | "name": "Tom", "age": 16, "gender": 0, 160 | "hobby": [ 161 | "cooking", "sing" 162 | ] 163 | },{ 164 | "name": "Tony", "age": 16, "gender": 0, 165 | "hobby": [ 166 | "game", "dance" 167 | ] 168 | },{ 169 | "name": "Andy", "age": 20, "gender": 1, 170 | "hobby": [ 171 | "draw", "sing" 172 | ] 173 | },{ 174 | "name": "Kun", "age": 26, "gender": 1, 175 | "hobby": [ 176 | "sing", "dance", "rap", "basketball" 177 | ] 178 | }] 179 | // 将其加载到程序中: 180 | var json_src = STJson.Deserialize(System.IO.File.ReadAllText("./test.json")); 181 | ``` 182 | 通过以下方式可以构建一个`STJsonPath`: 183 | ```cs 184 | // var jp = new STJsonPath("$[0]name"); 185 | // var jp = new STJsonPath("$[0].name"); 186 | var jp = new STJsonPath("[0]'name'"); // 以上方式均可以使用 $不是必须的 187 | Console.WriteLine(jp.Select(json_src)); 188 | /******************************************************************************* 189 | * [output] * 190 | *******************************************************************************/ 191 | ["Tom"] 192 | ``` 193 | 当然在`STJson`中的扩展函数中已经集成`STJsonPath`,可以通过下面的方式直接使用: 194 | ```cs 195 | // var jp = new STJsonPath("[0].name"); 196 | // Console.WriteLine(json_src.Select(jp)); 197 | Console.WriteLine(json_src.Select("[0].name")); // 内部动态构建 STJsonPath 198 | /******************************************************************************* 199 | * [output] * 200 | *******************************************************************************/ 201 | ["Tom"] 202 | ``` 203 | 204 | 普通模式(默认方式): 205 | ```cs 206 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.ItemOnly).ToString(4)); 207 | /******************************************************************************* 208 | * [output] * 209 | *******************************************************************************/ 210 | [ 211 | "Tom", "Tony", "Andy", "Kun" 212 | ] 213 | ``` 214 | 路径模式: 215 | ```cs 216 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.ItemWithPath).ToString(4)); 217 | /******************************************************************************* 218 | * [output] * 219 | *******************************************************************************/ 220 | [ 221 | { 222 | "path": [ 223 | 0, "name" 224 | ], 225 | "item": "Tom" 226 | }, { 227 | "path": [ 228 | 1, "name" 229 | ], 230 | "item": "Tony" 231 | }, { 232 | "path": [ 233 | 2, "name" 234 | ], 235 | "item": "Andy" 236 | }, { 237 | "path": [ 238 | 3, "name" 239 | ], 240 | "item": "Kun" 241 | } 242 | ] 243 | ``` 244 | 保持结构: 245 | ```cs 246 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.KeepStructure).ToString(4)); 247 | /******************************************************************************* 248 | * [output] * 249 | *******************************************************************************/ 250 | [ 251 | { 252 | "name": "Tom" 253 | }, { 254 | "name": "Tony" 255 | }, { 256 | "name": "Andy" 257 | }, { 258 | "name": "Kun" 259 | } 260 | ] 261 | ``` 262 | 263 | 当然上面仅仅是介绍了一个基本用法,还有很多丰富的功能并没有介绍到。如果你时间充足可以直接阅读教程: 264 | 265 | CN: [https://DebugST.github.io/STJson/tutorial_cn.html](https://DebugST.github.io/STJson/tutorial_cn.html) 266 | 267 | EN: [https://DebugST.github.io/STJson/tutorial_en.html](https://DebugST.github.io/STJson/tutorial_en.html) 268 | 269 | # 联系作者 270 | 271 | * TG: DebugST 272 | * QQ: 2212233137 273 | * Mail: 2212233137@qq.com -------------------------------------------------------------------------------- /Src/STLib.Json.Test/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using STLib.Json; 5 | 6 | namespace STLib.Json.Test 7 | { 8 | public class UserInfo 9 | { 10 | public string Name { get; set; } 11 | public string Github { get; set; } 12 | public string[] Language { get; set; } 13 | public Address Address { get; set; } 14 | } 15 | 16 | public class Address 17 | { 18 | public string Country { get; set; } 19 | public string Province { get; set; } 20 | public string City { get; set; } 21 | } 22 | 23 | internal class Program 24 | { 25 | static void Main(string[] args) 26 | { 27 | //var obj_test = STJsonTestObject.CreateTestObject(); 28 | var type = typeof(UserInfo); 29 | var obj_test = new UserInfo() 30 | { 31 | Name = "DebugST", 32 | Github = "https://github.com/DebugST", 33 | Language = new string[] { "C#", "JS", "..." }, 34 | Address = new Address() 35 | { 36 | Country = "China", 37 | Province = "GuangDong", 38 | City = "ShenZhen" 39 | } 40 | }; 41 | string str_json, str_temp; 42 | Console.WriteLine("========================================"); 43 | Console.WriteLine(STJson.Serialize(obj_test)); 44 | Console.WriteLine("========================================"); 45 | 46 | Console.WriteLine("[CHECK_IS_SAME]"); 47 | 48 | str_json = JsonConvert.SerializeObject(obj_test); 49 | str_temp = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(str_json)); 50 | Console.WriteLine("Newtonsoft : " + (str_temp == str_json)); 51 | 52 | str_json = STJson.Serialize(obj_test); 53 | str_temp = STJson.Serialize(STJson.Deserialize(str_json)); 54 | Console.WriteLine("STJson : " + (str_temp == str_json)); 55 | 56 | var sw = new System.Diagnostics.Stopwatch(); 57 | 58 | int n_counter = 50000; 59 | System.Threading.Thread.Sleep(5000); 60 | Console.WriteLine("========================================"); 61 | Console.WriteLine("[Deserialize To Linq] - " + n_counter); 62 | sw.Reset(); 63 | sw.Start(); 64 | for (int i = 0; i < n_counter; i++) { 65 | JsonConvert.DeserializeObject(str_json); 66 | } 67 | sw.Stop(); 68 | Console.WriteLine("Newstonoft : " + sw.ElapsedMilliseconds); 69 | 70 | sw.Reset(); 71 | sw.Start(); 72 | for (int i = 0; i < n_counter; i++) { 73 | STJson.Deserialize(str_json); 74 | } 75 | sw.Stop(); 76 | Console.WriteLine("STJson : " + sw.ElapsedMilliseconds); 77 | // ==================================================================================================== 78 | System.Threading.Thread.Sleep(5000); 79 | Console.WriteLine("========================================"); 80 | Console.WriteLine("[Deserialize To object] - " + n_counter); 81 | sw.Reset(); 82 | sw.Start(); 83 | for (int i = 0; i < n_counter; i++) { 84 | JsonConvert.DeserializeObject(str_json); 85 | } 86 | sw.Stop(); 87 | Console.WriteLine("Newstonoft : " + sw.ElapsedMilliseconds); 88 | 89 | sw.Reset(); 90 | sw.Start(); 91 | for (int i = 0; i < n_counter; i++) { 92 | STJson.Deserialize(str_json); 93 | } 94 | sw.Stop(); 95 | Console.WriteLine("STJson : " + sw.ElapsedMilliseconds); 96 | // ==================================================================================================== 97 | System.Threading.Thread.Sleep(5000); 98 | Console.WriteLine("========================================"); 99 | Console.WriteLine("[Serialize] - " + n_counter); 100 | sw.Reset(); 101 | sw.Start(); 102 | for (int i = 0; i < n_counter; i++) { 103 | JsonConvert.SerializeObject(obj_test); 104 | } 105 | sw.Stop(); 106 | Console.WriteLine("Newstonoft : " + sw.ElapsedMilliseconds); 107 | 108 | sw.Reset(); 109 | sw.Start(); 110 | for (int i = 0; i < n_counter; i++) { 111 | STJson.Serialize(obj_test); 112 | } 113 | sw.Stop(); 114 | Console.WriteLine("STJson : " + sw.ElapsedMilliseconds); 115 | Console.WriteLine("========================================"); 116 | Console.WriteLine("==END=="); 117 | Console.ReadKey(); 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /Src/STLib.Json.Test/STJsonTestObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace STLib.Json.Test 5 | { 6 | public enum TestObjectEnum { Enum1, Enum2, Enum3 } 7 | 8 | [STJson(STJsonSerializeMode.All)] 9 | public class TestObject 10 | { 11 | private string m_private_string = "private_string_obj"; 12 | public static string Name { get { return "TestObject"; } } 13 | public string STR { get; set; } 14 | public int INT { get; set; } 15 | public double DB { get; set; } 16 | public decimal DEC { get; set; } 17 | public TestObjectEnum Enum { get; set; } 18 | public DateTime TIME { get; set; } 19 | public TestObject_1 OBJ { get; set; } 20 | [STJsonProperty] 21 | public TestObject_1[] ARR_OBJ { get; set; } 22 | 23 | public void Function() { Console.WriteLine(m_private_string); } 24 | } 25 | 26 | public class TestObject_1 27 | { 28 | private string m_private_string = "private_string_obj_1"; 29 | public static string Name { get { return "TestObject_1"; } } 30 | public int[] ARR_INT { get; set; } 31 | public List LST_INT { get; set; } 32 | public List LST_OBJ { get; set; } 33 | public Dictionary DIC_STR_INT { get; set; } 34 | public Dictionary DIC_STR_OBJ { get; set; } 35 | public int[] ARR_INT_READONLY { get; private set; } 36 | public int[][] ARR_ARR_INT { get; set; } 37 | public int[,] ARRARR_INT { get; set; } 38 | public int[,,] ARRARRARR_INT { get; set; } 39 | public List LST_INT_READONLY { get; private set; } 40 | public int ARR_INT_READONLY_LENGTH { get { return ARR_INT_READONLY.Length; } } 41 | 42 | public TestObject_1() { 43 | ARRARR_INT = new int[2, 3]; 44 | ARRARRARR_INT = new int[2, 3, 4]; 45 | ARR_ARR_INT = new int[5][]; 46 | for (int i = 0; i < ARR_ARR_INT.Length; i++) { 47 | ARR_ARR_INT[i] = new int[i]; 48 | } 49 | ARR_INT_READONLY = new int[] { 101, 202 }; 50 | LST_INT_READONLY = new List() { 100, 200 }; 51 | } 52 | 53 | public void Function() { Console.WriteLine(m_private_string); } 54 | } 55 | 56 | public class STJsonTestObject 57 | { 58 | public static TestObject CreateTestObject() { 59 | return new TestObject() { 60 | STR = "string", 61 | INT = 10, 62 | DB = -0.123, 63 | DEC = 0.123M, 64 | TIME = DateTime.Now, 65 | OBJ = new TestObject_1() { 66 | ARR_INT = new int[] { 1, 2, 3 }, 67 | LST_INT = new List() { 11, 12, 13 }, 68 | LST_OBJ = new List() { true, false, 123, "string", new { DY_STR = "str" }, -0.0005 }, 69 | DIC_STR_INT = new Dictionary() { 70 | {"key_1", 10}, 71 | {"key_2", 10} 72 | }, 73 | DIC_STR_OBJ = new Dictionary(){ 74 | {"key_1", true}, 75 | {"key_2", false}, 76 | {"key_3", null}, 77 | {"key_4", "string"}, 78 | {"key_5", 1234}, 79 | {"key_6", new {DY_INT = 100}}, 80 | } 81 | }, 82 | ARR_OBJ = new TestObject_1[]{ 83 | null, new TestObject_1(){ARR_INT = new int[]{60, 70}}, null 84 | } 85 | }; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Src/STLib.Json.Test/STLib.Json.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | STJson 7 | DebugST 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Src/STLib.Json.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.34930.48 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STLib.Json", "STLib.Json\STLib.Json.csproj", "{151B52D3-E5D0-4877-8A84-FF7764F270DD}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STLib.Json.Test", "STLib.Json.Test\STLib.Json.Test.csproj", "{E9423C17-AF9B-46F4-BAE6-0D440F9D7095}" 9 | EndProject 10 | Global 11 | GlobalSection(Performance) = preSolution 12 | HasPerformanceSessions = true 13 | EndGlobalSection 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {151B52D3-E5D0-4877-8A84-FF7764F270DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {151B52D3-E5D0-4877-8A84-FF7764F270DD}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {151B52D3-E5D0-4877-8A84-FF7764F270DD}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {151B52D3-E5D0-4877-8A84-FF7764F270DD}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {E9423C17-AF9B-46F4-BAE6-0D440F9D7095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {E9423C17-AF9B-46F4-BAE6-0D440F9D7095}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {E9423C17-AF9B-46F4-BAE6-0D440F9D7095}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {E9423C17-AF9B-46F4-BAE6-0D440F9D7095}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | GlobalSection(ExtensibilityGlobals) = postSolution 32 | SolutionGuid = {C0D3E6E9-5F55-4EC6-8578-F30C609492E6} 33 | EndGlobalSection 34 | GlobalSection(Performance) = preSolution 35 | HasPerformanceSessions = true 36 | EndGlobalSection 37 | GlobalSection(Performance) = preSolution 38 | HasPerformanceSessions = true 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /Src/STLib.Json/DevLog.txt: -------------------------------------------------------------------------------- 1 | [3.0.1][2024-10-21] 2 | -------------------------------------------------- 3 | Fixed STJson.Insert() error. 4 | Fixed empty object to string error. 5 | Optimize some code. 6 | 7 | [3.0.0][2024-08-02] 8 | -------------------------------------------------- 9 | Add Json5 support. 10 | Add STJsonReader/Writer. 11 | Add STJsonCreator. 12 | Add STJson.ToString(TextWriter). 13 | Optimize STJson.Sort(). 14 | Optimize some STJsonPath built-in functions. 15 | 16 | [2.0.0][2024-02-14] 17 | -------------------------------------------------- 18 | Fixed JsonPath error for [?()] 19 | Fixed some string serialization cannot be parsed in other languages. 20 | 21 | [1.0.4][2023-11-27] 22 | -------------------------------------------------- 23 | Fixed parsing string error for ["....\\"] 24 | Fixed parsing number error for [12E-12] 25 | Changed STJsonPathCallBack 26 | 27 | [1.0.3][2023-11-10] 28 | -------------------------------------------------- 29 | Fixed DateTime type sorting error. 30 | Fixed parsing scientific notation string error. 31 | Fixed STJson.GetValue() error. 32 | 33 | [1.0.1][2023-07-24] 34 | -------------------------------------------------- 35 | Fixed STJson.GetValue() error. 36 | 37 | [1.0.0][2023-06-04] 38 | -------------------------------------------------- 39 | Publish project. 40 | Support Json serialization and deserialization. 41 | Support JsonPath syntax. 42 | Simple data aggregation processing. -------------------------------------------------------------------------------- /Src/STLib.Json/Extensions/STJson.Static.Extensions.cs: -------------------------------------------------------------------------------- 1 | namespace STLib.Json 2 | { 3 | public partial class STJson 4 | { 5 | public static STJson Create(STJsonCreatorStartCallback callback) 6 | { 7 | return new STJsonCreator().Create(callback); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Src/STLib.Json/Extensions/STJsonAggregateException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonAggregateException : Exception 6 | { 7 | public STJsonAggregateException(string strErr) : base(strErr) 8 | { 9 | } 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /Src/STLib.Json/Extensions/STJsonCreator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace STLib.Json 6 | { 7 | public delegate void STJsonCreatorCallback(); 8 | public delegate void STJsonCreatorForCallback(int n_index); 9 | public delegate void STJsonCreatorForEachCallback(T v); 10 | public delegate void STJsonCreatorStartCallback(STJsonCreator writer); 11 | 12 | public class STJsonCreatorException : STJsonException 13 | { 14 | public STJsonCreatorException(string str_error) : base(str_error) { } 15 | } 16 | 17 | public class STJsonCreator 18 | { 19 | private bool m_b_started; 20 | private STJson m_current_json; 21 | 22 | private Stack m_stack; 23 | 24 | public STJsonCreator() 25 | { 26 | m_stack = new Stack(); 27 | } 28 | 29 | public STJson Create(STJsonCreatorStartCallback callback) 30 | { 31 | if (m_b_started) { 32 | m_b_started = false; 33 | throw new STJsonCreatorException("Please wait Create() end."); 34 | } 35 | m_stack.Clear(); 36 | m_b_started = true; 37 | this.Push(new STJson()); 38 | callback(this); 39 | m_b_started = false; 40 | return m_current_json; 41 | } 42 | 43 | public STJsonCreator SetItem(string str_key, long value) 44 | { 45 | this.CheckStarted(); 46 | m_current_json.SetItem(str_key, value); 47 | return this; 48 | } 49 | 50 | public STJsonCreator SetItem(string str_key, double value) 51 | { 52 | this.CheckStarted(); 53 | m_current_json.SetItem(str_key, value); 54 | return this; 55 | } 56 | 57 | public STJsonCreator SetItem(string str_key, bool value) 58 | { 59 | this.CheckStarted(); 60 | m_current_json.SetItem(str_key, value); 61 | return this; 62 | } 63 | 64 | public STJsonCreator SetItem(string str_key, string value) 65 | { 66 | this.CheckStarted(); 67 | m_current_json.SetItem(str_key, value); 68 | return this; 69 | } 70 | 71 | public STJsonCreator SetItem(string str_key, DateTime value) 72 | { 73 | this.CheckStarted(); 74 | m_current_json.SetItem(str_key, value); 75 | return this; 76 | } 77 | 78 | public STJsonCreator SetItem(string str_key, STJson json) 79 | { 80 | this.CheckStarted(); 81 | m_current_json.SetItem(str_key, json); 82 | return this; 83 | } 84 | 85 | public STJsonCreator SetItem(string str_key, object obj) 86 | { 87 | this.CheckStarted(); 88 | m_current_json.SetItem(str_key, obj); 89 | return this; 90 | } 91 | 92 | public STJsonCreator SetItem(string str_key, bool b_express, STJsonCreatorCallback callback) 93 | { 94 | this.CheckStarted(); 95 | if (!b_express) return this; 96 | var json = new STJson(); 97 | m_current_json.SetItem(str_key, json); 98 | 99 | this.Push(json); 100 | callback(); 101 | this.Pop(); 102 | return this; 103 | } 104 | 105 | public STJsonCreator Append(long value) 106 | { 107 | this.CheckStarted(); 108 | m_current_json.Append(value); 109 | return this; 110 | } 111 | 112 | public STJsonCreator Append(double value) 113 | { 114 | this.CheckStarted(); 115 | m_current_json.Append(value); 116 | return this; 117 | } 118 | 119 | public STJsonCreator Append(bool value) 120 | { 121 | this.CheckStarted(); 122 | m_current_json.Append(value); 123 | return this; 124 | } 125 | 126 | public STJsonCreator Append(string value) 127 | { 128 | this.CheckStarted(); 129 | m_current_json.Append(value); 130 | return this; 131 | } 132 | 133 | public STJsonCreator Append(DateTime value) 134 | { 135 | this.CheckStarted(); 136 | m_current_json.Append(value); 137 | return this; 138 | } 139 | 140 | public STJsonCreator Append(object obj) 141 | { 142 | this.CheckStarted(); 143 | m_current_json.Append(obj); 144 | return this; 145 | } 146 | 147 | public STJsonCreator Append(STJson json) 148 | { 149 | this.CheckStarted(); 150 | m_current_json.Append(json); 151 | return this; 152 | } 153 | 154 | public STJsonCreator Append(STJsonCreatorCallback callback) 155 | { 156 | this.CheckStarted(); 157 | var json = new STJson(); 158 | m_current_json.Append(json); 159 | 160 | this.Push(json); 161 | callback(); 162 | this.Pop(); 163 | return this; 164 | } 165 | 166 | public STJsonCreator Append(int n_count, STJsonCreatorForCallback callback) 167 | { 168 | return this.Append(0, n_count, 1, callback); 169 | } 170 | 171 | public STJsonCreator Append(int n_start, int n_end, STJsonCreatorForCallback callback) 172 | { 173 | return this.Append(n_start, n_end, 1, callback); 174 | } 175 | 176 | public STJsonCreator Append(int n_start, int n_end, int n_step, STJsonCreatorForCallback callback) 177 | { 178 | this.CheckStarted(); 179 | for (int i = n_start; i < n_end; i += n_step) { 180 | var json = new STJson(); 181 | m_current_json.Append(json); 182 | 183 | this.Push(json); 184 | callback(i); 185 | this.Pop(); 186 | } 187 | return this; 188 | } 189 | 190 | public STJsonCreator Append(Array arr, STJsonCreatorForEachCallback callback) 191 | { 192 | 193 | return this.Append(arr.GetEnumerator(), callback); 194 | } 195 | 196 | public STJsonCreator Append(IList lst, STJsonCreatorForEachCallback callback) 197 | { 198 | 199 | return this.Append(lst.GetEnumerator(), callback); 200 | } 201 | 202 | public STJsonCreator Append(IList lst, STJsonCreatorForEachCallback callback) 203 | { 204 | 205 | return this.Append(lst.GetEnumerator(), callback); 206 | } 207 | 208 | public STJsonCreator Append(IEnumerator enumerator, STJsonCreatorForEachCallback callback) 209 | { 210 | return this.Append(enumerator, callback); 211 | } 212 | 213 | public STJsonCreator Append(IEnumerator enumerator, STJsonCreatorForEachCallback callback) 214 | { 215 | this.CheckStarted(); 216 | while (enumerator.MoveNext()) { 217 | var json = new STJson(); 218 | m_current_json.Append(json); 219 | 220 | this.Push(json); 221 | callback(enumerator.Current); 222 | this.Pop(); 223 | } 224 | return this; 225 | } 226 | 227 | public STJsonCreator Append(IEnumerable enumerable, STJsonCreatorForEachCallback callback) 228 | { 229 | return this.Append(enumerable, callback); 230 | } 231 | 232 | public STJsonCreator Append(IEnumerable enumerable, STJsonCreatorForEachCallback callback) 233 | { 234 | this.CheckStarted(); 235 | foreach (var v in enumerable) { 236 | var json = new STJson(); 237 | m_current_json.Append(json); 238 | 239 | this.Push(json); 240 | callback(v); 241 | this.Pop(); 242 | } 243 | return this; 244 | } 245 | 246 | public STJsonCreator Set(string str_path, object obj) 247 | { 248 | this.CheckStarted(); 249 | m_current_json.Set(str_path, obj); 250 | return this; 251 | } 252 | 253 | public STJsonCreator Set(string str_path, STJson json) 254 | { 255 | this.CheckStarted(); 256 | m_current_json.Set(str_path, json); 257 | return this; 258 | } 259 | 260 | public STJsonCreator Set(string str_path, STJsonCreatorCallback callback) 261 | { 262 | return this.Set(str_path, true, callback); 263 | } 264 | 265 | public STJsonCreator Set(string str_path, bool b_express, STJsonCreatorCallback callback) 266 | { 267 | this.CheckStarted(); 268 | if (!b_express) return this; 269 | var json = new STJson(); 270 | m_current_json.Set(str_path, json); 271 | 272 | this.Push(json); 273 | callback(); 274 | this.Pop(); 275 | return this; 276 | } 277 | 278 | 279 | private void Push(STJson json) 280 | { 281 | m_current_json = json; 282 | m_stack.Push(json); 283 | } 284 | 285 | private void Pop() 286 | { 287 | m_current_json = null; 288 | if (m_stack.Count == 0) return; 289 | m_stack.Pop(); 290 | if (m_stack.Count == 0) return; 291 | m_current_json = m_stack.Peek(); 292 | } 293 | 294 | private void CheckStarted() 295 | { 296 | if (m_b_started) { 297 | return; 298 | } 299 | throw new STJsonCreatorException("Please call Create() first."); 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Attributes/STJsonAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonAttribute : Attribute 6 | { 7 | public STJsonSerializeMode SerilizaMode { get; private set; } 8 | 9 | public STJsonAttribute(STJsonSerializeMode serilizaMode) { 10 | this.SerilizaMode = serilizaMode; 11 | } 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Attributes/STJsonConverterAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonConverterAttribute : Attribute 6 | { 7 | private static Type m_type_convert = typeof(STJsonConverter); 8 | public Type Type { get; private set; } 9 | 10 | public STJsonConverterAttribute(Type type) { 11 | if (!type.IsSubclassOf(m_type_convert)) { 12 | throw new ArgumentException("The type {" + type.FullName + "} is not sub class of {" + m_type_convert.FullName + "}", "type"); 13 | } 14 | this.Type = type; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Attributes/STJsonPropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonPropertyAttribute : Attribute 6 | { 7 | public string Name { get; private set; } 8 | 9 | public STJsonPropertyAttribute() { 10 | } 11 | 12 | public STJsonPropertyAttribute(string strName) { 13 | this.Name = strName; 14 | } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Converter/FPInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | 5 | namespace STLib.Json 6 | { 7 | internal class FPInfo 8 | { 9 | private FieldInfo m_f_info; 10 | private PropertyInfo m_p_info; 11 | 12 | private static Type m_type_attr_property = typeof(STJsonPropertyAttribute); 13 | private static Type m_type_attr_converter = typeof(STJsonConverterAttribute); 14 | private static Dictionary m_dic_type_map = new Dictionary(); 15 | private static Dictionary> m_dic_fp_infos = new Dictionary>(); 16 | 17 | public string Name { get; private set; } 18 | public string KeyName { get; private set; } 19 | public STJsonConverter Converter { get; private set; } 20 | public STJsonPropertyAttribute PropertyAttribute { get; private set; } 21 | 22 | public Type Type { get; private set; } 23 | 24 | public bool CanSetValue { get; private set; } 25 | 26 | public bool CanGetValue { get; private set; } 27 | 28 | //public bool CanSetValue { 29 | // get { 30 | // if (m_f_info != null) return true; 31 | // return m_p_info.GetSetMethod() != null; 32 | // } 33 | //} 34 | 35 | //public bool CanGetValue { 36 | // get { 37 | // if (m_f_info != null) return true; 38 | // return m_p_info.GetGetMethod() != null; 39 | // } 40 | //} 41 | 42 | public object GetValue(object obj) { 43 | if (m_f_info != null) { 44 | return m_f_info.GetValue(obj); 45 | } 46 | return m_p_info.GetValue(obj, null); 47 | } 48 | 49 | public void SetValue(object obj, object value) { 50 | if (m_f_info != null) { 51 | m_f_info.SetValue(obj, value); 52 | return; 53 | } 54 | m_p_info.SetValue(obj, value, null); 55 | } 56 | 57 | public Attribute GetCustomAttribute(Type type) { 58 | #if NETSTANDARD 59 | if (m_f_info != null) { 60 | return m_f_info.GetCustomAttribute(type); 61 | } 62 | return m_p_info.GetCustomAttribute(type); 63 | #else 64 | if (m_f_info != null) { 65 | var f_attrs = m_f_info.GetCustomAttributes(type, true); 66 | if (f_attrs == null || f_attrs.Length == 0) { 67 | return null; 68 | } 69 | return f_attrs[0] as Attribute; 70 | } 71 | var p_attrs = m_p_info.GetCustomAttributes(type, true); 72 | if (p_attrs == null || p_attrs.Length == 0) { 73 | return null; 74 | } 75 | return p_attrs[0] as Attribute; 76 | #endif 77 | } 78 | 79 | public static List GetFPInfo(Type type) { 80 | List lst = null; 81 | int n_code = type.GetHashCode(); 82 | if (m_dic_fp_infos.ContainsKey(n_code)) { 83 | return m_dic_fp_infos[n_code]; 84 | } else { 85 | lst = new List(); 86 | m_dic_fp_infos.Add(n_code, lst); 87 | } 88 | var fs = type.GetFields(BindingFlags.Instance | BindingFlags.Public); 89 | var ps = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); 90 | foreach (var v in fs) { 91 | FPInfo fp = new FPInfo(); 92 | fp.m_f_info = v; 93 | fp.Name = v.Name; 94 | fp.Type = v.FieldType; 95 | fp.CanGetValue = true; 96 | fp.CanSetValue = true; 97 | lst.Add(fp); 98 | } 99 | foreach (var v in ps) { 100 | FPInfo fp = new FPInfo(); 101 | fp.m_p_info = v; 102 | fp.Name = v.Name; 103 | fp.Type = v.PropertyType; 104 | fp.CanGetValue = v.GetGetMethod() != null; 105 | fp.CanSetValue = v.GetSetMethod() != null; 106 | //if (fp.CanGetValue) { 107 | // fp.CanGetValue = v.GetGetMethod().GetParameters().Length == 0; 108 | //} 109 | //if (fp.CanSetValue) { 110 | // fp.CanSetValue = v.GetSetMethod().GetParameters().Length == 0; 111 | //} 112 | lst.Add(fp); 113 | } 114 | for (int i = 0; i < lst.Count; i++) { 115 | var fp = lst[i]; 116 | var attr = fp.GetCustomAttribute(m_type_attr_property); 117 | if (attr != null) { 118 | fp.PropertyAttribute = attr as STJsonPropertyAttribute; 119 | } 120 | if (fp.PropertyAttribute != null && !string.IsNullOrEmpty(fp.PropertyAttribute.Name)) { 121 | fp.KeyName = fp.PropertyAttribute.Name; 122 | } else { 123 | fp.KeyName = fp.Name; 124 | } 125 | 126 | STJsonConverter converter = null; 127 | attr = fp.GetCustomAttribute(m_type_attr_converter); 128 | if (attr == null) { 129 | continue; 130 | } 131 | n_code = attr.GetType().GetHashCode(); 132 | if (m_dic_type_map.ContainsKey(n_code)) { 133 | converter = m_dic_type_map[n_code]; 134 | } else { 135 | converter = (STJsonConverter)Activator.CreateInstance(((STJsonConverterAttribute)attr).Type); 136 | m_dic_type_map.Add(n_code, converter); 137 | } 138 | fp.Converter = converter; 139 | } 140 | return lst; 141 | } 142 | } 143 | } 144 | 145 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Converter/ObjectToSTJson.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | 4 | using ME = STLib.Json.ObjectToSTJson; 5 | 6 | namespace STLib.Json 7 | { 8 | internal class ObjectToSTJson 9 | { 10 | private static Type m_type_attr_stjson = typeof(STJsonAttribute); 11 | 12 | public static STJson Get(object obj, STJsonSetting setting) 13 | { 14 | if (obj == null) { 15 | return null; 16 | } 17 | if (obj is STJson) return (STJson)obj; 18 | var type = obj.GetType(); 19 | STJson json = new STJson(); 20 | bool b_processed = true; 21 | STJsonConverter converter = STJson.GetCustomConverter(type); 22 | if (converter == null) converter = STJson.GetConverter(type); 23 | if (converter != null) { 24 | var json_custom = converter.ObjectToJson(type, obj, ref b_processed); 25 | if (b_processed) { 26 | return json_custom; 27 | } 28 | } 29 | if (type.IsEnum) { 30 | if (setting.EnumUseNumber) { 31 | json.SetValue(Convert.ToInt64(obj)); 32 | } else { 33 | json.SetValue(Convert.ToString(obj)); 34 | } 35 | return json; 36 | } 37 | 38 | if (type.IsArray) { 39 | Array arr = obj as Array; 40 | int nDim = type.FullName.Length - type.FullName.LastIndexOf('[') - 1; 41 | int[] nLens = new int[nDim]; 42 | int[] nIndices = new int[nDim]; 43 | for (int i = 0; i < nDim; i++) { 44 | nLens[i] = arr.GetLength(i); 45 | } 46 | json.SetValue(GetArray(arr, nLens, nIndices, 0, setting)); 47 | return json; 48 | } 49 | if (type.IsGenericType) { 50 | if (obj is IDictionary) { 51 | var idic = (IDictionary)obj; 52 | json.SetModel(STJsonValueType.Object); 53 | //ICollection ic_keys = (ICollection)t.GetProperty("Keys").GetValue(obj, null); 54 | //ICollection ic_values = (ICollection)t.GetProperty("Values").GetValue(obj, null); 55 | IEnumerator ie_keys = idic.Keys.GetEnumerator();// ic_keys.GetEnumerator(); 56 | IEnumerator ie_values = idic.Values.GetEnumerator();// ic_values.GetEnumerator(); 57 | while (ie_keys.MoveNext() && ie_values.MoveNext()) { 58 | var strKey = ie_keys.Current.ToString(); 59 | json.SetKey(strKey).SetValue(ME.Get(ie_values.Current, setting)); 60 | } 61 | return json; 62 | } 63 | 64 | if (obj is IEnumerable) { 65 | json.SetModel(STJsonValueType.Array); 66 | //var method = t.GetMethod("GetEnumerator"); 67 | IEnumerator ie = ((IEnumerable)obj).GetEnumerator();// (IEnumerator)method.Invoke(obj, null); 68 | while (ie.MoveNext()) { 69 | json.Append(ME.Get(ie.Current, setting)); 70 | } 71 | return json; 72 | } 73 | } 74 | json.SetModel(STJsonValueType.Object); 75 | var fps = FPInfo.GetFPInfo(type); 76 | var serilizaModel = STJsonSerializeMode.All; 77 | if (!setting.IgnoreAttribute) { 78 | //#if NETSTANDARD 79 | // var attr = t.GetCustomAttribute(m_type_attr_stjson); 80 | // if (attr != null) { 81 | // serilizaModel = ((STJsonAttribute)attr).SerilizaModel; 82 | // } 83 | //#else 84 | var attrs = type.GetCustomAttributes(m_type_attr_stjson, true); 85 | if (attrs != null && attrs.Length > 0) { 86 | serilizaModel = ((STJsonAttribute)attrs[0]).SerilizaMode; 87 | } 88 | //#endif 89 | } 90 | foreach (var p in fps) { 91 | if (!p.CanGetValue) { 92 | continue; 93 | } 94 | switch (serilizaModel) { 95 | case STJsonSerializeMode.All: 96 | break; 97 | case STJsonSerializeMode.Include: 98 | if (p.PropertyAttribute == null) { 99 | continue; 100 | } 101 | break; 102 | case STJsonSerializeMode.Exclude: 103 | if (p.PropertyAttribute != null) { 104 | continue; 105 | } 106 | break; 107 | } 108 | switch (setting.Mode) { 109 | case STJsonSetting.KeyMode.Include: 110 | if (!setting.KeyList.Contains(p.KeyName)) { 111 | continue; 112 | } 113 | break; 114 | case STJsonSetting.KeyMode.Exclude: 115 | if (setting.KeyList.Contains(p.KeyName)) { 116 | continue; 117 | } 118 | break; 119 | } 120 | converter = p.Converter; 121 | if (converter == null) { 122 | converter = STJson.GetCustomConverter(p.KeyName); 123 | } 124 | if (converter != null) { 125 | b_processed = true; 126 | var json_custom = converter.ObjectToJson(type, p.GetValue(obj), ref b_processed); 127 | if (b_processed) { 128 | return json.SetItem(p.KeyName, json_custom); 129 | } 130 | } 131 | if (!p.CanGetValue) continue; 132 | json.SetKey(p.KeyName).SetValue(ME.Get(p.GetValue(obj), setting)); 133 | } 134 | return json; 135 | } 136 | 137 | private static STJson GetArray(Array arr, int[] nLens, int[] nIndices, int nLevel, STJsonSetting setting) 138 | { 139 | STJson json = new STJson(); 140 | json.SetModel(STJsonValueType.Array); 141 | for (int i = 0; i < nLens[nLevel]; i++) { 142 | nIndices[nLevel] = i; 143 | if (nLevel == nLens.Length - 1) { 144 | var obj = arr.GetValue(nIndices); 145 | json.Append(ME.Get(obj, setting)); 146 | } else { 147 | json.Append(GetArray(arr, nLens, nIndices, nLevel + 1, setting)); 148 | } 149 | } 150 | return json; 151 | } 152 | } 153 | } 154 | 155 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Converter/STJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public abstract class STJsonConverter 6 | { 7 | public virtual STJson ObjectToJson(Type t, object obj, ref bool bProcessed) { 8 | bProcessed = false; 9 | return null; 10 | } 11 | public virtual string ObjectToString(Type t, object obj, ref bool bProcessed) { 12 | bProcessed = false; 13 | return null; 14 | } 15 | public virtual object JsonToObject(Type t, STJson json, ref bool bProcessed) { 16 | bProcessed = false; 17 | return null; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Entities/Enums/STJsonSerializeMode.cs: -------------------------------------------------------------------------------- 1 | namespace STLib.Json 2 | { 3 | public enum STJsonSerializeMode 4 | { 5 | All, Include, Exclude 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Entities/Enums/STJsonValueType.cs: -------------------------------------------------------------------------------- 1 | namespace STLib.Json 2 | { 3 | public enum STJsonValueType 4 | { 5 | Long, Double, Boolean, String, Array, Object, Datetime, Undefined 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Entities/Structures/STJsonTypeMapInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public struct STJsonTypeMapInfo : IComparable 6 | { 7 | public int HashCode; 8 | public Type Type; 9 | public STJsonConverter Converter; 10 | 11 | public static STJsonTypeMapInfo Empty; 12 | 13 | public int CompareTo(object obj) 14 | { 15 | return this.HashCode - ((STJsonTypeMapInfo)obj).HashCode; 16 | } 17 | 18 | public static STJsonTypeMapInfo Create(Type type, STJsonConverter converter) 19 | { 20 | return new STJsonTypeMapInfo() 21 | { 22 | HashCode = type.GetHashCode(), 23 | Type = type, 24 | Converter = converter 25 | }; 26 | } 27 | 28 | public static STJsonTypeMapInfo Create(int n_code, STJsonConverter converter) 29 | { 30 | return new STJsonTypeMapInfo() 31 | { 32 | HashCode = n_code, 33 | Converter = converter 34 | }; 35 | } 36 | 37 | public override string ToString() 38 | { 39 | return this.Type.FullName; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Exceptions/STJsonCastException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonCastException : InvalidCastException 6 | { 7 | public STJsonCastException(string str_error) : base(str_error) { } 8 | public STJsonCastException(string str_error, Exception inner_exception) : base(str_error, inner_exception) { } 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Exceptions/STJsonException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonException : Exception 6 | { 7 | public STJsonException(string str_error) : base(str_error) { } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Exceptions/STJsonParseException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonParseException : STJsonException 6 | { 7 | public int Index { get; private set; } 8 | public int Row { get; private set; } 9 | public int Col { get; private set; } 10 | 11 | internal STJsonParseException(STJsonToken token) 12 | : base("Invalid token: '" + token.Value + "'. " + string.Format(" [index:{0}, row:{1}, col:{2}]", token.Index, token.Row, token.Col)) 13 | { 14 | this.Index = token.Index; 15 | this.Row = token.Row; 16 | this.Col = token.Col; 17 | } 18 | 19 | internal STJsonParseException(int n_index, int n_row, int n_col, string str_error) 20 | : base(str_error + " " + string.Format(" [index:{0}, row:{1}, col:{2}]", n_index, n_row, n_col)) 21 | { 22 | } 23 | 24 | internal STJsonParseException(int n_index, string str_error) : base(str_error) 25 | { 26 | this.Index = n_index; 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Exceptions/STJsonWriterException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STLib.Json 7 | { 8 | public class STJsonWriterException : STJsonException 9 | { 10 | public STJsonWriterException(string str_error) : base(str_error) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Parser/Entities/Enums/STJsonTokenType.cs: -------------------------------------------------------------------------------- 1 | namespace STLib.Json 2 | { 3 | internal enum STJsonTokenType 4 | { 5 | None, Symbol, /*Keyword,*/ Long, Double, String, ItemSplitor, KVSplitor, ObjectStart, ObjectEnd, ArrayStart, ArrayEnd, Comment 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Parser/Entities/Structures/STJsonToken.cs: -------------------------------------------------------------------------------- 1 | namespace STLib.Json 2 | { 3 | internal struct STJsonToken 4 | { 5 | public static readonly STJsonToken None = new STJsonToken() 6 | { 7 | Index = -1, 8 | Row = -1, 9 | Col = -1, 10 | Type = STJsonTokenType.None 11 | }; 12 | 13 | public int Index; 14 | public int Row; 15 | public int Col; 16 | public string Value; 17 | public STJsonTokenType Type; 18 | 19 | public STJsonToken(int n_index, int n_row, int n_col, string str_value, STJsonTokenType type) 20 | { 21 | this.Index = n_index; 22 | this.Row = n_row; 23 | this.Col = n_col; 24 | this.Value = str_value; 25 | this.Type = type; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Parser/STJsonParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | 5 | using ME = STLib.Json.STJsonParser; 6 | 7 | namespace STLib.Json 8 | { 9 | internal class STJsonParser 10 | { 11 | public static STJson Parse(string str_json) 12 | { 13 | var lst_token = new STJsonTokenizer(str_json).GetTokens(); 14 | return ME.Parse(lst_token); 15 | } 16 | 17 | internal static STJson Parse(List lst_token) 18 | { 19 | if (lst_token.Count == 0) { 20 | throw new STJsonParseException(-1, "Invalid JSON string."); 21 | } 22 | int n_index = 1; 23 | STJson json = null; 24 | switch (lst_token[0].Type) { 25 | case STJsonTokenType.ObjectStart: 26 | json = ME.GetObject(lst_token, ref n_index); 27 | break; 28 | case STJsonTokenType.ArrayStart: 29 | json = ME.GetArray(lst_token, ref n_index); 30 | break; 31 | default: 32 | throw new STJsonParseException(lst_token[0]); 33 | } 34 | if (n_index < lst_token.Count) { 35 | throw new STJsonParseException(lst_token[n_index]); 36 | } 37 | return json; 38 | } 39 | 40 | private static STJson GetObject(List lst_token, ref int n_index) 41 | { 42 | STJson json = new STJson(); 43 | json.SetModel(STJsonValueType.Object); 44 | while (n_index < lst_token.Count) { 45 | var token = lst_token[n_index]; 46 | if (token.Type == STJsonTokenType.ObjectEnd) { // '}' 47 | n_index++; 48 | return json; 49 | } 50 | token = lst_token[n_index++]; 51 | if (token.Type != STJsonTokenType.String && token.Type != STJsonTokenType.Symbol) { 52 | throw new STJsonParseException(token); 53 | } 54 | var jv = json.SetKey(token.Value); 55 | if (n_index >= lst_token.Count) throw new STJsonParseException(-1, "Incomplete JSON string."); 56 | token = lst_token[n_index++]; 57 | if (token.Type != STJsonTokenType.KVSplitor) { // ':' 58 | throw new STJsonParseException(token); 59 | } 60 | if (n_index >= lst_token.Count) throw new STJsonParseException(-1, "Incomplete JSON string."); 61 | token = lst_token[n_index++]; 62 | switch (token.Type) { 63 | case STJsonTokenType.Symbol: 64 | switch (token.Value) { 65 | case "true": 66 | jv.SetValue(true); 67 | break; 68 | case "false": 69 | jv.SetValue(false); 70 | break; 71 | case "null": 72 | jv.SetValue(value: null); 73 | break; 74 | default: 75 | throw new STJsonParseException(token); 76 | } 77 | break; 78 | case STJsonTokenType.String: 79 | jv.SetValue(ME.ParseString(token)); 80 | break; 81 | case STJsonTokenType.Long: 82 | jv.SetValue(ME.ParseNumberLong(token)); 83 | break; 84 | case STJsonTokenType.Double: 85 | jv.SetValue(ME.ParseNumberDouble(token)); 86 | break; 87 | case STJsonTokenType.ObjectStart: 88 | jv.SetValue(ME.GetObject(lst_token, ref n_index)); 89 | break; 90 | case STJsonTokenType.ArrayStart: 91 | jv.SetValue(ME.GetArray(lst_token, ref n_index)); 92 | break; 93 | default: 94 | throw new STJsonParseException(token); 95 | } 96 | token = lst_token[n_index++]; 97 | switch (token.Type) { 98 | case STJsonTokenType.ItemSplitor: continue; // ',' 99 | case STJsonTokenType.ObjectEnd: return json; // '}' 100 | default: 101 | throw new STJsonParseException(token); 102 | } 103 | } 104 | throw new STJsonParseException(-1, "Incomplete JSON string."); 105 | } 106 | 107 | private static STJson GetArray(List lst_token, ref int n_index) 108 | { 109 | STJson json = new STJson(); 110 | json.SetModel(STJsonValueType.Array); 111 | while (n_index < lst_token.Count) { 112 | var token = lst_token[n_index++]; 113 | switch (token.Type) { 114 | case STJsonTokenType.ArrayEnd: 115 | return json; 116 | case STJsonTokenType.String: 117 | json.Append(ME.ParseString(token)); 118 | break; 119 | case STJsonTokenType.Long: 120 | json.Append(ME.ParseNumberLong(token)); 121 | break; 122 | case STJsonTokenType.Double: 123 | json.Append(ME.ParseNumberDouble(token)); 124 | break; 125 | case STJsonTokenType.Symbol: 126 | switch (token.Value) { 127 | case "true": 128 | json.Append(true); 129 | break; 130 | case "false": 131 | json.Append(false); 132 | break; 133 | case "null": 134 | case "undefined": 135 | json.Append(json: null); 136 | break; 137 | default: 138 | throw new STJsonParseException(token); 139 | } 140 | break; 141 | case STJsonTokenType.ObjectStart: 142 | json.Append(ME.GetObject(lst_token, ref n_index)); 143 | break; 144 | case STJsonTokenType.ArrayStart: 145 | json.Append(ME.GetArray(lst_token, ref n_index)); 146 | break; 147 | default: 148 | throw new STJsonParseException(token); 149 | } 150 | token = lst_token[n_index++]; 151 | switch (token.Type) { 152 | case STJsonTokenType.ItemSplitor: continue; // ',' 153 | case STJsonTokenType.ArrayEnd: return json; // ']' 154 | default: 155 | throw new STJsonParseException(token); 156 | } 157 | } 158 | throw new STJsonParseException(-1, "Incomplete JSON string."); 159 | } 160 | 161 | internal static long ParseNumberLong(STJsonToken token) 162 | { 163 | // note: -0xAAA, 0XAAA 164 | var b_flag = token.Value[0] == '-'; 165 | var str = b_flag ? token.Value.Substring(1) : token.Value; 166 | try { 167 | for (int i = 1; i < str.Length; i++) { 168 | if (i > 2) break; 169 | var ch = token.Value[i]; 170 | switch (ch) { 171 | case 'x': 172 | case 'X': // -0x** will get a exception. 173 | return b_flag ? 0 - Convert.ToInt64(str, 16) : Convert.ToInt64(str, 16); 174 | } 175 | } 176 | return b_flag ? 0 - Convert.ToInt64(str) : Convert.ToInt64(str); 177 | } catch { 178 | throw new STJsonParseException(token); 179 | } 180 | } 181 | 182 | internal static double ParseNumberDouble(STJsonToken token) 183 | { 184 | try { 185 | return Convert.ToDouble(token.Value); 186 | } catch { 187 | throw new STJsonParseException(token); 188 | } 189 | } 190 | 191 | internal static string ParseString(STJsonToken token) 192 | { 193 | int n_hex_string = 0; 194 | string str_temp = string.Empty; 195 | StringBuilder sb = new StringBuilder(); 196 | 197 | for (int i = 0, n_len = token.Value.Length; i < n_len; i++) { 198 | var ch = token.Value[i]; 199 | if (ch != '\\') { 200 | sb.Append(ch); 201 | continue; 202 | } 203 | if (++i >= n_len) { 204 | throw new STJsonParseException(token); 205 | } 206 | ch = token.Value[i]; 207 | var b_is_newline = false; 208 | switch (ch) { 209 | case '\r': 210 | for (i++; i < n_len; i++) { 211 | switch (token.Value[i]) { 212 | case '\r': continue; 213 | case '\n': b_is_newline = true; break; 214 | default: 215 | throw new STJsonParseException(token); 216 | } 217 | if (b_is_newline) break; 218 | } 219 | continue; 220 | case '\n': continue; 221 | case 'r': sb.Append('\r'); continue; 222 | case 'n': sb.Append('\n'); continue; 223 | case 't': sb.Append('\t'); continue; 224 | case 'f': sb.Append('\f'); continue; 225 | case 'b': sb.Append('\b'); continue; 226 | case 'a': sb.Append('\a'); continue; 227 | case 'v': sb.Append('\v'); continue; 228 | case '0': sb.Append('\0'); continue; 229 | case 'x': 230 | case 'u': 231 | n_hex_string = ch == 'x' ? 2 : 4; 232 | if (i + n_hex_string >= token.Value.Length) { 233 | throw new STJsonParseException(token); 234 | } 235 | str_temp = token.Value.Substring(i + 1, n_hex_string); 236 | try { 237 | sb.Append((char)Convert.ToUInt16(str_temp, 16)); 238 | } catch { 239 | throw new STJsonParseException(token); 240 | } 241 | i += n_hex_string; 242 | continue; 243 | default: 244 | sb.Append(ch); 245 | continue; 246 | } 247 | } 248 | return sb.ToString(); 249 | } 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Parser/STJsonTokenReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | using System.Collections.Generic; 6 | using System.Collections; 7 | 8 | namespace STLib.Json 9 | { 10 | internal class STJsonTokenReader : IEnumerable, IDisposable 11 | { 12 | private TextReader m_reader; 13 | private int m_n_position; 14 | private int m_n_row; 15 | private int m_n_col; 16 | 17 | private STJsonToken m_last_token; 18 | private bool m_is_auto_close; 19 | 20 | public bool Disposed { get; private set; } 21 | 22 | public STJsonTokenReader(TextReader reader, bool is_auto_close) 23 | { 24 | m_reader = reader; 25 | m_is_auto_close = is_auto_close; 26 | } 27 | 28 | public IEnumerator GetEnumerator() 29 | { 30 | m_n_position = 0; 31 | m_n_row = 1; 32 | m_n_col = 1; 33 | 34 | int n_char = -1; 35 | var token = new STJsonToken(); 36 | 37 | while ((n_char = m_reader.Peek()) != -1) { 38 | var ch = (char)n_char; 39 | int n_index = m_n_position, n_row = m_n_row, n_col = m_n_col; 40 | if (('0' <= ch && ch <= '9') || ch == '-' || ch == '+' || ch == '.') { 41 | yield return m_last_token = this.GetNumber(); 42 | continue; 43 | } 44 | switch (ch) { 45 | case '{': // object start 46 | this.ReadInt(); 47 | yield return m_last_token = new STJsonToken(n_index, n_row, n_col, "{", STJsonTokenType.ObjectStart); 48 | continue; 49 | case '[': // array start 50 | this.ReadInt(); 51 | yield return m_last_token = new STJsonToken(n_index, n_row, n_col, "[", STJsonTokenType.ArrayStart); 52 | continue; 53 | case ',': // item splitor 54 | this.ReadInt(); 55 | yield return m_last_token = new STJsonToken(n_index, n_row, n_col, ",", STJsonTokenType.ItemSplitor); 56 | continue; 57 | case ':': // key value splitor 58 | this.ReadInt(); 59 | yield return m_last_token = new STJsonToken(n_index, n_row, n_col, ":", STJsonTokenType.KVSplitor); 60 | continue; 61 | case ']': // array end 62 | this.ReadInt(); 63 | yield return m_last_token = new STJsonToken(n_index, n_row, n_col, "]", STJsonTokenType.ArrayEnd); 64 | continue; 65 | case '}': // object end 66 | this.ReadInt(); 67 | yield return m_last_token = new STJsonToken(n_index, n_row, n_col, "}", STJsonTokenType.ObjectEnd); 68 | continue; 69 | case ' ': // space 70 | case '\r': 71 | case '\n': 72 | case '\t': 73 | this.ReadInt(); 74 | continue; 75 | case '/': 76 | this.GetComment(); 77 | continue; 78 | case '\'': // string 79 | case '\"': 80 | token = this.GetString(); 81 | if (m_last_token.Type == STJsonTokenType.String) { 82 | m_last_token.Value += token.Value; 83 | } else { 84 | m_last_token = token; 85 | } 86 | while ((n_char = m_reader.Peek()) != -1) { 87 | switch (n_char) { 88 | case ' ': // space 89 | case '\r': 90 | case '\n': 91 | case '\t': 92 | this.ReadInt(); 93 | continue; 94 | } 95 | break; 96 | } 97 | switch (m_reader.Peek()) { 98 | case '\'': 99 | case '\"': 100 | continue; 101 | } 102 | yield return m_last_token; 103 | continue; 104 | default: 105 | token = this.GetSymbol(); 106 | if (token.Value.Length == 0) { 107 | throw new STJsonParseException(m_n_position, "Invalid char '" + ch + "'."); 108 | } 109 | yield return token; 110 | continue; 111 | } 112 | } 113 | this.Dispose(); 114 | } 115 | 116 | public void Dispose() 117 | { 118 | if (this.Disposed) return; 119 | this.Disposed = true; 120 | if (m_is_auto_close) { 121 | m_reader.Dispose(); 122 | } 123 | } 124 | 125 | private char ReadChar() 126 | { 127 | return (char)this.ReadInt(); 128 | } 129 | 130 | private int ReadInt() 131 | { 132 | var ch = m_reader.Read(); 133 | m_n_position++; 134 | m_n_col++; 135 | if (ch == '\n') { 136 | m_n_row++; 137 | m_n_col = 1; 138 | } 139 | return ch; 140 | } 141 | 142 | private STJsonToken GetNumber() 143 | { 144 | StringBuilder sb = new StringBuilder(12); 145 | int n_char = -1; 146 | int n_index = m_n_position, n_row = m_n_row, n_col = m_n_col; 147 | bool b_dot = false, b_e = false, b_hex = false; 148 | while ((n_char = m_reader.Peek()) != -1) { 149 | var ch = (char)n_char; 150 | switch (ch) { 151 | case 'x': // 0x123 0X123 152 | case 'X': 153 | b_hex = true; 154 | sb.Append(this.ReadChar()); 155 | continue; 156 | case '-': // -123 +123 157 | case '+': 158 | sb.Append(this.ReadChar()); 159 | continue; 160 | case 'e': // 123E+2 123e2 123e-2 161 | case 'E': 162 | b_e = true; 163 | sb.Append(this.ReadChar()); 164 | continue; 165 | case '.': // 123.213 .123 123. 166 | b_dot = true; 167 | sb.Append(this.ReadChar()); 168 | continue; 169 | } 170 | if ('0' <= ch && ch <= '9') { 171 | sb.Append(this.ReadChar()); continue; 172 | } 173 | if ('a' <= ch && ch <= 'f') { 174 | sb.Append(this.ReadChar()); continue; 175 | } 176 | if ('A' <= ch && ch <= 'F') { 177 | sb.Append(this.ReadChar()); continue; 178 | } 179 | break; 180 | } 181 | return new STJsonToken() 182 | { 183 | Type = (b_dot || b_e) && !b_hex ? STJsonTokenType.Double : STJsonTokenType.Long, 184 | Index = n_index, 185 | Row = n_row, 186 | Col = n_col, 187 | Value = sb.ToString() 188 | }; 189 | } 190 | 191 | private STJsonToken GetSymbol() 192 | { 193 | StringBuilder sb = new StringBuilder(12); 194 | int n_char = -1; 195 | int n_index = m_n_position, n_row = m_n_row, n_col = m_n_col; 196 | 197 | while ((n_char = m_reader.Peek()) != -1) { 198 | var ch = (char)n_char; 199 | if ('a' <= ch && ch <= 'z') { 200 | sb.Append(this.ReadChar()); continue; 201 | } 202 | if ('A' <= ch && ch <= 'Z') { 203 | sb.Append(this.ReadChar()); continue; 204 | } 205 | if ('0' <= ch && ch <= '9') { 206 | sb.Append(this.ReadChar()); continue; 207 | } 208 | if (ch == '_') { 209 | sb.Append(this.ReadChar()); continue; 210 | } 211 | break; 212 | } 213 | 214 | return new STJsonToken() 215 | { 216 | Type = STJsonTokenType.Symbol, 217 | Index = n_index, 218 | Row = n_row, 219 | Col = n_col, 220 | Value = sb.ToString() 221 | }; 222 | } 223 | 224 | private STJsonToken GetString() 225 | { 226 | StringBuilder sb = new StringBuilder(512); 227 | int n_char = -1; 228 | int n_index = m_n_position, n_row = m_n_row, n_col = m_n_col; 229 | 230 | var ch_begin = this.ReadChar(); 231 | var token = new STJsonToken() 232 | { 233 | Type = STJsonTokenType.String, 234 | Index = n_index, 235 | Row = n_row, 236 | Col = n_col 237 | }; 238 | 239 | while ((n_char = this.ReadInt()) != -1) { 240 | var ch = (char)n_char; 241 | if (ch == ch_begin) { 242 | token.Value = sb.ToString(); 243 | return token; 244 | } 245 | sb.Append(ch); 246 | if (ch == '\\') sb.Append(this.ReadChar()); 247 | } 248 | throw new STJsonParseException(n_index, m_n_row, m_n_col, "Can not get a string. missing '\'' or '\"'."); 249 | } 250 | 251 | private STJsonToken GetComment() 252 | { 253 | // note: str_text[n_index] == '/' 254 | int n_index = m_n_position, n_row = m_n_row, n_col = m_n_col; 255 | var n_char = this.ReadInt(); 256 | if ((n_char = this.ReadInt()) == -1) { 257 | throw new STJsonParseException(n_index, m_n_row, m_n_col, "Invalid char '/'."); 258 | } 259 | switch (n_char) { 260 | case '/': return this.GetCommentLine(); 261 | case '*': return this.GetCommentBlock(); 262 | default: 263 | throw new STJsonParseException(n_index + 1, n_row, n_col + 1, "Invalid char '" + (char)n_char + "'."); 264 | } 265 | } 266 | 267 | private STJsonToken GetCommentLine() 268 | { 269 | // note: str_text[n_index:2] == '//' 270 | int n_char = -1; 271 | 272 | while ((n_char = this.ReadInt()) != -1) { 273 | if (n_char == '\n') { 274 | break; 275 | } 276 | } 277 | return new STJsonToken() 278 | { 279 | Type = STJsonTokenType.Comment 280 | }; 281 | } 282 | 283 | private STJsonToken GetCommentBlock() 284 | { 285 | // note: str_text[n_index:2] == '/*' 286 | int n_char_current = '\0', n_char_last = '\0'; 287 | while ((n_char_current = this.ReadInt()) != -1) { 288 | if (n_char_current == '/' && n_char_last == '*') { 289 | break; 290 | } 291 | n_char_last = n_char_current; 292 | } 293 | return new STJsonToken() 294 | { 295 | Type = STJsonTokenType.Comment 296 | }; 297 | } 298 | 299 | // ============================================= 300 | 301 | IEnumerator IEnumerable.GetEnumerator() 302 | { 303 | return this.GetEnumerator(); 304 | } 305 | 306 | IEnumerator IEnumerable.GetEnumerator() 307 | { 308 | return this.GetEnumerator(); 309 | } 310 | 311 | void IDisposable.Dispose() 312 | { 313 | this.Dispose(); 314 | } 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Parser/STJsonTokenizer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | 5 | namespace STLib.Json 6 | { 7 | internal class STJsonTokenizer 8 | { 9 | public string Text { get => m_str_json; } 10 | 11 | private string m_str_json; 12 | 13 | private int m_n_position; 14 | private int m_n_row; 15 | private int m_n_col; 16 | 17 | public STJsonTokenizer(string str_json) 18 | { 19 | m_str_json = str_json; 20 | } 21 | 22 | public List GetTokens() 23 | { 24 | m_n_position = 0; 25 | m_n_row = 1; 26 | m_n_col = 1; 27 | 28 | var token = new STJsonToken(); 29 | List lst = new List(); 30 | 31 | while (m_n_position < m_str_json.Length) { 32 | var ch = m_str_json[m_n_position]; 33 | if (('0' <= ch && ch <= '9') || ch == '-' || ch == '+' || ch == '.') { 34 | token = this.GetNumber(); 35 | lst.Add(token); 36 | continue; 37 | } 38 | switch (ch) { 39 | case '{': // object start 40 | //stack_region.Push('{'); 41 | lst.Add(new STJsonToken(m_n_position++, m_n_row, m_n_col++, "{", STJsonTokenType.ObjectStart)); 42 | continue; 43 | case '[': // array start 44 | //stack_region.Push('['); 45 | lst.Add(new STJsonToken(m_n_position++, m_n_row, m_n_col++, "[", STJsonTokenType.ArrayStart)); 46 | continue; 47 | case ',': // item splitor 48 | lst.Add(new STJsonToken(m_n_position++, m_n_row, m_n_col++, ",", STJsonTokenType.ItemSplitor)); 49 | continue; 50 | case ':': // key value splitor 51 | lst.Add(new STJsonToken(m_n_position++, m_n_row, m_n_col++, ":", STJsonTokenType.KVSplitor)); 52 | continue; 53 | case ']': // array end 54 | lst.Add(new STJsonToken(m_n_position++, m_n_row, m_n_col++, "]", STJsonTokenType.ArrayEnd)); 55 | continue; 56 | case '}': // object end 57 | lst.Add(new STJsonToken(m_n_position++, m_n_row, m_n_col++, "}", STJsonTokenType.ObjectEnd)); 58 | continue; 59 | case ' ': // space 60 | case '\r': 61 | case '\n': 62 | case '\t': 63 | m_n_position++; 64 | m_n_col++; 65 | if (ch == '\n') { 66 | m_n_row++; 67 | m_n_col = 1; 68 | } 69 | continue; 70 | case '/': 71 | token = this.GetComment(); 72 | continue; 73 | case '\'': // string 74 | case '\"': 75 | token = this.GetString(); 76 | if (lst.Count > 0 && lst[lst.Count - 1].Type == STJsonTokenType.String) { 77 | var temp = lst[lst.Count - 1]; 78 | temp.Value += token.Value; 79 | lst[lst.Count - 1] = temp; 80 | } else { 81 | lst.Add(token); 82 | } 83 | continue; 84 | default: 85 | token = this.GetSymbol(); 86 | if (token.Value.Length == 0) { 87 | throw new STJsonParseException(m_n_position, "Invalid char '" + ch + "'."); 88 | } 89 | lst.Add(token); 90 | break; 91 | } 92 | } 93 | return lst; 94 | } 95 | 96 | private STJsonToken GetNumber() 97 | { 98 | int n_index = m_n_position, n_len = -1; 99 | bool b_dot = false, b_e = false, b_hex = false; 100 | for (int i = n_index; i < m_str_json.Length; i++) { 101 | var ch = m_str_json[i]; 102 | switch (ch) { 103 | case 'x': // 0x123 0X123 104 | case 'X': 105 | b_hex = true; 106 | continue; 107 | case '-': // -123 +123 108 | case '+': 109 | continue; 110 | case 'e': // 123E+2 123e2 123e-2 111 | case 'E': 112 | b_e = true; 113 | continue; 114 | case '.': // 123.213 .123 123. 115 | b_dot = true; 116 | continue; 117 | } 118 | if ('0' <= ch && ch <= '9') continue; 119 | if ('a' <= ch && ch <= 'f') continue; 120 | if ('A' <= ch && ch <= 'F') continue; 121 | n_len = i - n_index; 122 | break; 123 | } 124 | if (n_len == -1) n_len = m_str_json.Length - n_index; 125 | m_n_position += n_len; 126 | m_n_col += n_len; 127 | return new STJsonToken() 128 | { 129 | Index = n_index, 130 | Type = (b_dot || b_e) && !b_hex ? STJsonTokenType.Double : STJsonTokenType.Long, 131 | Value = m_str_json.Substring(n_index, n_len) 132 | }; 133 | } 134 | 135 | private STJsonToken GetSymbol() 136 | { 137 | int n_col = m_n_col; 138 | int n_index = m_n_position, n_len = -1; 139 | for (var i = n_index; i < m_str_json.Length; i++) { 140 | var ch = m_str_json[i]; 141 | if ('a' <= ch && ch <= 'z') continue; 142 | if ('A' <= ch && ch <= 'Z') continue; 143 | if ('0' <= ch && ch <= '9') continue; 144 | if (ch == '_') continue; 145 | n_len = i - n_index; 146 | break; 147 | } 148 | if (n_len == -1) n_len = m_str_json.Length - n_index; 149 | m_n_position += n_len; 150 | m_n_col += n_len; 151 | return new STJsonToken() 152 | { 153 | Type = STJsonTokenType.Symbol, 154 | Index = n_index, 155 | Row = m_n_row, 156 | Col = n_col, 157 | Value = m_str_json.Substring(n_index, n_len) 158 | }; 159 | } 160 | 161 | private STJsonToken GetString() 162 | { 163 | int n_index = m_n_position; 164 | var ch_begin = m_str_json[n_index]; 165 | var token = new STJsonToken() 166 | { 167 | Index = n_index, 168 | Row = m_n_row, 169 | Col = m_n_col++, 170 | Type = STJsonTokenType.String 171 | }; 172 | for (int i = n_index + 1; i < m_str_json.Length; i++) { 173 | var ch = m_str_json[i]; 174 | m_n_col++; 175 | if (ch == ch_begin) { 176 | token.Value = m_str_json.Substring(n_index + 1, i - n_index - 1); 177 | m_n_position += i - n_index + 1; 178 | return token; 179 | } 180 | switch (ch) { 181 | case '\\': 182 | i++; 183 | continue; 184 | case '\n': 185 | m_n_row++; 186 | m_n_col = 1; 187 | continue; 188 | } 189 | } 190 | throw new STJsonParseException(n_index, m_n_row, m_n_col, "Can not get a string. missing '\'' or '\"'."); 191 | } 192 | 193 | private STJsonToken GetComment() 194 | { 195 | // note: str_text[n_index] == '/' 196 | var n_index = m_n_position + 1; 197 | if (n_index >= m_str_json.Length) { 198 | throw new STJsonParseException(m_n_position, m_n_row, m_n_col, "Invalid char '/'."); 199 | } 200 | var ch = m_str_json[n_index]; 201 | switch (ch) { 202 | case '/': return this.GetCommentLine(); 203 | case '*': return this.GetCommentBlock(); 204 | default: 205 | throw new STJsonParseException(n_index, m_n_row, m_n_col, "Invalid char '" + ch + "'."); 206 | } 207 | } 208 | 209 | private STJsonToken GetCommentLine() 210 | { 211 | // note: str_text[n_index:2] == '//' 212 | int n_index = m_n_position, n_len = -1; 213 | m_n_col += 2; 214 | for (int i = n_index + 2; i < m_str_json.Length; i++) { 215 | m_n_col++; 216 | if (m_str_json[i] == '\n') { 217 | n_len = i - n_index + 1; 218 | m_n_row++; 219 | m_n_col = 1; 220 | break; 221 | } 222 | } 223 | if (n_len == -1) n_len = m_str_json.Length - n_index; 224 | m_n_position += n_len; 225 | return new STJsonToken() 226 | { 227 | Type = STJsonTokenType.Comment 228 | }; 229 | } 230 | 231 | private STJsonToken GetCommentBlock() 232 | { 233 | // note: str_text[n_index:2] == '/*' 234 | m_n_col += 2; 235 | int n_index = m_n_position, n_len = -1; 236 | char ch_current = '\0', ch_last = '\0'; 237 | for (int i = n_index + 2; i < m_str_json.Length; i++) { 238 | ch_current = m_str_json[i]; 239 | m_n_col++; 240 | if (ch_current == '\n') { 241 | m_n_row++; 242 | m_n_col = 1; 243 | } else if (ch_current == '/' && ch_last == '*') { 244 | n_len = i - n_index + 1; 245 | break; 246 | } 247 | ch_last = ch_current; 248 | } 249 | if (n_len == -1) n_len = m_str_json.Length - n_index; 250 | m_n_position += n_len; 251 | return new STJsonToken() 252 | { 253 | Type = STJsonTokenType.Comment 254 | }; 255 | } 256 | } 257 | } 258 | 259 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Parser_backup/STJsonParserOld.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.Text; 3 | //using System.Collections.Generic; 4 | 5 | //using ME = STLib.Json.STJsonParserOld; 6 | 7 | //namespace STLib.Json 8 | //{ 9 | // internal class STJsonParserOld 10 | // { 11 | // public static STJson Parse(string str_json) 12 | // { 13 | // var tokens = STJsonTokenizerOld.GetTokens(str_json); 14 | // if (tokens.Count == 0) { 15 | // throw new STJsonParseException(0, "Invalid string."); 16 | // } 17 | // int nIndex = 1; 18 | // if (tokens[0].Value == "{") { 19 | // return ME.GetObject(tokens, ref nIndex); 20 | // } 21 | 22 | // if (tokens[0].Value == "[") { 23 | // return ME.GetArray(tokens, ref nIndex); 24 | // } 25 | // throw new STJsonParseException( 26 | // tokens[0].Index, 27 | // "Invalid char form index [" + tokens[0].Index + "]{" + tokens[0].Value + "}" 28 | // ); 29 | // } 30 | 31 | // private static STJson GetObject(List lst_token, ref int n_index) 32 | // { 33 | // STJson json = new STJson(); 34 | // json.SetModel(STJsonValueType.Object); 35 | // if (lst_token[n_index].Value == "}") { 36 | // n_index++; 37 | // return json; 38 | // } 39 | // while (n_index < lst_token.Count) { 40 | // var token = lst_token[n_index++]; 41 | // if (token.Type != STJsonTokenType.String) { 42 | // throw new STJsonParseException( 43 | // token.Index, 44 | // "Invalid char form index [" + token.Index + "]{" + token.Value + "}" 45 | // ); 46 | // } 47 | // var jv = json.SetKey(token.Value); 48 | // token = lst_token[n_index++]; 49 | // if (token.Value != ":") { 50 | // throw new STJsonParseException( 51 | // token.Index, 52 | // "Invalid char form index [" + token.Index + "]{" + token.Value + "}" 53 | // ); 54 | // } 55 | // token = lst_token[n_index++]; 56 | // switch (token.Type) { 57 | // case STJsonTokenType.Keyword: 58 | // switch (token.Value) { 59 | // case "true": 60 | // jv.SetValue(true); 61 | // break; 62 | // case "false": 63 | // jv.SetValue(false); 64 | // break; 65 | // case "null": 66 | // jv.SetValue(value: null); 67 | // break; 68 | // } 69 | // break; 70 | // case STJsonTokenType.String: 71 | // jv.SetValue(ME.ParseString(token)); 72 | // break; 73 | // case STJsonTokenType.Long: 74 | // jv.SetValue(ME.ParseNumberLong(token)); 75 | // break; 76 | // case STJsonTokenType.Double: 77 | // jv.SetValue(ME.ParseNumberDouble(token)); 78 | // break; 79 | // case STJsonTokenType.ObjectStart: 80 | // jv.SetValue(ME.GetObject(lst_token, ref n_index)); 81 | // break; 82 | // case STJsonTokenType.ArrayStart: 83 | // jv.SetValue(ME.GetArray(lst_token, ref n_index)); 84 | // break; 85 | // default: 86 | // throw new STJsonParseException( 87 | // token.Index, 88 | // "Invalid char form index [" + token.Index + "]{" + token.Value + "}" 89 | // ); 90 | // } 91 | // token = lst_token[n_index++]; 92 | // switch (token.Value) { 93 | // case ",": continue; 94 | // case "}": return json; 95 | // default: 96 | // throw new STJsonParseException( 97 | // token.Index, 98 | // "Invalid char form index [" + token.Index + "]{" + token.Value + "}" 99 | // ); 100 | // } 101 | // } 102 | // throw new STJsonParseException(-1, "Incomplete string."); 103 | // } 104 | 105 | // private static STJson GetArray(List lst_token, ref int n_index) 106 | // { 107 | // STJson json = new STJson(); 108 | // json.SetModel(STJsonValueType.Array); 109 | // if (lst_token[n_index].Value == "]") { 110 | // n_index++; 111 | // return json; 112 | // } 113 | // while (n_index < lst_token.Count) { 114 | // var token = lst_token[n_index++]; 115 | // switch (token.Type) { 116 | // case STJsonTokenType.String: 117 | // json.Append(ME.ParseString(token)); 118 | // break; 119 | // case STJsonTokenType.Long: 120 | // json.Append(ME.ParseNumberLong(token)); 121 | // break; 122 | // case STJsonTokenType.Double: 123 | // json.Append(ME.ParseNumberDouble(token)); 124 | // break; 125 | // case STJsonTokenType.Keyword: 126 | // switch (token.Value) { 127 | // case "true": 128 | // json.Append(true); 129 | // break; 130 | // case "false": 131 | // json.Append(false); 132 | // break; 133 | // case "null": 134 | // json.Append(json: null); 135 | // break; 136 | // } 137 | // break; 138 | // case STJsonTokenType.ObjectStart: 139 | // json.Append(ME.GetObject(lst_token, ref n_index)); 140 | // break; 141 | // case STJsonTokenType.ArrayStart: 142 | // json.Append(ME.GetArray(lst_token, ref n_index)); 143 | // break; 144 | // default: 145 | // throw new STJsonParseException( 146 | // token.Index, 147 | // "Invalid char form index [" + token.Index + "]{" + token.Value + "}" 148 | // ); 149 | // } 150 | // token = lst_token[n_index++]; 151 | // switch (token.Value) { 152 | // case ",": continue; 153 | // case "]": return json; 154 | // default: 155 | // throw new STJsonParseException( 156 | // token.Index, 157 | // "Invalid char form index [" + token.Index + "]{" + token.Value + "}" 158 | // ); 159 | // } 160 | // } 161 | // throw new STJsonParseException(-1, "Incomplete string."); 162 | // } 163 | 164 | // private static long ParseNumberLong(STJsonToken token) 165 | // { 166 | // try { 167 | // return Convert.ToInt64(token.Value); 168 | // } catch { 169 | // throw new STJsonParseException(token.Index, "Can not convert [" + token.Value + "] to long."); 170 | // } 171 | // } 172 | 173 | // private static double ParseNumberDouble(STJsonToken token) 174 | // { 175 | // try { 176 | // return Convert.ToDouble(token.Value); 177 | // } catch { 178 | // throw new STJsonParseException(token.Index, "Can not convert [" + token.Value + "] to double."); 179 | // } 180 | // } 181 | 182 | // private static string ParseString(STJsonToken token) 183 | // { 184 | // int n_hex_len = 0; 185 | // string str_temp = string.Empty; 186 | // StringBuilder sb = new StringBuilder(); 187 | // for (int i = 0; i < token.Value.Length; i++) { 188 | // var ch = token.Value[i]; 189 | // if (ch != '\\') { 190 | // sb.Append(ch); 191 | // continue; 192 | // } 193 | // i++; 194 | // if (i >= token.Value.Length) { 195 | // throw new STJsonParseException(token.Index + i, ch); 196 | // } 197 | // ch = token.Value[i]; 198 | // switch (ch) { 199 | // case 'r': sb.Append('\r'); continue; 200 | // case 'n': sb.Append('\n'); continue; 201 | // case 't': sb.Append('\t'); continue; 202 | // case 'f': sb.Append('\f'); continue; 203 | // case 'b': sb.Append('\b'); continue; 204 | // case 'a': sb.Append('\a'); continue; 205 | // case 'v': sb.Append('\v'); continue; 206 | // case '0': sb.Append('\0'); continue; 207 | // case 'x': 208 | // case 'u': 209 | // n_hex_len = ch == 'x' ? 2 : 4; 210 | // if (i + n_hex_len >= token.Value.Length) { 211 | // throw new STJsonParseException(token.Index + i, ch); 212 | // } 213 | // str_temp = token.Value.Substring(i + 1, n_hex_len); 214 | // try { 215 | // sb.Append((char)Convert.ToUInt16(str_temp, 16)); 216 | // } catch { 217 | // throw new STJsonParseException(token.Index + i, "Invalid string [" + (token.Value.Substring(i + str_temp.Length + 2)) + "]"); 218 | // } 219 | // i += n_hex_len; 220 | // continue; 221 | // default: 222 | // sb.Append(ch); 223 | // continue; 224 | // } 225 | // } 226 | // return sb.ToString(); 227 | // } 228 | // } 229 | //} 230 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/Parser_backup/STJsonTokenizerOld.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.Text; 3 | //using System.Collections.Generic; 4 | 5 | //using ME = STLib.Json.STJsonTokenizerOld; 6 | 7 | //namespace STLib.Json 8 | //{ 9 | // internal class STJsonTokenizerOld 10 | // { 11 | // public static List GetTokens(string str_json) 12 | // { 13 | // var token = new STJsonToken(); 14 | // var lst_token = new List(); 15 | // Stack stack_region = new Stack(); 16 | // for (int i = 0; i < str_json.Length; i++) { 17 | // var c = str_json[i]; 18 | // if (('0' <= c && c <= '9') || c == '-') { 19 | // token = ME.GetNumber(str_json, i); 20 | // lst_token.Add(token); 21 | // i += token.Value.Length - 1; 22 | // continue; 23 | // } 24 | // switch (c) { 25 | // case '{': // object start 26 | // stack_region.Push('{'); 27 | // lst_token.Add(new STJsonToken(i, "{", STJsonTokenType.ObjectStart)); 28 | // continue; 29 | // case '[': // array start 30 | // stack_region.Push('['); 31 | // lst_token.Add(new STJsonToken(i, "[", STJsonTokenType.ArrayStart)); 32 | // continue; 33 | // case ',': // item splitor 34 | // lst_token.Add(new STJsonToken(i, ",", STJsonTokenType.ItemSplitor)); 35 | // continue; 36 | // case ':': // key value splitor 37 | // lst_token.Add(new STJsonToken(i, ":", STJsonTokenType.KVSplitor)); 38 | // continue; 39 | // case ']': // array end 40 | // if (stack_region.Count == 0 || stack_region.Pop() != '[') { 41 | // throw new STJsonParseException(i, "Invalid char, missing '[' or '}'. Index: " + i); 42 | // } 43 | // lst_token.Add(new STJsonToken(i, "]", STJsonTokenType.ArrayEnd)); 44 | // continue; 45 | // case '}': // object end 46 | // if (stack_region.Count == 0 || stack_region.Pop() != '{') { 47 | // throw new STJsonParseException(i, "Invalid char, missing '[' or '}'. Index: " + i); 48 | // } 49 | // lst_token.Add(new STJsonToken(i, "}", STJsonTokenType.ObjectEnd)); 50 | // continue; 51 | // case 't': // [keyword] - true 52 | // lst_token.Add(ME.GetKeyword(str_json, i, "true")); 53 | // i += 3; 54 | // continue; 55 | // case 'f': // [keyword] - false 56 | // lst_token.Add(ME.GetKeyword(str_json, i, "false")); 57 | // i += 4; 58 | // continue; 59 | // case 'n': // [keyword] - null 60 | // lst_token.Add(ME.GetKeyword(str_json, i, "null")); 61 | // i += 3; 62 | // continue; 63 | // case '"': // string 64 | // token = ME.GetString(str_json, i); 65 | // i += token.Value.Length + 1; 66 | // lst_token.Add(token); 67 | // continue; 68 | // case ' ': 69 | // case '\r': // space 70 | // case '\n': 71 | // case '\t': 72 | // continue; 73 | // default: 74 | // throw new STJsonParseException(i, "Invalid char. Index: " + i); 75 | // } 76 | // } 77 | // return lst_token; 78 | // } 79 | 80 | // private static STJsonToken GetNumber(string str_text, int n_index) 81 | // { 82 | // bool b_float = false; 83 | // int n_len = -1; 84 | // for (int i = 0; i < str_text.Length; i++) { 85 | // var ch = str_text[i]; 86 | // switch (ch) { 87 | // case '+': 88 | // case '-': 89 | // continue; 90 | // case '.': 91 | // case 'E': 92 | // case 'e': 93 | // b_float = true; 94 | // continue; 95 | // } 96 | // if ('0' <= ch && ch <= '9') continue; 97 | // break; 98 | // } 99 | // return new STJsonToken() 100 | // { 101 | // Index = n_index, 102 | // Type = b_float ? STJsonTokenType.Double : STJsonTokenType.Long, 103 | // Value = n_len == -1 ? str_text.Substring(n_index) : str_text.Substring(n_index, n_len) 104 | // }; 105 | // } 106 | 107 | // /*private static STJsonToken GetNumber(string strText, int nIndex) 108 | // { 109 | // bool bDot = false, bE = false; 110 | // var token = new STJsonToken() 111 | // { 112 | // Index = nIndex, 113 | // Type = STJsonTokenType.Long 114 | // }; 115 | // for (int i = nIndex; i < strText.Length; i++) { 116 | // var c = strText[i]; 117 | // if (c == '-') { // -123 118 | // if (i != nIndex) { 119 | // throw new STJsonParseException(i, "Invalid char. Index: " + i); 120 | // } 121 | // continue; 122 | // } 123 | // if (c == '.') { // 1.23 124 | // if (bDot || bE || i == nIndex || strText[i - 1] == '-') { 125 | // throw new STJsonParseException(i, "Invalid char. Index: " + i); 126 | // } 127 | // bDot = true; 128 | // token.Type = STJsonTokenType.Double; 129 | // continue; 130 | // } 131 | // if (c == 'E' || c == 'e') { // 12E+3 Regex:-?\d+(\.\d+)?E[+-]?(\d+) 132 | // if (bE || i == nIndex || strText[i - 1] == '-' || strText[i - 1] == '.') { 133 | // throw new STJsonParseException(i, "Invalid char. Index: " + i); 134 | // } 135 | // if (i + 2 >= strText.Length) { 136 | // throw new STJsonParseException(i, "Invalid char. Index: " + i); 137 | // } 138 | // c = strText[++i]; 139 | // if (c == '-' || c == '+') { // E+ | E- 140 | // c = strText[++i]; 141 | // } 142 | // //if (strText[++i] != '+') { // E+ 143 | // // throw new STJsonParseException(i + 1, "Invalid char. Index: " + (i + 1)); 144 | // //} 145 | // bE = true; 146 | // //c = strText[++i]; 147 | // if (c < '0' || '9' < c) { // E+[0-9] 148 | // throw new STJsonParseException(i + 2, "Invalid char. Index: " + (i + 2)); 149 | // } 150 | // token.Type = STJsonTokenType.Double; 151 | // continue; 152 | // } 153 | // if ('0' <= c && c <= '9') continue; 154 | // token.Value = strText.Substring(nIndex, i - nIndex); 155 | // return token; 156 | // } 157 | // token.Value = strText.Substring(nIndex); 158 | // return token; 159 | // }*/ 160 | 161 | // private static STJsonToken GetKeyword(string str_text, int n_index, string str_keyword) 162 | // { 163 | // var token = new STJsonToken() 164 | // { 165 | // Index = n_index, 166 | // Type = STJsonTokenType.Keyword 167 | // }; 168 | // if (str_text.Substring(n_index, str_keyword.Length) == str_keyword) { 169 | // token.Value = str_keyword; 170 | // return token; 171 | // } 172 | // throw new STJsonParseException(n_index, "Invalid char. Index: " + n_index); 173 | // } 174 | 175 | // private static STJsonToken GetString(string str_text, int n_index) 176 | // { 177 | // var token = new STJsonToken() 178 | // { 179 | // Index = n_index, 180 | // Type = STJsonTokenType.String 181 | // }; 182 | // if (str_text[n_index] != '"') { 183 | // return token; 184 | // } 185 | // for (int i = n_index + 1; i < str_text.Length; i++) { 186 | // var ch = str_text[i]; 187 | // switch (ch) { 188 | // case '\n': 189 | // throw new STJsonParseException(i, "Invalid char(\\n) for a string. Index: " + i); 190 | // case '\\': 191 | // i++; 192 | // continue; 193 | // case '"': 194 | // token.Value = str_text.Substring(n_index + 1, i - n_index - 1); 195 | // return token; 196 | // } 197 | // } 198 | // throw new STJsonParseException(n_index, "Can not get a string. Index: " + n_index); 199 | // } 200 | // } 201 | //} -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/STJsonReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | using System.IO; 7 | using System.Collections; 8 | 9 | namespace STLib.Json 10 | { 11 | public class STJsonReader : IEnumerable, IDisposable 12 | { 13 | private class StackInfo 14 | { 15 | public char Symbol { get; set; } 16 | public int Level { get; set; } 17 | public string Key { get; set; } 18 | public int Index { get; set; } 19 | 20 | public StackInfo(char ch_symbol, int n_level) 21 | { 22 | this.Symbol = ch_symbol; 23 | this.Level = n_level; 24 | } 25 | } 26 | 27 | public bool Disposed { get; private set; } 28 | public bool IsAutoClose { get; private set; } 29 | 30 | internal STJsonTokenReader TokenReader { get { return m_token_reader; } } 31 | 32 | private bool m_b_started; 33 | private STJsonTokenReader m_token_reader; 34 | private Stack m_stack_path = new Stack(); 35 | 36 | private StackInfo m_current_stack = null; 37 | private List m_lst_stack_info = new List(16); 38 | 39 | public STJsonReader(string str_file) : this(new StreamReader(str_file, Encoding.UTF8), true) { } 40 | 41 | public STJsonReader(TextReader reader) : this(reader, true) { } 42 | 43 | public STJsonReader(TextReader reader, bool is_auto_close) 44 | { 45 | this.IsAutoClose = is_auto_close; 46 | m_token_reader = new STJsonTokenReader(reader, is_auto_close); 47 | } 48 | 49 | public IEnumerator GetEnumerator() 50 | { 51 | STJsonReaderItem item = null; 52 | while ((item = this.GetNextItem()) != null) { 53 | yield return item; 54 | } 55 | this.Dispose(); 56 | } 57 | 58 | public STJsonReaderItem GetNextItem() 59 | { 60 | this.CheckStarted(); 61 | STJsonReaderItem item = null; 62 | if (m_current_stack != null) { 63 | switch (m_current_stack.Symbol) { 64 | case '{': // '{' 65 | item = this.GetNextObjectKV(); 66 | break; 67 | default: // '[' 68 | item = this.GetNextArrayItem(); 69 | break; 70 | } 71 | } 72 | if (item == null) { 73 | this.Dispose(); 74 | } 75 | return item; 76 | } 77 | 78 | public void Dispose() 79 | { 80 | if (this.Disposed) { 81 | return; 82 | } 83 | this.Disposed = true; 84 | m_current_stack = null; 85 | m_stack_path.Clear(); 86 | m_lst_stack_info.Clear(); 87 | m_token_reader.Dispose(); 88 | } 89 | 90 | // ===================================== 91 | 92 | internal void PushStack(char ch_symbol, int n_level) 93 | { 94 | m_current_stack = new StackInfo(ch_symbol, n_level); 95 | m_lst_stack_info.Add(m_current_stack); 96 | } 97 | 98 | internal void PopStack() 99 | { 100 | m_current_stack = null; 101 | if (m_lst_stack_info.Count == 0) return; 102 | m_lst_stack_info.RemoveAt(m_lst_stack_info.Count - 1); 103 | if (m_lst_stack_info.Count == 0) return; 104 | m_current_stack = m_lst_stack_info[m_lst_stack_info.Count - 1]; 105 | } 106 | 107 | // ===================================== 108 | 109 | private void CheckStarted() 110 | { 111 | if (!m_b_started) { 112 | m_b_started = true; 113 | var token = this.GetNextFilteredToken(); 114 | if (token.Type == STJsonTokenType.None) { 115 | return; 116 | } 117 | switch (token.Type) { 118 | case STJsonTokenType.ObjectStart: 119 | case STJsonTokenType.ArrayStart: 120 | break; 121 | default: 122 | throw new STJsonParseException(token); 123 | } 124 | this.PushStack(token.Value[0], 0); 125 | } 126 | } 127 | 128 | private STJsonToken GetNextFilteredToken() 129 | { 130 | foreach (var v in m_token_reader) { 131 | switch (v.Type) { 132 | case STJsonTokenType.KVSplitor: // : 133 | case STJsonTokenType.ItemSplitor: // , 134 | continue; 135 | default: 136 | return v; 137 | } 138 | } 139 | return STJsonToken.None; 140 | } 141 | 142 | private STJsonReaderItem GetNextObjectKV() 143 | { 144 | var token_key = this.GetNextFilteredToken(); 145 | switch (token_key.Type) { 146 | case STJsonTokenType.None: 147 | return null; 148 | case STJsonTokenType.ObjectEnd: 149 | this.PopStack(); 150 | return this.GetNextItem(); 151 | case STJsonTokenType.Symbol: 152 | case STJsonTokenType.String: 153 | break; 154 | default: 155 | throw new STJsonParseException(token_key); 156 | } 157 | m_current_stack.Key = token_key.Value; 158 | var token_val = this.GetNextFilteredToken(); 159 | if (token_val.Type == STJsonTokenType.None) { 160 | return null; 161 | //throw new Exception("error"); 162 | } 163 | var item = new STJsonReaderItem(this, token_val) 164 | { 165 | ParentType = STJsonValueType.Object, 166 | Key = token_key.Value, 167 | Text = token_val.Value 168 | }; 169 | return this.CheckValueToken(item, token_val); 170 | } 171 | 172 | private STJsonReaderItem GetNextArrayItem() 173 | { 174 | var token = this.GetNextFilteredToken(); 175 | switch (token.Type) { 176 | case STJsonTokenType.None: 177 | return null; 178 | case STJsonTokenType.ArrayEnd: 179 | this.PopStack(); 180 | return this.GetNextItem(); 181 | } 182 | var item = new STJsonReaderItem(this, token) 183 | { 184 | ParentType = STJsonValueType.Array, 185 | Index = m_current_stack.Index++, 186 | Text = token.Value 187 | }; 188 | return this.CheckValueToken(item, token); 189 | } 190 | 191 | private STJsonReaderItem CheckValueToken(STJsonReaderItem item, STJsonToken token) 192 | { 193 | this.SetItemPath(item); 194 | switch (token.Type) { 195 | case STJsonTokenType.ObjectStart: 196 | item.ValueType = STJsonValueType.Object; 197 | item.Text = "{...}"; 198 | this.PushStack('{', m_current_stack.Level + 1); 199 | return item; 200 | case STJsonTokenType.ArrayStart: 201 | item.ValueType = STJsonValueType.Array; 202 | item.Text = "[...]"; 203 | this.PushStack('[', m_current_stack.Level + 1); 204 | return item; 205 | case STJsonTokenType.Double: 206 | item.ValueType = STJsonValueType.Double; 207 | return item; 208 | case STJsonTokenType.Long: 209 | item.ValueType = STJsonValueType.Long; 210 | return item; 211 | case STJsonTokenType.String: 212 | item.ValueType = STJsonValueType.String; 213 | return item; 214 | case STJsonTokenType.Symbol: 215 | switch (token.Value) { 216 | case "true": 217 | case "false": 218 | item.ValueType = STJsonValueType.Boolean; 219 | return item; 220 | case "null": 221 | case "undefined": 222 | item.ValueType = STJsonValueType.Object; 223 | return item; 224 | } 225 | break; 226 | } 227 | throw new STJsonParseException(token); 228 | } 229 | 230 | private void SetItemPath(STJsonReaderItem item) 231 | { 232 | int n_index = 0; 233 | var str_path = string.Empty; 234 | object[] obj_path = new object[m_lst_stack_info.Count]; 235 | foreach (var v in m_lst_stack_info) { 236 | switch (v.Symbol) { 237 | case '{': 238 | if (n_index != 0) str_path += '.'; 239 | obj_path[n_index++] = v.Key; 240 | if (v.Key.IndexOf('.') != -1) { 241 | str_path += "'" + v.Key.Replace("'", "\\'") + "'"; 242 | } else { 243 | str_path += v.Key; 244 | } 245 | break; 246 | case '[': 247 | obj_path[n_index++] = v.Index - 1; // m_current_index++; 248 | str_path += "[" + (v.Index - 1) + ']'; 249 | break; 250 | } 251 | } 252 | item.Path = str_path; 253 | item.PathArray = obj_path; 254 | } 255 | 256 | // =================================================== 257 | 258 | IEnumerator IEnumerable.GetEnumerator() 259 | { 260 | return this.GetEnumerator(); 261 | } 262 | 263 | IEnumerator IEnumerable.GetEnumerator() 264 | { 265 | return this.GetEnumerator(); 266 | } 267 | 268 | void IDisposable.Dispose() 269 | { 270 | this.Dispose(); 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/STJsonReaderItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace STLib.Json 7 | { 8 | public class STJsonReaderItem 9 | { 10 | public string Path { get; internal set; } 11 | public object PathArray { get; internal set; } 12 | public string Key { get; internal set; } 13 | public int Index { get; internal set; } 14 | public string Text { get; internal set; } 15 | public STJsonValueType ParentType { get; internal set; } 16 | public STJsonValueType ValueType { get; internal set; } 17 | 18 | private STJsonReader m_reader; 19 | private STJsonToken m_value_token; 20 | 21 | internal STJsonReaderItem(STJsonReader reader, STJsonToken token) 22 | { 23 | m_reader = reader; 24 | m_value_token = token; 25 | } 26 | 27 | public STJson GetSTJson() 28 | { 29 | switch (this.ValueType) { 30 | case STJsonValueType.String: 31 | return STJson.FromObject(this.Text); 32 | case STJsonValueType.Double: 33 | return STJson.FromObject(double.Parse(this.Text)); 34 | case STJsonValueType.Long: 35 | return STJson.FromObject(long.Parse(this.Text)); 36 | case STJsonValueType.Boolean: 37 | return STJson.FromObject(bool.Parse(this.Text)); 38 | case STJsonValueType.Array: 39 | return this.GetArray(); 40 | case STJsonValueType.Object: 41 | return this.GetObject(); 42 | } 43 | return new STJson(); 44 | } 45 | 46 | private STJson GetObject() 47 | { 48 | int n_counter = 1; 49 | List lst_token = new List() { m_value_token }; 50 | foreach (var token in m_reader.TokenReader) { 51 | lst_token.Add(token); 52 | switch (token.Type) { 53 | case STJsonTokenType.ObjectStart: 54 | n_counter++; 55 | continue; 56 | case STJsonTokenType.ObjectEnd: 57 | if (--n_counter == 0) { 58 | break; 59 | } 60 | continue; 61 | default: continue; 62 | } 63 | break; 64 | } 65 | m_reader.PopStack(); 66 | return STJsonParser.Parse(lst_token); 67 | } 68 | 69 | private STJson GetArray() 70 | { 71 | int n_counter = 1; 72 | List lst_token = new List() { m_value_token }; 73 | foreach (var token in m_reader.TokenReader) { 74 | lst_token.Add(token); 75 | switch (token.Type) { 76 | case STJsonTokenType.ArrayStart: 77 | n_counter++; 78 | continue; 79 | case STJsonTokenType.ArrayEnd: 80 | if (--n_counter == 0) { 81 | break; 82 | } 83 | continue; 84 | default: continue; 85 | } 86 | break; 87 | } 88 | m_reader.PopStack(); 89 | return STJsonParser.Parse(lst_token); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/STJsonSetting.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonSetting 6 | { 7 | public static STJsonSetting Default = new STJsonSetting(); 8 | 9 | public enum KeyMode 10 | { 11 | All, Include, Exclude 12 | } 13 | 14 | public bool EnumUseNumber { get; set; } 15 | public bool IgnoreAttribute { get; set; } 16 | public bool IgnoreNullValue { get; set; } 17 | public KeyMode Mode { get; set; } 18 | public HashSet KeyList { get; private set; } 19 | 20 | public STJsonSetting() 21 | { 22 | this.KeyList = new HashSet(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJson/STJsonWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | using System.IO; 7 | 8 | namespace STLib.Json 9 | { 10 | public delegate void STJsonWriterCallback(); 11 | public delegate void STJsonWriterStartCallback(STJsonWriter writer); 12 | 13 | public class STJsonWriter : IDisposable 14 | { 15 | private enum LevelType { None, Object, Array } 16 | private class StackInfo 17 | { 18 | public int ItemCount { get; set; } 19 | public int Level { get; private set; } 20 | public LevelType LeveType { get; private set; } 21 | public string Space { get; private set; } 22 | 23 | public StackInfo(int n_level, LevelType type, string str_space) 24 | { 25 | this.Level = n_level; 26 | this.LeveType = type; 27 | this.Space = str_space; 28 | } 29 | } 30 | 31 | //==================================================== 32 | 33 | private bool m_b_start; 34 | private Stack m_stack = new Stack(); 35 | private StackInfo m_current_stack = null; 36 | 37 | private TextWriter m_writer; 38 | 39 | public bool Disposed { get; private set; } 40 | public bool IsAutoClose { get; private set; } 41 | public int SpaceCount { get; private set; } 42 | 43 | public int Level 44 | { 45 | get { 46 | return m_current_stack == null ? 0 : m_current_stack.Level; 47 | } 48 | } 49 | 50 | public STJsonValueType ValueType 51 | { 52 | get { 53 | if (m_current_stack == null) return STJsonValueType.Undefined; 54 | switch (m_current_stack.LeveType) { 55 | case LevelType.Array: 56 | return STJsonValueType.Array; 57 | case LevelType.Object: 58 | return STJsonValueType.Object; 59 | } 60 | return STJsonValueType.Undefined; 61 | } 62 | } 63 | 64 | public STJsonWriter(string str_file) : this(new StreamWriter(str_file, false, Encoding.UTF8), true, 0) { } 65 | 66 | public STJsonWriter(string str_file, int n_space_count) : this(new StreamWriter(str_file, false, Encoding.UTF8), true, n_space_count) { } 67 | 68 | public STJsonWriter(TextWriter writer) : this(writer, true, 0) { } 69 | 70 | public STJsonWriter(TextWriter writer, int n_space_count) : this(writer, true, n_space_count) { } 71 | 72 | public STJsonWriter(TextWriter writer, bool is_auto_close, int n_space_count) 73 | { 74 | m_writer = writer; 75 | this.IsAutoClose = is_auto_close; 76 | this.SpaceCount = n_space_count; 77 | if (this.SpaceCount < 0) { 78 | this.SpaceCount = 0; 79 | } 80 | this.PushStack(0, LevelType.None); 81 | } 82 | 83 | public void StartWithObject(STJsonWriterStartCallback callback) 84 | { 85 | if (m_b_start) throw new STJsonWriterException("It's already started."); 86 | m_b_start = true; 87 | this.CheckDisposedOrStarted(); 88 | this.CreateObject(callback, null); 89 | } 90 | 91 | public void StartWithArray(STJsonWriterStartCallback callback) 92 | { 93 | if (m_b_start) throw new STJsonWriterException("It's already started."); 94 | m_b_start = true; 95 | this.CheckDisposedOrStarted(); 96 | this.CreateArray(callback, null); 97 | } 98 | 99 | public STJsonWriter Append(object value) 100 | { 101 | this.CheckDisposedOrStarted(); 102 | if (m_current_stack.LeveType != LevelType.Array) { // check current level 103 | throw new STJsonWriterException("Current level is not a array. The current operation is only available at the array level."); 104 | } 105 | if (m_current_stack.ItemCount > 0) { // not the first item need add (,) 106 | m_writer.Write(','); 107 | } 108 | if (this.SpaceCount != 0) { 109 | m_writer.Write("\r\n" + m_current_stack.Space); 110 | ObjectToString.Get(m_writer, m_current_stack.Level, this.SpaceCount, value, STJsonSetting.Default); 111 | } else { 112 | m_writer.Write(STJson.Serialize(value)); 113 | } 114 | m_current_stack.ItemCount++; 115 | return this; 116 | } 117 | 118 | public STJsonWriter SetItem(string str_key, object value) 119 | { 120 | this.CheckDisposedOrStarted(); 121 | if (m_current_stack.LeveType != LevelType.Object) { 122 | throw new STJsonWriterException("Current level is not a object. The current operation is only available at the object level."); 123 | } 124 | if (m_current_stack.ItemCount++ > 0) { 125 | m_writer.Write(','); 126 | } 127 | var str_text = "\"" + STJson.Escape(str_key) + "\":"; 128 | if (this.SpaceCount != 0) { 129 | m_writer.Write("\r\n" + m_current_stack.Space + str_text + " "); 130 | ObjectToString.Get(m_writer, m_current_stack.Level, this.SpaceCount, value, STJsonSetting.Default); 131 | } else { 132 | m_writer.Write(str_text + STJson.Serialize(value)); 133 | } 134 | return this; 135 | } 136 | 137 | public STJsonWriter SetObject(string str_key, STJsonWriterCallback callback) 138 | { 139 | return this.SetObject(str_key, true, callback); 140 | } 141 | 142 | public STJsonWriter SetObject(string str_key, bool b_express, STJsonWriterCallback callback) 143 | { 144 | if (!b_express) return this; 145 | this.CheckDisposedOrStarted(); 146 | this.SetKey(str_key).CreateObject(null, callback); 147 | return this; 148 | } 149 | 150 | public STJsonWriter SetArray(string str_key, STJsonWriterCallback callback) 151 | { 152 | return this.SetArray(str_key, true, callback); 153 | } 154 | 155 | public STJsonWriter SetArray(string str_key, bool b_express, STJsonWriterCallback callback) 156 | { 157 | if (!b_express) return this; 158 | this.CheckDisposedOrStarted(); 159 | this.SetKey(str_key).CreateArray(null, callback); 160 | return this; 161 | } 162 | 163 | public STJsonWriter CreateObject(STJsonWriterCallback callback) 164 | { 165 | this.CheckDisposedOrStarted(); 166 | if (m_current_stack.LeveType != LevelType.Array) { 167 | throw new STJsonWriterException("Current level is not a array. The current operation is only available at the array level."); 168 | } 169 | if (m_current_stack.ItemCount++ > 0) { 170 | m_writer.Write(','); 171 | } 172 | if (this.SpaceCount != 0) { 173 | m_writer.Write("\r\n" + m_current_stack.Space); 174 | } 175 | 176 | return this.CreateObject(null, callback); 177 | } 178 | 179 | public STJsonWriter CreateArray(STJsonWriterCallback callback) 180 | { 181 | this.CheckDisposedOrStarted(); 182 | if (m_current_stack.LeveType != LevelType.Array) { 183 | throw new STJsonWriterException("Current level is not a array. The current operation is only available at the array level."); 184 | } 185 | if (m_current_stack.ItemCount++ > 0) { 186 | m_writer.Write(','); 187 | } 188 | if (this.SpaceCount != 0) { 189 | m_writer.Write("\r\n" + m_current_stack.Space); 190 | } 191 | 192 | return this.CreateArray(null, callback); 193 | } 194 | 195 | public void Dispose() 196 | { 197 | if (this.Disposed) return; 198 | this.Disposed = true; 199 | m_stack.Clear(); 200 | //if (m_writer == null) return; 201 | m_writer.Flush(); 202 | if (this.IsAutoClose) m_writer.Dispose(); 203 | } 204 | 205 | void IDisposable.Dispose() 206 | { 207 | this.Dispose(); 208 | } 209 | 210 | //================================== 211 | 212 | private void CheckDisposedOrStarted() 213 | { 214 | if (this.Disposed) { 215 | throw new ObjectDisposedException(nameof(STJsonWriter)); 216 | } 217 | if (!m_b_start) { 218 | throw new STJsonWriterException("Cannot complete the current operation. Please call StartWithObject/Array() first."); 219 | } 220 | } 221 | 222 | private STJsonWriter CreateObject(STJsonWriterStartCallback start_callback, STJsonWriterCallback callback) 223 | { 224 | 225 | this.PushStack(m_current_stack.Level + 1, LevelType.Object); 226 | 227 | m_writer.Write('{'); 228 | 229 | if (start_callback != null) { 230 | start_callback(this); 231 | } else { 232 | callback(); 233 | } 234 | int n_item_count = m_current_stack.ItemCount; 235 | 236 | this.PopStack(); 237 | 238 | if (this.SpaceCount != 0 && n_item_count != 0) { 239 | m_writer.Write("\r\n" + m_current_stack.Space); 240 | } 241 | m_writer.Write('}'); 242 | return this; 243 | } 244 | 245 | private STJsonWriter CreateArray(STJsonWriterStartCallback start_callback, STJsonWriterCallback callback) 246 | { 247 | this.PushStack(m_current_stack.Level + 1, LevelType.Array); 248 | 249 | m_writer.Write('['); 250 | 251 | if (start_callback != null) { 252 | start_callback(this); 253 | } else { 254 | callback(); 255 | } 256 | int n_item_count = m_current_stack.ItemCount; 257 | 258 | this.PopStack(); 259 | 260 | if (this.SpaceCount != 0 && n_item_count != 0) { 261 | m_writer.Write("\r\n" + m_current_stack.Space); 262 | } 263 | m_writer.Write(']'); 264 | return this; 265 | } 266 | 267 | private void PushStack(int n_level, LevelType type) 268 | { 269 | var str_space = "".PadRight(n_level * this.SpaceCount); 270 | m_current_stack = new StackInfo(n_level, type, str_space); 271 | m_stack.Push(m_current_stack); 272 | } 273 | 274 | private void PopStack() 275 | { 276 | m_current_stack = null; 277 | if (m_stack.Count == 0) return; 278 | m_stack.Pop(); 279 | if (m_stack.Count == 0) return; 280 | m_current_stack = m_stack.Peek(); 281 | } 282 | 283 | private STJsonWriter SetKey(string str_key) 284 | { 285 | if (m_current_stack.LeveType != LevelType.Object) { 286 | throw new STJsonWriterException("Current level is not a object. The current operation is only available at the object level."); 287 | } 288 | if (m_current_stack.ItemCount++ > 0) { 289 | m_writer.Write(','); 290 | } 291 | var str_text = "\"" + STJson.Escape(str_key) + "\":"; 292 | if (this.SpaceCount != 0) { 293 | m_writer.Write("\r\n" + m_current_stack.Space + str_text + " "); 294 | } else { 295 | m_writer.Write(str_text); 296 | } 297 | return this; 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJsonPath/Exceptions/STJsonPathException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonPathException : Exception 6 | { 7 | public STJsonPathException(string strErr) : base(strErr) { 8 | } 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJsonPath/Exceptions/STJsonPathParseException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace STLib.Json 4 | { 5 | public class STJsonPathParseException : Exception 6 | { 7 | public int Index { get; private set; } 8 | 9 | public STJsonPathParseException(int nIndex, string strError) : base(strError) { 10 | this.Index = nIndex; 11 | } 12 | 13 | public STJsonPathParseException(int nIndex, char ch) 14 | : base("Can not parse the string. Index: " + nIndex + ", char: [" + ch + "]") { 15 | this.Index = nIndex; 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJsonPath/STJsonPath.DataType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace STLib.Json 5 | { 6 | public enum STJsonPathSelectMode 7 | { 8 | ItemOnly, ItemWithPath, KeepStructure 9 | } 10 | 11 | public class STJsonPathCallbackArgs 12 | { 13 | public bool Selected { get; set; } 14 | public STJson Path { get; internal set; } 15 | public STJson Json { get; set; } 16 | } 17 | 18 | public struct SelectSetting 19 | { 20 | public STJson Root; 21 | public STJsonPathSelectMode Mode; 22 | public Stack Path; 23 | public STJsonPathCallBack Callback; 24 | 25 | public static SelectSetting Create() 26 | { 27 | return new SelectSetting() 28 | { 29 | Path = new Stack() 30 | }; 31 | } 32 | } 33 | 34 | 35 | public delegate void STJsonPathCallBack(STJsonPathCallbackArgs args); 36 | public delegate STJson STJsonPathCustomFunctionHander(STJsonPathExpressionFunctionArg[] args); 37 | 38 | public enum STJsonPathExpressionFunctionArgType 39 | { 40 | Undefined, Long, Double, String, Boolean, Array, Object, 41 | } 42 | 43 | public struct STJsonPathExpressionFunctionArg 44 | { 45 | public STJsonPathExpressionFunctionArgType Type; 46 | public object Value; 47 | } 48 | 49 | 50 | /* ================================================== internal ================================================== */ 51 | 52 | 53 | //========================================================== 54 | internal delegate STJsonPathExpressionToken STJsonPathBuildInFuncHander(STJsonPathExpressionToken[] args); 55 | //========================================================== 56 | 57 | internal enum STJsonPathExpressionTokenType 58 | { 59 | Undefined, Long, Double, String, Boolean, Array, Object, ArrayExp, Func, PathItem, Operator, LeftParentheses, RightParentheses, Error 60 | } 61 | 62 | internal struct STJsonPathExpressionToken 63 | { 64 | 65 | public static readonly STJsonPathExpressionToken Undefined = new STJsonPathExpressionToken() { Type = STJsonPathExpressionTokenType.Undefined }; 66 | public static STJsonPathExpressionToken True = STJsonPathExpressionToken.Create(-1, STJsonPathExpressionTokenType.Boolean, true); 67 | public static STJsonPathExpressionToken False = STJsonPathExpressionToken.Create(-1, STJsonPathExpressionTokenType.Boolean, false); 68 | 69 | public bool IsNumber 70 | { 71 | get { return this.Type == STJsonPathExpressionTokenType.Long || this.Type == STJsonPathExpressionTokenType.Double; } 72 | } 73 | 74 | public string Text 75 | { 76 | get { 77 | if (this.Type == STJsonPathExpressionTokenType.Operator) { 78 | return " " + this.Value + " "; 79 | } 80 | if (this.Type == STJsonPathExpressionTokenType.PathItem) { 81 | string strItem = string.Empty; 82 | foreach (var v in this.PathItems) { 83 | strItem += v.Text; 84 | } 85 | return strItem.Trim(); 86 | } 87 | if (this.Type == STJsonPathExpressionTokenType.Func) { 88 | string strFunc = this.Value + "("; 89 | foreach (var v in this.Args) { 90 | strFunc += v.Text + ", "; 91 | } 92 | strFunc = strFunc.Trim().Trim(',') + ")"; 93 | if (this.PathItems == null || this.PathItems.Count < 1) { 94 | return strFunc; 95 | } 96 | strFunc += "."; 97 | for (int i = 1; i < this.PathItems.Count; i++) { 98 | strFunc += this.PathItems[i].Text + "."; 99 | } 100 | return strFunc.Trim('.'); 101 | } 102 | if (this.Type == STJsonPathExpressionTokenType.Array) { 103 | List lst = new List(); 104 | foreach (var v in this.Value as STJsonPathExpressionToken[]) { 105 | switch (v.Type) { 106 | case STJsonPathExpressionTokenType.String: 107 | lst.Add("'" + STJson.Escape(v.Text) + "'"); 108 | break; 109 | default: 110 | lst.Add(v.Text); 111 | break; 112 | } 113 | } 114 | return "[" + string.Join(",", lst.ToArray()) + "]"; 115 | } 116 | if (this.Type == STJsonPathExpressionTokenType.ArrayExp) { 117 | List lst = new List(); 118 | foreach (var v in this.Value as STJsonPathExpression[]) { 119 | lst.Add(v.Text); 120 | } 121 | return "[" + string.Join(",", lst.ToArray()) + "]"; 122 | } 123 | if (this.Type == STJsonPathExpressionTokenType.Undefined) { 124 | return "undefined"; 125 | } 126 | if (this.Type == STJsonPathExpressionTokenType.Boolean) { 127 | return Convert.ToString(this.Value).ToLower(); 128 | } 129 | return Convert.ToString(this.Value); 130 | } 131 | } 132 | 133 | public int Index; 134 | public STJsonPathExpressionTokenType Type; 135 | public object Value; 136 | public List Args; 137 | public List PathItems; 138 | 139 | public static STJsonPathExpressionToken CreateError(string str_error) { 140 | return new STJsonPathExpressionToken() 141 | { 142 | Index = -1, 143 | Type = STJsonPathExpressionTokenType.Error, 144 | Value = str_error 145 | }; 146 | } 147 | 148 | public static STJsonPathExpressionToken Create(int nIndex, STJsonPathExpressionTokenType type, object value) 149 | { 150 | return new STJsonPathExpressionToken() 151 | { 152 | Index = nIndex, 153 | Type = type, 154 | Value = value 155 | }; 156 | } 157 | 158 | public static STJsonPathExpressionToken Create(int nIndex, List items) 159 | { 160 | return new STJsonPathExpressionToken() 161 | { 162 | Index = nIndex, 163 | Type = STJsonPathExpressionTokenType.PathItem, 164 | PathItems = items 165 | }; 166 | } 167 | 168 | public static STJsonPathExpressionToken Create(int nIndex, string strFuncName, List args, List items) 169 | { 170 | return new STJsonPathExpressionToken() 171 | { 172 | Index = nIndex, 173 | Type = STJsonPathExpressionTokenType.Func, 174 | Value = strFuncName, 175 | Args = args, 176 | PathItems = items 177 | }; 178 | } 179 | 180 | public override string ToString() 181 | { 182 | return "[" + this.Type.ToString() + "] - (" + this.Value + ")"; 183 | } 184 | } 185 | //======================================= 186 | internal enum STJsonPathTokenType 187 | { 188 | None, Dot, Property, Operator, Long, Double, String, Keyword, Range 189 | } 190 | 191 | internal struct STJsonPathToken 192 | { 193 | public int Index; 194 | public string Value; 195 | public STJsonPathTokenType Type; 196 | 197 | public bool IsNumber 198 | { 199 | get { return this.Type == STJsonPathTokenType.Long || this.Type == STJsonPathTokenType.Double; } 200 | } 201 | 202 | public STJsonPathToken(int nIndex, string strValue, STJsonPathTokenType type) 203 | { 204 | this.Index = nIndex; 205 | this.Value = strValue; 206 | this.Type = type; 207 | } 208 | 209 | public bool IsSymbol(string strSmb) 210 | { 211 | return this.Value == strSmb && this.Type != STJsonPathTokenType.String; 212 | } 213 | 214 | public override string ToString() 215 | { 216 | return string.Format("\"{0}\" - [{1}] - [{2}]", this.Value, this.Index, this.Type); 217 | } 218 | } 219 | } 220 | 221 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJsonPath/STJsonPath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using ME = STLib.Json.STJsonPath; 5 | 6 | namespace STLib.Json 7 | { 8 | public partial class STJsonPath 9 | { 10 | private static char[] m_char_trim = new char[] { '$', '@' }; 11 | public string Name { get; set; } 12 | public string SourceText { get; private set; } 13 | 14 | private List m_lst_items; 15 | 16 | public STJsonPath(string strPath) : this(strPath, strPath) { } 17 | 18 | public STJsonPath(string strName, string strPath) { 19 | this.SourceText = strPath; 20 | if (string.IsNullOrEmpty(strPath)) { 21 | throw new ArgumentException("The strPath can not be empty.", "strPath"); 22 | } 23 | if (string.IsNullOrEmpty(strName)) { 24 | throw new ArgumentException("The strName can not be empty.", "strName"); 25 | } 26 | this.Name = strName; 27 | strPath = strPath.Trim(m_char_trim); 28 | var tokens = STJsonPathTokenizer.GetTokens(strPath); 29 | m_lst_items = STJsonPathParser.GetPathItems(tokens); 30 | } 31 | 32 | public STJson GetParsedTokens() { 33 | string strText = string.Empty; 34 | foreach (var v in m_lst_items) { 35 | strText += v.Text; 36 | } 37 | var json = STJson.FromObject(new { type = "entry", parsed = strText, items = ME.GetParsedTokens(m_lst_items) }); 38 | return json; 39 | } 40 | 41 | public STJson Select(STJson json) { 42 | return this.Select(json, STJsonPathSelectMode.ItemOnly, null); 43 | } 44 | 45 | public STJson Select(STJson json, STJsonPathSelectMode model) { 46 | return this.Select(json, model, null); 47 | } 48 | 49 | public STJson Select(STJson json, STJsonPathCallBack callBack) { 50 | return this.Select(json, STJsonPathSelectMode.ItemOnly, callBack); 51 | } 52 | 53 | public STJson Select(STJson json, STJsonPathSelectMode model, STJsonPathCallBack callBack) { 54 | SelectSetting setting = new SelectSetting() { 55 | Root = json, 56 | Mode = model, 57 | Path = new Stack(), 58 | Callback = callBack 59 | }; 60 | return this.Select(json, setting); 61 | } 62 | 63 | private STJson Select(STJson json, SelectSetting setting) { 64 | STJson jsonResult = STJson.CreateArray(); 65 | ME.GetSTJsons(m_lst_items, 0, json, setting, jsonResult); 66 | if (setting.Mode != STJsonPathSelectMode.KeepStructure) { 67 | return jsonResult; 68 | } 69 | return STJsonPath.RestorePathJson(jsonResult); 70 | } 71 | 72 | public STJson SelectFirst(STJson json) { 73 | return this.SelectFirst(json, STJsonPathSelectMode.ItemOnly); 74 | } 75 | 76 | public STJson SelectFirst(STJson json, STJsonPathSelectMode model) { 77 | STJson json_result = this.Select(json, model, null); 78 | if (json_result.Count == 0) { 79 | return null; 80 | } 81 | return json_result[0]; 82 | } 83 | 84 | public STJson SelectLast(STJson json) { 85 | return this.SelectLast(json, STJsonPathSelectMode.ItemOnly); 86 | } 87 | 88 | public STJson SelectLast(STJson json, STJsonPathSelectMode model) { 89 | STJson json_result = this.Select(json, model, null); 90 | if (json_result.Count == 0) { 91 | return null; 92 | } 93 | return json_result[json_result.Count - 1]; 94 | } 95 | 96 | 97 | public STJson CreatePathJson(string value) { 98 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 99 | } 100 | 101 | public STJson CreatePathJson(int value) { 102 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 103 | } 104 | 105 | public STJson CreatePathJson(long value) { 106 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 107 | } 108 | 109 | public STJson CreatePathJson(float value) { 110 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 111 | } 112 | 113 | public STJson CreatePathJson(double value) { 114 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 115 | } 116 | 117 | public STJson CreatePathJson(bool value) { 118 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 119 | } 120 | 121 | public STJson CreatePathJson(DateTime value) { 122 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 123 | } 124 | 125 | public STJson CreatePathJson(STJson value) { 126 | return STJsonPath.CreatePathJson(value, m_lst_items); 127 | } 128 | 129 | public STJson CreatePathJson(object value) { 130 | return STJsonPath.CreatePathJson(STJson.FromObject(value), m_lst_items); 131 | } 132 | 133 | public STJson CreatePathJson(STJsonPathCallBack callBack) { 134 | return STJsonPath.CreatePathJson(callBack, m_lst_items); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJsonPath/STJsonPathItem.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace STLib.Json 4 | { 5 | internal class STJsonPathItem 6 | { 7 | public static readonly STJsonPathItem Root = new STJsonPathItem(ItemType.Root); 8 | public static readonly STJsonPathItem Current = new STJsonPathItem(ItemType.Current); 9 | public static readonly STJsonPathItem Any = new STJsonPathItem(ItemType.Any); 10 | public static readonly STJsonPathItem Depth = new STJsonPathItem(ItemType.Depth); 11 | 12 | public string Text { 13 | get { 14 | switch (this.Type) { 15 | case ItemType.Root: return "[$]"; 16 | case ItemType.Current: return "[@]"; 17 | case ItemType.Any: return "[*]"; 18 | case ItemType.Depth: return "[..]"; 19 | case ItemType.Slice: return "[" + this.Start + ":" + this.End + ":" + this.Step + "]"; 20 | case ItemType.List: 21 | return "[" 22 | + (string.Join(",", (from a in this.Indices select a.ToString()).ToArray()) 23 | + "," 24 | + string.Join(",", (from a in this.Keys select ("'" + STJson.Escape(a) + "'")).ToArray())).Trim(',') 25 | + "]"; 26 | case ItemType.Express: return this.Express.Text; 27 | default: return null; 28 | } 29 | } 30 | } 31 | public enum ItemType 32 | { 33 | Root, Current, List, Slice, Any, Depth, Express 34 | } 35 | 36 | public ItemType Type { get; private set; } 37 | 38 | public int Start { get; private set; } 39 | 40 | public int End { get; private set; } 41 | 42 | public int Step { get; private set; } 43 | 44 | public int[] Indices { get; set; } 45 | 46 | public string[] Keys { get; set; } 47 | 48 | public object[] List { get; set; } 49 | 50 | public STJsonPathExpression Express { get; set; } 51 | 52 | private STJsonPathItem(ItemType type) { 53 | this.Type = type; 54 | } 55 | 56 | public STJsonPathItem(int indices) { 57 | this.Type = ItemType.List; 58 | this.Indices = new int[] { indices }; 59 | this.Keys = new string[0]; 60 | } 61 | 62 | public STJsonPathItem(string keys) { 63 | this.Type = ItemType.List; 64 | this.Keys = new string[] { keys }; 65 | this.Indices = new int[0]; 66 | } 67 | 68 | public STJsonPathItem(int[] indices, string[] keys) { 69 | this.Type = ItemType.List; 70 | this.Indices = indices; 71 | this.Keys = keys; 72 | } 73 | 74 | public STJsonPathItem(int nStart, int nEnd, int nStep) { 75 | this.Type = ItemType.Slice; 76 | this.Start = nStart; 77 | this.End = nEnd; 78 | this.Step = nStep; 79 | } 80 | 81 | public STJsonPathItem(STJsonPathExpression express) { 82 | this.Type = ItemType.Express; 83 | this.Express = express; 84 | } 85 | 86 | public override string ToString() { 87 | return "[" + this.Type + "] - " + this.Text; 88 | } 89 | } 90 | } 91 | 92 | -------------------------------------------------------------------------------- /Src/STLib.Json/STJsonPath/STJsonPathParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using ME = STLib.Json.STJsonPathParser; 5 | 6 | namespace STLib.Json 7 | { 8 | internal class STJsonPathParser 9 | { 10 | public static List GetPathItems(List tokens) { 11 | var lst = new List(); 12 | for (int i = 0; i < tokens.Count; i++) { 13 | var token = tokens[i]; 14 | switch (token.Type) { 15 | case STJsonPathTokenType.String: 16 | case STJsonPathTokenType.Property: 17 | case STJsonPathTokenType.Keyword: 18 | lst.Add(new STJsonPathItem(token.Value)); 19 | continue; 20 | case STJsonPathTokenType.Long: 21 | lst.Add(new STJsonPathItem(Convert.ToInt32(token.Value))); // this is for index 22 | continue; 23 | } 24 | switch (token.Value) { 25 | case "$": 26 | lst.Add(STJsonPathItem.Root); 27 | continue; 28 | case "@": 29 | lst.Add(STJsonPathItem.Current); 30 | continue; 31 | case "*": 32 | lst.Add(STJsonPathItem.Any); 33 | continue; 34 | case "[": 35 | var lst_range = STJsonPathTokenizer.GetRange(tokens, i, "[", "]"); 36 | if (lst_range.Count < 1) { 37 | throw new STJsonPathParseException(i, "The bracket is empty. index: " + i); 38 | } 39 | lst.Add(ME.GetJsonPathItemFromBracket(lst_range)); 40 | i += lst_range.Count + 1; 41 | continue; 42 | case ".": 43 | if (i + 1 >= tokens.Count) { 44 | throw new STJsonPathParseException(i, "Invalid char [.]. index: " + i); 45 | } 46 | if (tokens[i + 1].Value == ".") { 47 | lst.Add(STJsonPathItem.Depth); 48 | i++; 49 | } 50 | continue; 51 | } 52 | throw new STJsonPathParseException(token.Index, "Unknows token [" + token.Value + "]"); 53 | } 54 | return lst; 55 | } 56 | 57 | private static STJsonPathItem GetJsonPathItemFromBracket(List tokens) { 58 | var token = tokens[0]; 59 | int nLen = tokens.Count; 60 | 61 | if (nLen > 2 && token.IsSymbol("(")) { 62 | var lst_range = STJsonPathTokenizer.GetRange(tokens, 0, "(", ")"); 63 | if (lst_range.Count < 1) { 64 | throw new STJsonPathParseException(token.Index + 1, "The bracket is empty. index: " + (token.Index)); 65 | } 66 | return new STJsonPathItem(STJsonPathExpressParser.GetSTJsonPathExpress(lst_range, false)); 67 | } 68 | 69 | if (nLen > 3 && token.IsSymbol("?") && tokens[1].IsSymbol("(")) { 70 | var lst_range = STJsonPathTokenizer.GetRange(tokens, 1, "(", ")"); 71 | if (lst_range.Count < 1) { 72 | throw new STJsonPathParseException(token.Index + 1, "The bracket is empty. index: " + (token.Index + 1)); 73 | } 74 | return new STJsonPathItem(STJsonPathExpressParser.GetSTJsonPathExpress(lst_range, true)); 75 | } 76 | 77 | if (token.IsSymbol(":")) { 78 | return ME.GetSliceItem(tokens); 79 | } 80 | if (nLen > 1 && token.Type == STJsonPathTokenType.Long && tokens[1].IsSymbol(":")) { 81 | return ME.GetSliceItem(tokens); 82 | } 83 | 84 | List lst_idx = new List(); 85 | List lst_str = new List(); 86 | foreach (var v in tokens) { 87 | if (v.IsSymbol(",")) continue; 88 | switch (v.Type) { 89 | case STJsonPathTokenType.String: 90 | case STJsonPathTokenType.Property: 91 | case STJsonPathTokenType.Keyword: 92 | if (lst_idx.Count != 0) { 93 | throw new STJsonPathParseException(token.Index, "All the value of array must be string or int. index: " + (token.Index)); 94 | } 95 | lst_str.Add(v.Value); 96 | continue; 97 | case STJsonPathTokenType.Long: 98 | if (lst_str.Count != 0) { 99 | throw new STJsonPathParseException(token.Index, "All the value of array must be string or number. index: " + (token.Index)); 100 | } 101 | lst_idx.Add(Convert.ToInt32(v.Value)); 102 | continue; 103 | default: 104 | throw new STJsonPathParseException(token.Index, "Unknows token [" + token.Value + "]"); 105 | } 106 | } 107 | return new STJsonPathItem(lst_idx.ToArray(), lst_str.ToArray()); 108 | } 109 | 110 | private static STJsonPathItem GetSliceItem(List tokens) { 111 | int nIndex = 0; 112 | int[] arr_index = new int[3] { 0, -1, 1 }; 113 | for (int i = 0; i < arr_index.Length && nIndex < tokens.Count; i++) { 114 | if (tokens[nIndex].Type == STJsonPathTokenType.Long) { 115 | arr_index[i] = Convert.ToInt32(tokens[nIndex++].Value); // for index 116 | if (nIndex >= tokens.Count) { 117 | break; 118 | } 119 | } else if (tokens[nIndex].Value != ":") { 120 | throw new STJsonPathParseException(tokens[nIndex].Index, "Unknows token [" + tokens[nIndex].Value + "]"); 121 | } 122 | nIndex++; 123 | } 124 | if (nIndex != tokens.Count) { 125 | throw new STJsonPathParseException(tokens[nIndex].Index, "Unknows token [" + tokens[nIndex].Value + "]"); 126 | } 127 | if (arr_index[2] <= 0) { 128 | throw new STJsonPathParseException(tokens[nIndex - 1].Index, "The slice step must be more than zero. token [" + tokens[nIndex - 1].Value + "]"); 129 | } 130 | return new STJsonPathItem(arr_index[0], arr_index[1], arr_index[2]); 131 | } 132 | } 133 | } 134 | 135 | -------------------------------------------------------------------------------- /Src/STLib.Json/STLib.Json.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | unknows 5 | 2017 6 | 2019 7 | 2022 8 | 9 | 10 | 11 | net40 12 | 13 | 14 | net35 15 | 16 | 17 | netstandard2.0;net46; 18 | 19 | 20 | net6.0;net8.0;netstandard2.0;net35;net46;net47;net48 21 | 22 | 23 | 24 | 25 | STJson 26 | True 27 | DebugST 28 | None 29 | https://github.com/DebugST/STJson 30 | https://debugst.github.io/STJson 31 | STJson.icon.png 32 | json;jsonpath;stlib;debugst; 33 | README.md 34 | STJson is a Json parsing library based on the MIT open source protocol . The library is purely native implementation does not rely on any library , so it is very light and convenient , and powerful . 35 | True 36 | git 37 | [3.0.1][2024-10-21] 38 | -------------------------------------------------- 39 | Fixed STJson.Insert() error. 40 | Fixed empty object to string error. 41 | Optimize some code. 42 | 43 | [3.0.0][2024-08-02] 44 | -------------------------------------------------- 45 | Add Json5 support. 46 | Add STJsonReader/Writer. 47 | Add STJsonCreator. 48 | Add STJson.ToString(TextWriter). 49 | Optimize STJson.Sort(). 50 | Optimize some STJsonPath built-in functions. 51 | 52 | [2.0.0][2024-02-14] 53 | -------------------------------------------------- 54 | Fixed JsonPath error for [?()] 55 | Fixed some string serialization cannot be parsed in other languages. 56 | 57 | [1.0.4][2023-11-27] 58 | -------------------------------------------------- 59 | Fixed parsing string error for ["....\\"] 60 | Fixed parsing number error for [12E-12] 61 | Changed STJsonPathCallBack 62 | 63 | [1.0.3][2023-11-10] 64 | -------------------------------------------------- 65 | Fixed DateTime type sorting error. 66 | Fixed parsing scientific notation string error. 67 | Fixed STJson.GetValue<object>() error. 68 | 69 | [1.0.1][2023-07-24] 70 | -------------------------------------------------- 71 | Fixed STJson.GetValue<T>() error. 72 | 73 | [1.0.0][2023-06-04] 74 | -------------------------------------------------- 75 | Publish project. 76 | Support Json serialization and deserialization. 77 | Support JsonPath syntax. 78 | Simple data aggregation processing. 79 | Copyright 2022 DebugST 80 | LICENSE 81 | 3.0.2 82 | 83 | 84 | 85 | 86 | True 87 | \ 88 | 89 | 90 | True 91 | \ 92 | 93 | 94 | True 95 | \ 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Src/sources/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 DebugST 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 | -------------------------------------------------------------------------------- /Src/sources/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | `STJson` is a `Json` parsing library based on the `MIT` open source protocol . The library is purely native implementation does not rely on any library , so it is very light and convenient , and powerful . 4 | 5 | Full tutorial: 6 | 7 | CN: [https://DebugST.github.io/STJson/tutorial_cn.html](https://DebugST.github.io/STJson/tutorial_cn.html) 8 | 9 | EN: [https://DebugST.github.io/STJson/tutorial_en.html](https://DebugST.github.io/STJson/tutorial_en.html) 10 | 11 | Unlike other `Json` libraries, `STJson` not has objects similar to `JObject` and `JArray`. Just `STJson`. which can be either `Object` or `Array`. `STJson` has two indexers: `STJson[int]` and `STJson[string]`. The type of the current `Json` object can be determined by `STJson.ValueType`. 12 | 13 | ```cs 14 | var json_1 = new STJson(); 15 | Console.WriteLine("[json_1] - " + json_1.IsNullValue + " - " + json_1.ValueType); 16 | 17 | var json_2 = STJson.New(); 18 | json_2.SetItem("key", "value"); 19 | Console.WriteLine("[json_2] - " + json_2.IsNullValue + " - " + json_2.ValueType); 20 | 21 | var json_3 = new STJson(); 22 | json_3.Append(1, 2, 3); 23 | Console.WriteLine("[json_3] - " + json_3.IsNullValue + " - " + json_3.ValueType); 24 | 25 | var json_4 = new STJson(); 26 | json_4.SetValue(DateTime.Now); 27 | Console.WriteLine("[json_4] - " + json_4.IsNullValue + " - " + json_4.ValueType); 28 | 29 | var json_5 = STJson.CreateArray(); // made by static function 30 | Console.WriteLine("[json_5] - " + json_5.IsNullValue + " - " + json_5.ValueType); 31 | 32 | var json_6 = STJson.CreateObject(); // made by static function 33 | Console.WriteLine("[json_6] - " + json_6.IsNullValue + " - " + json_6.ValueType); 34 | 35 | var json_7 = STJson.FromObject(12); // made by static function 36 | Console.WriteLine("[json_3] - " + json_7.IsNullValue + " - " + json_7.ValueType); 37 | /******************************************************************************* 38 | * [output] * 39 | *******************************************************************************/ 40 | [json_1] - True - Undefined 41 | [json_2] - False - Object 42 | [json_3] - False - Array 43 | [json_4] - False - Datetime 44 | [json_5] - False - Array 45 | [json_6] - False - Object 46 | [json_7] - False - Long 47 | ``` 48 | 49 | # STJson 50 | 51 | `STJson` is an intermediate data type that is a bridge between `string` and `object` and is very convenient to use, e.g: 52 | 53 | ```cs 54 | var st_json = new STJson() 55 | .SetItem("number", 0) // The function returns itself so it can be operated continuously. 56 | .SetItem("boolean", true) 57 | .SetItem("string", "this is string") 58 | .SetItem("datetime", DateTime.Now) 59 | .SetItem("array_1", STJson.CreateArray(123, true, "string")) 60 | .SetItem("array_2", STJson.FromObject(new object[] { 123, true, "string" })) 61 | .SetItem("object", new { key = "this is a object" }) 62 | .SetItem("null", obj: null); 63 | st_json.SetKey("key").SetValue("this is a test"); 64 | Console.WriteLine(st_json.ToString(4)); // 4 -> indentation space count 65 | /******************************************************************************* 66 | * [output] * 67 | *******************************************************************************/ 68 | { 69 | "number": 0, 70 | "boolean": true, 71 | "string": "this is string", 72 | "datetime": "2023-04-22T21:12:30.6109410+08:00", 73 | "array_1": [ 74 | 123, true, "string" 75 | ], 76 | "array_2": [ 77 | 123, true, "string" 78 | ], 79 | "object": { 80 | "key": "this is a object" 81 | }, 82 | "null": null, 83 | "key": "this is a test" 84 | } 85 | ``` 86 | 87 | # Serialize 88 | 89 | By the above example maybe you already know how to convert an object to `string`, by `STJson.FromObject(object).ToString(+n)`, but is it possible that it actually doesn't need to be so troublesome? For example: `STJson.Serialize(+n)` will do? 90 | 91 | In fact `STJson.Serialize(+n)` would be more efficient because it converts the object directly to a string, rather than converting it to `STJson` and then to a string. 92 | 93 | ```cs 94 | Console.WriteLine(STJson.Serialize(new { key = "this is test" })); 95 | /******************************************************************************* 96 | * [output] * 97 | *******************************************************************************/ 98 | {"key":"this is test"} 99 | ``` 100 | 101 | Of course you can have a more friendly output format: 102 | 103 | ```cs 104 | Console.WriteLine(STJson.Serialize(new { key = "this is test" }, 4)); 105 | /******************************************************************************* 106 | * [output] * 107 | *******************************************************************************/ 108 | { 109 | "key": "this is test" 110 | } 111 | ``` 112 | 113 | In fact formatting the output is done by calling the static function `STJson.Format(+n)`. If you don't like the author's built-in formatting style, you can write a formatting function of your own. Or go modify the source file `STJson.Statics.cs:Format(string,int)`. 114 | 115 | # Deserialize 116 | 117 | The code doesn't actually convert `string` to `object` directly. It has to parse the string to make sure it's a properly formatted `Json` before it does that. But by the time this is done, you'll already have an `STJson` object. Finally, `STJson` is converted to `object` again. 118 | 119 | So you will see the following files in the source code `STLib.Json.Converter`: 120 | 121 | `ObjectToSTJson.cs` `ObjectToString.cs` `STJsonToObject.cs` `StringToSTJson.cs` 122 | 123 | There is no `StringToObject.cs` file inside, and the source code of `STJson.Deserialize(+n)` is as follows: 124 | 125 | ```cs 126 | public static T Deserialize(string strJson, +n) { 127 | var json = StringToSTJson.Get(strJson, +n); 128 | return STJsonToObject.Get(json, +n); 129 | } 130 | ``` 131 | 132 | How to convert strings to objects, I believe the author does not need to explain the reader should know how to handle, but here it is worth explaining that `STJson` can be attached to objects to achieve local updates. 133 | 134 | ```cs 135 | public class TestClass { 136 | public int X; 137 | public int Y; 138 | } 139 | 140 | TestClass tc = new TestClass() { 141 | X = 10, 142 | Y = 20 143 | }; 144 | STJson json_test = new STJson().SetItem("Y", 100); 145 | STJson.Deserialize(json_test, tc); 146 | Console.WriteLine(STJson.Serialize(tc)); 147 | /******************************************************************************* 148 | * [output] * 149 | *******************************************************************************/ 150 | {"X":10,"Y":100} 151 | ``` 152 | 153 | # STJsonPath 154 | 155 | Test data: `test.json`: 156 | 157 | ```cs 158 | [{ 159 | "name": "Tom", "age": 16, "gender": 0, 160 | "hobby": [ 161 | "cooking", "sing" 162 | ] 163 | },{ 164 | "name": "Tony", "age": 16, "gender": 0, 165 | "hobby": [ 166 | "game", "dance" 167 | ] 168 | },{ 169 | "name": "Andy", "age": 20, "gender": 1, 170 | "hobby": [ 171 | "draw", "sing" 172 | ] 173 | },{ 174 | "name": "Kun", "age": 26, "gender": 1, 175 | "hobby": [ 176 | "sing", "dance", "rap", "basketball" 177 | ] 178 | }] 179 | // Load it: 180 | var json_src = STJson.Deserialize(System.IO.File.ReadAllText("./test.json")); 181 | ``` 182 | An `STJsonPath` can be constructed by: 183 | ```cs 184 | // var jp = new STJsonPath("$[0]name"); 185 | // var jp = new STJsonPath("$[0].name"); 186 | var jp = new STJsonPath("[0]'name'"); // All of the above can be used, but $ is not required. 187 | Console.WriteLine(jp.Select(json_src)); 188 | /******************************************************************************* 189 | * [output] * 190 | *******************************************************************************/ 191 | ["Tom"] 192 | ``` 193 | Of course `STJsonPath` is already integrated in the extension functions in `STJson` and can be used directly by the following: 194 | ```cs 195 | // var jp = new STJsonPath("[0].name"); 196 | // Console.WriteLine(json_src.Select(jp)); 197 | Console.WriteLine(json_src.Select("[0].name")); // 内部动态构建 STJsonPath 198 | /******************************************************************************* 199 | * [output] * 200 | *******************************************************************************/ 201 | ["Tom"] 202 | ``` 203 | 204 | Normal mode (default mode): 205 | ```cs 206 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.ItemOnly).ToString(4)); 207 | /******************************************************************************* 208 | * [output] * 209 | *******************************************************************************/ 210 | [ 211 | "Tom", "Tony", "Andy", "Kun" 212 | ] 213 | ``` 214 | Path mode: 215 | ```cs 216 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.ItemWithPath).ToString(4)); 217 | /******************************************************************************* 218 | * [output] * 219 | *******************************************************************************/ 220 | [ 221 | { 222 | "path": [ 223 | 0, "name" 224 | ], 225 | "item": "Tom" 226 | }, { 227 | "path": [ 228 | 1, "name" 229 | ], 230 | "item": "Tony" 231 | }, { 232 | "path": [ 233 | 2, "name" 234 | ], 235 | "item": "Andy" 236 | }, { 237 | "path": [ 238 | 3, "name" 239 | ], 240 | "item": "Kun" 241 | } 242 | ] 243 | ``` 244 | Keep Structure: 245 | ```cs 246 | Console.WriteLine(json_src.Select("..name", STJsonPathSelectMode.KeepStructure).ToString(4)); 247 | /******************************************************************************* 248 | * [output] * 249 | *******************************************************************************/ 250 | [ 251 | { 252 | "name": "Tom" 253 | }, { 254 | "name": "Tony" 255 | }, { 256 | "name": "Andy" 257 | }, { 258 | "name": "Kun" 259 | } 260 | ] 261 | ``` 262 | 263 | Of course the above is just an introduction to the basic usage, there are many rich features are not introduced to. If you have enough time you can read the tutorial directly at 264 | 265 | CN: [https://DebugST.github.io/STJson/tutorial_cn.html](https://DebugST.github.io/STJson/tutorial_cn.html) 266 | 267 | EN: [https://DebugST.github.io/STJson/tutorial_en.html](https://DebugST.github.io/STJson/tutorial_en.html) 268 | 269 | # Contact Author 270 | 271 | * TG: DebugST 272 | * QQ: 2212233137 273 | * Mail: 2212233137@qq.com -------------------------------------------------------------------------------- /Src/sources/STJson.icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DebugST/STJson/476fd7ab6908ccde74c1c88e8b830225d7cba76e/Src/sources/STJson.icon.png -------------------------------------------------------------------------------- /docs/css/index.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | :root{ 3 | --clr-body:#151515; 4 | --clr-bg:#343434; 5 | --clr-selection: rgba(0,255,255,.2); 6 | --clr-active: #0076A0; 7 | --clr-time: slateblue; 8 | --clr-hr: #2b2b2b; 9 | --clr-lst-b:tan; 10 | --clr-lst-f:white; 11 | --clr-lst-h:deepskyblue; 12 | } 13 | *{ 14 | color:black; 15 | font-family:"consolas","Menlo","DejaVu Sans Mono","monaco","MonoSpace","courier new","微软雅黑","Microsoft Yahei"; 16 | font-weight:300; 17 | background-repeat:no-repeat; 18 | -webkit-font-smoothing:antialiased; 19 | -webkit-text-size-adjust: none; 20 | } 21 | ::selection { background-color: var(--clr-selection); } 22 | ::-moz-selection { background-color: var(--clr-selection); } 23 | ::-webkit-selection { background-color: var(--clr-selection); } 24 | ::-webkit-scrollbar { display: none; } 25 | html,body{ 26 | margin:0px; 27 | width:100%; 28 | height:100%; 29 | } 30 | img{ 31 | display:block; 32 | max-width:100%; 33 | box-sizing: border-box; 34 | } 35 | a{ 36 | cursor:pointer; 37 | outline:none; 38 | text-decoration:none; 39 | } 40 | a:hover{ 41 | outline-style:none; 42 | } 43 | .div_top{ 44 | min-height:350px; 45 | position:relative; 46 | background-image:url('../images/banner.jpg'); 47 | background-size: cover; 48 | } 49 | .div_top_content{ 50 | width:100%; 51 | max-width: 1024px; 52 | text-align: center; 53 | transform: translate(-50%, -50%); 54 | left: 50%; 55 | top: 50%; 56 | position: absolute; 57 | } 58 | .div_mid{ 59 | margin:auto; 60 | max-width:1024px; 61 | } 62 | .div_bottom{ 63 | height:100px; 64 | color:white; 65 | background-color:black; 66 | text-align:center; 67 | position:relative; 68 | } 69 | .a_button{ 70 | margin:5px 10px; 71 | padding:10px 20px; 72 | color:white; 73 | border-radius: 5px; 74 | display: inline-block; 75 | min-width: 120px; 76 | } 77 | .a_lua{ 78 | position:fixed; 79 | width:30px; 80 | height:30px; 81 | z-index:1; 82 | background-color:ghostwhite; 83 | text-align:center; 84 | line-height:30px; 85 | border-radius:15px; 86 | } 87 | @keyframes good{ 88 | 0% { 89 | transform: rotate(-30deg); 90 | } 91 | 50%{ 92 | transform:rotate(30deg); 93 | } 94 | 100% { 95 | transform: rotate(-30deg); 96 | } 97 | } 98 | .img_good{ 99 | animation: good 2s infinite; 100 | } 101 | .span_note{ 102 | display: inline-block; 103 | background-color: goldenrod; 104 | font-size: 12px; 105 | color: white; 106 | position: absolute; 107 | z-index: 2; 108 | left: 50%; 109 | transform: translate(-50%, 0); 110 | padding: 2px 10px; 111 | border-radius: 0px 0px 5px 5px; 112 | white-space: nowrap; 113 | } -------------------------------------------------------------------------------- /docs/css/stdoc.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | :root{ 3 | --clr-body:#151515; 4 | --clr-bg:#343434; 5 | --clr-selection: rgba(0,255,255,.2); 6 | --clr-active: #0076A0; 7 | --clr-time: slateblue; 8 | --clr-hr: #2b2b2b; 9 | --clr-lst-b:tan; 10 | --clr-lst-f:white; 11 | --clr-lst-h:deepskyblue; 12 | } 13 | *{ 14 | color:lightgray; 15 | font-family:"consolas","Menlo","DejaVu Sans Mono","monaco","MonoSpace","courier new","微软雅黑","Microsoft Yahei"; 16 | font-weight:300; 17 | background-repeat:no-repeat; 18 | -webkit-font-smoothing:antialiased; 19 | -webkit-text-size-adjust: none; 20 | } 21 | ::selection { background-color: var(--clr-selection); } 22 | ::-moz-selection { background-color: var(--clr-selection); } 23 | ::-webkit-selection { background-color: var(--clr-selection); } 24 | ::-webkit-scrollbar { display: none; } 25 | html,body{ 26 | width:100%; 27 | height:100%; 28 | } 29 | img{ 30 | display:block; 31 | max-width:100%; 32 | margin-bottom:10px; 33 | border:5px solid rgba(125,125,125,.5); 34 | border-radius:5px; 35 | box-sizing: border-box; 36 | background-color:white; 37 | } 38 | hr{ 39 | height: 1px; 40 | border: none; 41 | border-top: solid 1px var(--clr-hr); 42 | } 43 | body{ 44 | margin:0px; 45 | position:relative; 46 | font-size:0.85rem; 47 | line-height:1.05rem; 48 | background-color:var(--clr-bg); 49 | } 50 | a{ 51 | color:#58b4e8; 52 | cursor:pointer; 53 | outline:none; 54 | text-decoration:none; 55 | } 56 | a:hover{ 57 | color:#58b4e8; 58 | outline-style:none; 59 | } 60 | table{ 61 | margin:10px 0px; 62 | color: rgba(255,255,255,.7); 63 | font-size: 12px; 64 | border-spacing: 0px; 65 | border-top: solid 1px #1f1f1f; 66 | border-left: solid 1px #1f1f1f; 67 | background-color: #2b2b2b; 68 | } 69 | th{ 70 | padding: 5px 20px; 71 | border-right: solid 1px #1f1f1f; 72 | border-bottom: solid 1px #1f1f1f; 73 | background-color:#505050; 74 | } 75 | .tr_hight{background-color:rgba(255,255,255,.04);} 76 | td{ 77 | padding: 5px 20px; 78 | border-right: solid 1px #1f1f1f; 79 | border-bottom: solid 1px #1f1f1f; 80 | } 81 | #div_body{ 82 | height:100%; 83 | background-color:var(--clr-bg); 84 | margin:auto; 85 | max-width:1024px; 86 | position:relative; 87 | } 88 | #div_left{ 89 | overflow:auto; 90 | height:100%; 91 | width:250px; 92 | position:absolute; 93 | padding-right:10px; 94 | z-index:1; 95 | background-color:var(--clr-bg); 96 | } 97 | #div_left_list{ 98 | height:100%; 99 | overflow:auto; 100 | background-color:#1A1A1A; 101 | border-right:solid 1px black; 102 | } 103 | #a_btn_left{ 104 | display:block; 105 | } 106 | .ul_group_root a{ 107 | color:gray; 108 | font-weight:300px; 109 | line-height:30px; 110 | display:block; 111 | padding:5px 15px; 112 | transition:background-color .5s; 113 | } 114 | .ul_group_root a:hover{ 115 | color:white; 116 | background-color:deepskyblue; 117 | transition:background-color 0s; 118 | } 119 | .ul_group_root,.ul_group_root ul{ 120 | margin:0px; 121 | padding:0px; 122 | list-style:none; 123 | font-size:12px; 124 | background-color:#1A1A1A; 125 | } 126 | .a_node_root{ 127 | color:gray; 128 | font-size:14px; 129 | padding:5px; 130 | display:block; 131 | background-color:#343434; 132 | } 133 | .anchor_btn{ 134 | transition:background-color 1s; 135 | } 136 | .anchor_btn.active{ 137 | color:white; 138 | background-color:var(--clr-active); 139 | transition:background-color 0s; 140 | } 141 | .li_node_sub{ 142 | text-align:right; 143 | } 144 | #div_left:hover{ 145 | left:0px; 146 | } 147 | #div_right{ 148 | height:100%; 149 | margin:0px 10px; 150 | overflow:auto; 151 | position:relative; 152 | } 153 | #div_right p{ 154 | color: inherit; 155 | word-break: break-word; 156 | line-height:1.5em; 157 | } 158 | #div_right li{ 159 | line-height:1.5em; 160 | } 161 | #div_logo{ 162 | position:absolute; 163 | left:0px; 164 | top:0px; 165 | right:0px; 166 | bottom:0px; 167 | pointer-events:none; 168 | z-index:100; 169 | background-size: contain; 170 | background-position: center; 171 | background-image:url('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTI4IDEyOCIgd2lkdGg9IjEyOCIgaGVpZ2h0PSIxMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4xIj4KPGcgZmlsbD0icmdiYSgxMjUsMTI1LDEyNSwuMikiIHN0cm9rZT0icmdiYSgxMjUsMTI1LDEyNSwuMSkiIHN0cm9rZS13aWR0aD0iMC4wMSI+CjxwYXRoIGQ9Ik0gMjAgMjAgTCAxMDggMjAgODggNDAgNzQgNDAgNzQgMTA4IDU0IDEwOCA1NCA0MCA0MCA0MCB6Ii8+CjxwYXRoIGQ9Ik0gMjAgMzAgTCAyMCA3NCA0OCA3NCA0OCA1NCA0MCA1NCA0MCA1MCB6Ii8+CjxwYXRoIGQ9Ik0gODAgNTQgTCAxMDggNTQgMTA4IDEwOCA4MCAxMDggODAgODggODggODggODggNzQgODAgNzQgeiIvPgo8cGF0aCBkPSJNIDIwIDEwOCBMIDQ4IDEwOCA0OCA4OCA0MCA4OCB6Ii8+CjwvZz4KPC9zdmc+'); 172 | } 173 | @media screen and (min-width:820px){ 174 | #div_right{ 175 | margin-left:260px; 176 | } 177 | #div_logo{ 178 | left:260px; 179 | } 180 | } 181 | @media screen and (min-width:1024px){ 182 | #div_body{ 183 | border-left:1px solid var(--clr-bg); 184 | border-right:1px solid var(--clr-bg); 185 | box-shadow:0px 0px 10px 10px rgba(0,0,0,1); 186 | } 187 | } 188 | @media screen and (max-width:820px){ 189 | #div_left{ 190 | left:-250px; 191 | transition:left 1s; 192 | } 193 | #div_left:hover{border-right:solid 1px black;} 194 | #div_left:before{ 195 | content: ' '; 196 | position: fixed; 197 | width: 10px; 198 | left: 4px; 199 | top: 0px; 200 | height: 100%; 201 | animation-name: light; 202 | animation-duration: 2s; 203 | animation-iteration-count: 4; 204 | border-left:dashed 2px gray; 205 | transition:left 1s; 206 | } 207 | @keyframes light{ 208 | from{opacity: 0;} 209 | 50%{opacity: 1;} 210 | to{opacity: 0;} 211 | } 212 | #div_left:hover:before{ 213 | left:254px; 214 | transition:left 1s; 215 | } 216 | .h_title{ font-size:1.4rem; } 217 | } 218 | #div_right iframe{ 219 | position:absolute; 220 | left:0px; 221 | top:0px; 222 | width:100%; 223 | height:100%; 224 | margin:0px; 225 | padding:0px; 226 | border:none; 227 | } 228 | #div_right a{ 229 | color:white; 230 | background-color: rgba(28,144,255,.8); 231 | text-decoration: underline; 232 | } 233 | .h_title{ 234 | margin:0px 0px 10px 0px; 235 | padding-left:10px; 236 | border-left:solid 5px dodgerblue; 237 | border-right:solid 5px dodgerblue; 238 | font-weight:bold; 239 | background-color:rgba(125,125,125,.5); 240 | height:40px; 241 | line-height:40px; 242 | } 243 | .h_option{ 244 | margin:0px; 245 | display: inline-block; 246 | background-color: rgba(125,125,125,.5); 247 | border-left:solid 5px dodgerblue; 248 | border-right:solid 5px dodgerblue; 249 | padding: 2px 10px; 250 | font-size: 12px; 251 | position: relative; 252 | height: 20pxpx; 253 | line-height: 20px; 254 | } 255 | .mark{ 256 | color:white; 257 | border-radius: 3px; 258 | background-color: rgba(125,125,125,.5); 259 | padding: 1px 4px; 260 | margin:0px 4px; 261 | } 262 | .div_hightlight{ 263 | padding: 1px 5px; 264 | border-radius: 5px; 265 | margin:5px 0px; 266 | } 267 | .div_table{ 268 | overflow:auto; 269 | } 270 | .div_code{ 271 | overflow: auto; 272 | counter-reset: code_line_num; 273 | border: solid 1px black; 274 | vertical-align: bottom; 275 | font-size: 0px; 276 | max-width:100%; 277 | margin-bottom:10px; 278 | line-height:0px; 279 | background-color:#1a1a1a; 280 | } 281 | .span_code_title{ 282 | display: inline-block; 283 | background-color: black; 284 | padding: 2px 5px; 285 | margin-top: 10px; 286 | } 287 | .pre_code{ 288 | background-color: #1a1a1a; 289 | font-size: 0.75rem; 290 | overflow: auto; 291 | padding:10px 10px 10px 35px; 292 | display:inline-block; 293 | margin:0px; 294 | /*min-width:680px;*/ 295 | position:relative; 296 | line-height:1rem; 297 | } 298 | .pre_code:before{ 299 | content: ' '; 300 | background-color: gray; 301 | width: 30px; 302 | display: block; 303 | position: absolute; 304 | height: 100%; 305 | left: 0px; 306 | top: 0px; 307 | background-color: rgb(43 43 43); 308 | } 309 | .span_code_line{ 310 | position:relative; 311 | } 312 | .span_code_line:before{ 313 | content: counter(code_line_num); 314 | counter-increment: code_line_num; 315 | position: absolute; 316 | width: 25px; 317 | text-align: right; 318 | left: -35px; 319 | height: 100%; 320 | color:gray; 321 | } 322 | #a_introduction{ 323 | background-color:black; 324 | font-size:0.85em; 325 | line-height:20px; 326 | display:block; 327 | text-align:center; 328 | } 329 | #span_time{ 330 | color:black; 331 | display: block; 332 | text-align: center; 333 | font-size: 0.85em; 334 | background-color: tan; 335 | position:absolute; 336 | left:0px; 337 | bottom:0px; 338 | width:249px; 339 | } 340 | #span_time *{ 341 | color:white; 342 | background-color:dodgerblue; 343 | padding:0px 5px; 344 | display:inline-block; 345 | } 346 | .div_left_space_space{ 347 | height:40px; 348 | border-top:1px solid var(--clr-bg); 349 | } 350 | .span_location{ 351 | font-size:0.85em; 352 | padding:2px 5px; 353 | background-color:black; 354 | display:block; 355 | } 356 | #div_right_list{ 357 | position:absolute; 358 | right:0px; 359 | top:50%; 360 | width:10px; 361 | transform: translate(0px, -50%); 362 | overflow:hidden; 363 | border-radius: 5px; 364 | transition:width 1s; 365 | border-top:5px solid var(--clr-lst-b); 366 | border-bottom:5px solid var(--clr-lst-b); 367 | } 368 | #div_right_list:hover{ 369 | width:auto; 370 | border-radius:9px 0px 0px 9px; 371 | border-left:2px solid var(--clr-lst-b); 372 | background-color:rgba(0,0,0,.5); 373 | } 374 | #div_right_list a{ 375 | color:var(--clr-lst-f); 376 | display:block; 377 | line-height:30px; 378 | margin:2px 10px; 379 | padding:0px 10px; 380 | white-space:nowrap; 381 | position:relative; 382 | text-align:right; 383 | border-radius:5px; 384 | background-color:var(--clr-lst-b); 385 | transition:background-color .5s; 386 | } 387 | 388 | #div_right_list a.active{ 389 | color:white; 390 | background-color:var(--clr-active); 391 | transition:background-color 0s; 392 | } 393 | #div_right_list:hover a{ 394 | margin-left:2px; 395 | } 396 | #div_right_list:hover a:before{ 397 | left:100% 398 | } 399 | #div_right_list:hover a:after{ 400 | left:100%; 401 | transform:translate(4px,0px); 402 | } 403 | #div_right_list a:before{ 404 | content:' '; 405 | border-radius:5px; 406 | width:10px; 407 | height:10px; 408 | display:inline-block; 409 | background-color:var(--clr-lst-b); 410 | position:absolute; 411 | left:-10px; 412 | top:10px; 413 | } 414 | #div_right_list a.active:before{ 415 | background-color:var(--clr-active); 416 | transition:background-color 0s; 417 | } 418 | #div_right_list a:hover:before{ 419 | background-color:var(--clr-lst-h); 420 | transition:background-color 0s; 421 | } 422 | #div_right_list a:after{ 423 | content:' '; 424 | width:2px; 425 | height:34px; 426 | display:inline-block; 427 | background-color:var(--clr-lst-b); 428 | position:absolute; 429 | left:-6px; 430 | top:-2px; 431 | } 432 | #div_right_list a.active:after{ 433 | background-color:var(--clr-active); 434 | transition:background-color 0s; 435 | } 436 | #div_right_list a:hover:after{ 437 | background-color:var(--clr-lst-h); 438 | transition:background-color 0s; 439 | } 440 | #div_right_list a:hover{ 441 | color:white; 442 | background-color:var(--clr-lst-h); 443 | transition:background-color 0s; 444 | } -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DebugST/STJson/476fd7ab6908ccde74c1c88e8b830225d7cba76e/docs/favicon.png -------------------------------------------------------------------------------- /docs/images/STJson.icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DebugST/STJson/476fd7ab6908ccde74c1c88e8b830225d7cba76e/docs/images/STJson.icon.png -------------------------------------------------------------------------------- /docs/images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DebugST/STJson/476fd7ab6908ccde74c1c88e8b830225d7cba76e/docs/images/banner.jpg -------------------------------------------------------------------------------- /docs/images/good.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DebugST/STJson/476fd7ab6908ccde74c1c88e8b830225d7cba76e/docs/images/good.webp -------------------------------------------------------------------------------- /docs/images/st_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | STJson - Home 7 | 8 | 9 | 10 | 22 | 23 | 24 | CN 25 | EN 26 |
27 | 这是一个很严肃的主页 28 |
29 |
30 |

STLib.Json

31 |

一款轻量级Json操作库,功能强大且使用简单。Emm...反正就是很强大。。。很简单。。。

32 | 在线教程GitHub 34 |

版本:3.0

35 |
36 |
37 |
38 |
39 |
40 | 41 |
42 |

如果。。你也选择使用 STLib.Json

43 |

那么这件事情。。。实在是。。。

44 |

TM!!!

48 |
49 |
50 |
51 |
52 |

哇喔。。。快看!石头好TM帅!!!

53 |

2024-08-02

54 |
55 |
56 |
57 | 88 | 89 | -------------------------------------------------------------------------------- /docs/js/stdoc.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | let strModel = $("#div_model").text() 3 | if(strModel == "BOOK"){ 4 | $("#div_left").remove(); 5 | $("#div_logo").css({"left":0}); 6 | $("#div_right").css({"margin-left":location.search.indexOf("?iframe") == -1 ? 10 : 0}); 7 | }else{ 8 | $("#div_right_list").remove(); 9 | if(strModel == "HOME"){ 10 | loadHome(); 11 | } 12 | } 13 | $(".anchor_btn,#div_right_list a").click(function(){ 14 | scrollToAnchor($(this).attr('name')); 15 | }); 16 | $("#div_right").scroll(function(){ 17 | var nMin = 100000,strName = '',strLast = ''; 18 | var nHeight =window.innerHeight;// document.body.clientHeight; 19 | var nHtmlTop = $(this).scrollTop(); 20 | var es = $('.anchor_point'); 21 | for(i = 0; i < es.length; i++){ 22 | var nSub = Math.abs(es[i].offsetTop - nHtmlTop); 23 | if(nSub < nMin){ 24 | nMin = nSub; 25 | if(nHtmlTop + (nHeight / 2) >= es[i].offsetTop){ 26 | strName = $(es[i]).attr('name'); 27 | } 28 | } 29 | strLast = $(es[i]).attr('name'); 30 | } 31 | $(".anchor_btn").removeClass('active'); 32 | $(".anchor_btn[name='" + strName + "']").addClass('active'); 33 | $("#div_right_list a").removeClass('active'); 34 | $("#div_right_list a[name='" + strName + "']").addClass('active'); 35 | }); 36 | 37 | function loadHome(){ 38 | $(".a_node_root").click(function(){ 39 | $(this).next().toggle(500); 40 | }).css({ 41 | "line-height":"29px", 42 | "border-top":"1px solid black" 43 | }); 44 | $("#div_right").css({"margin-right":0,"overflow":"hidden"}); 45 | let search = location.search; 46 | let m = search.match("id=([0-9.]+)"); 47 | if(!m) { 48 | $('iframe').attr("src","./pages/introduction.html?iframe" + location.hash); 49 | return; 50 | }; 51 | $('iframe').attr("src","./pages/" + m[1] + ".html?iframe" + location.hash); 52 | let strs = m[1].split('.'); 53 | let ele =$($(".a_node_root")[parseInt(strs[0]) - 1]); 54 | ele.css({"background-color":"#0076A0","color":"white"}) 55 | .next().show(); 56 | $(ele.next().find("a")[parseInt(strs[1]) - 1]).css({"background-color":"rgba(0, 118, 160,.5)","color":"white"}); 57 | $("#div_left_list").scrollTop(ele.offset().top); 58 | } 59 | 60 | function scrollToAnchor(strName){ 61 | var nTop = $(".anchor_point[name='" + strName + "']").offset().top; 62 | nTop = $('#div_right').scrollTop() + nTop - 5; 63 | $('#div_right').animate({scrollTop:nTop},500,function(){ 64 | parent.window.location.hash = location.hash; 65 | }); 66 | } 67 | 68 | $(document).on("touchstart","#div_left",function(e){}); 69 | 70 | if(strModel != "HOME"){ 71 | var hash = window.location.hash; 72 | if(hash && hash[0] == '#'){ 73 | scrollToAnchor(hash.substring(1)); 74 | } 75 | } 76 | 77 | var strUA = navigator.userAgent.toLowerCase(); 78 | if(strUA.indexOf('windows') != -1 && strUA.indexOf('webkit') == -1){ 79 | //console.log('what the fuck...!!!!!!'); 80 | //我是真没想到都2021年了 windows还在采用可视化滚动条 81 | //而且还只有webkit内核提供了滚动条样式的支持 82 | //我一直以为现在这个年代 滚动条基本都是隐藏式了的吧 83 | //且不说windows 浏览器厂商就这么赤裸裸的使用系统原生滚动条真棒 84 | //我不是吐槽没有解决方案 而是这种设计 85 | //当发现问题后 我仅仅是想通过样式隐藏滚动条 而只有webkit能做到 86 | //::-webkit-scrollbar { display: none; } 87 | $('body').append( 88 | "
" 89 | + "老铁!用WebKit浏览器,不然滚动条太丑了,不想改页面了!
" 90 | + "(Use the WebKit browser as much as possible!!)" 91 | + "
" 92 | ); 93 | $('#WO_TE_ME_DE_YE_HEN_JUE_WANG_A_CAO').css({ 94 | position:"fixed", 95 | top:0, 96 | left:0, 97 | right:0, 98 | color:"white", 99 | "line-height":"20px", 100 | "text-align":"center", 101 | "background-color":"rgba(255,255,0,.6)", 102 | border:"solid 1px yellow", 103 | "text-shadow":"0px 1px 1px black", 104 | "z-index":100 105 | }).click(function(){$(this).remove();}); 106 | } 107 | }); --------------------------------------------------------------------------------