json-duplicate-keys 2025.7.1__py3-none-any.whl → 2025.9.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- json_duplicate_keys/__init__.py +36 -28
- {json_duplicate_keys-2025.7.1.dist-info → json_duplicate_keys-2025.9.9.dist-info}/METADATA +68 -49
- json_duplicate_keys-2025.9.9.dist-info/RECORD +6 -0
- json_duplicate_keys-2025.7.1.dist-info/RECORD +0 -6
- {json_duplicate_keys-2025.7.1.dist-info → json_duplicate_keys-2025.9.9.dist-info}/LICENSE +0 -0
- {json_duplicate_keys-2025.7.1.dist-info → json_duplicate_keys-2025.9.9.dist-info}/WHEEL +0 -0
- {json_duplicate_keys-2025.7.1.dist-info → json_duplicate_keys-2025.9.9.dist-info}/top_level.txt +0 -0
json_duplicate_keys/__init__.py
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
json_duplicate_keys_VERSION = "2025.7.1"
|
3
|
-
|
4
2
|
try:
|
5
|
-
unicode
|
3
|
+
unicode
|
6
4
|
except NameError:
|
7
|
-
unicode = str
|
5
|
+
unicode = str
|
8
6
|
|
9
7
|
from collections import OrderedDict
|
10
8
|
import json, re, copy
|
@@ -24,7 +22,7 @@ def normalize_key(name, dupSign_start="{{{", dupSign_end="}}}", _isDebug_=False)
|
|
24
22
|
|
25
23
|
if type(dupSign_end) not in [str, unicode]: dupSign_end = "}}}"
|
26
24
|
|
27
|
-
return re.sub('
|
25
|
+
return re.sub(re.escape(dupSign_start)+'_\\d+_'+re.escape(dupSign_end)+'$', "", name)
|
28
26
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
29
27
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
30
28
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
@@ -118,13 +116,13 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skip
|
|
118
116
|
Jstr = re.sub(r'"([^"]*)"[\s\t\r\n]*([,\]}])'.encode(), '\x04\x05\\1\x04\x05\\2'.encode(), Jstr)
|
119
117
|
|
120
118
|
|
121
|
-
Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:'.encode(), r'"\1
|
119
|
+
Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:'.encode(), (r'"\1'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":').encode(), Jstr)
|
122
120
|
|
123
|
-
Jstr = re.sub(r'""[\s\t\r\n]*:'.encode(), '"
|
121
|
+
Jstr = re.sub(r'""[\s\t\r\n]*:'.encode(), ('"'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":').encode(), Jstr)
|
124
122
|
|
125
123
|
i = 0
|
126
|
-
while re.search(r'
|
127
|
-
Jstr = re.sub(r'
|
124
|
+
while re.search((dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:').encode(), Jstr):
|
125
|
+
Jstr = re.sub((dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:').encode(), (dupSign_start_escape+"_"+str(i)+"_"+dupSign_end_escape+'":').encode(), Jstr, 1)
|
128
126
|
i += 1
|
129
127
|
|
130
128
|
Jstr = re.sub('\x00\x01'.encode(), r'\\\\'.encode(), Jstr)
|
@@ -135,13 +133,13 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skip
|
|
135
133
|
Jstr = re.sub(r'\\"', '\x02\x03', Jstr)
|
136
134
|
Jstr = re.sub(r'"([^"]*)"[\s\t\r\n]*([,\]}])', '\x04\x05\\1\x04\x05\\2', Jstr)
|
137
135
|
|
138
|
-
Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:', r'"\1
|
136
|
+
Jstr = re.sub(r'"([^"]+)"[\s\t\r\n]*:', r'"\1'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":', Jstr)
|
139
137
|
|
140
|
-
Jstr = re.sub(r'""[\s\t\r\n]*:', '"
|
138
|
+
Jstr = re.sub(r'""[\s\t\r\n]*:', '"'+dupSign_start_escape+'_dupSign_'+dupSign_end_escape+'":', Jstr)
|
141
139
|
|
142
140
|
i = 0
|
143
|
-
while re.search(r'
|
144
|
-
Jstr = re.sub(r'
|
141
|
+
while re.search(dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:', Jstr):
|
142
|
+
Jstr = re.sub(dupSign_start_escape+'_dupSign_'+dupSign_end_escape+r'"[\s\t\r\n]*:', dupSign_start_escape+"_"+str(i)+"_"+dupSign_end_escape+'":', Jstr, 1)
|
145
143
|
i += 1
|
146
144
|
|
147
145
|
Jstr = re.sub('\x00\x01', r'\\\\', Jstr)
|
@@ -178,11 +176,15 @@ def loads(Jstr, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skip
|
|
178
176
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
179
177
|
def load(Jfilepath, dupSign_start="{{{", dupSign_end="}}}", ordered_dict=False, skipDuplicated=False, _isDebug_=False):
|
180
178
|
try:
|
181
|
-
|
182
|
-
|
183
|
-
|
179
|
+
try:
|
180
|
+
with open(Jfilepath) as Jfile: Jstr = Jfile.read()
|
181
|
+
except Exception as e:
|
182
|
+
with open(Jfilepath, "rb") as Jfile: Jstr = Jfile.read()
|
184
183
|
|
185
|
-
|
184
|
+
return loads(Jstr, dupSign_start=dupSign_start, dupSign_end=dupSign_end, ordered_dict=ordered_dict, skipDuplicated=skipDuplicated, _isDebug_=_isDebug_)
|
185
|
+
except Exception as e:
|
186
|
+
if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
|
187
|
+
return False
|
186
188
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
187
189
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
188
190
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
@@ -360,8 +362,8 @@ class JSON_DUPLICATE_KEYS:
|
|
360
362
|
# User input data type validation
|
361
363
|
if type(_isDebug_) != bool: _isDebug_ = False
|
362
364
|
|
363
|
-
if type(name) not in [str, unicode]:
|
364
|
-
if _isDebug_: print("\x1b[31m[-] DataTypeError: the KEY name must be str or
|
365
|
+
if type(name) not in [str, unicode, type(None)]:
|
366
|
+
if _isDebug_: print("\x1b[31m[-] DataTypeError: the KEY name must be str, unicode or None, not {}\x1b[0m".format(type(name)))
|
365
367
|
return False
|
366
368
|
|
367
369
|
if type(position) != int: position = None
|
@@ -379,6 +381,12 @@ class JSON_DUPLICATE_KEYS:
|
|
379
381
|
if type(self.getObject()) not in [list, dict, OrderedDict]:
|
380
382
|
if _isDebug_: print("\x1b[31m[-] DataTypeError: the JSON object must be list, dict or OrderedDict, not {}\x1b[0m".format(type(self.getObject())))
|
381
383
|
return False
|
384
|
+
|
385
|
+
if (name is None or name == "") and type(self.getObject()) == list:
|
386
|
+
if position is None: position = len(self.getObject())
|
387
|
+
|
388
|
+
self.getObject().insert(position, value)
|
389
|
+
return True
|
382
390
|
|
383
391
|
if re.search(re.escape(separator)+"$", name):
|
384
392
|
if _isDebug_: print("\x1b[31m[-] KeyNameInvalidError: \x1b[0m"+name)
|
@@ -492,10 +500,10 @@ class JSON_DUPLICATE_KEYS:
|
|
492
500
|
for k, v in JDKSObject.getObject().items():
|
493
501
|
if type(k) == str and type(name) == str:
|
494
502
|
if re.search(name, k):
|
495
|
-
newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
|
503
|
+
newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
|
496
504
|
else:
|
497
505
|
if name == k:
|
498
|
-
newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
|
506
|
+
newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
|
499
507
|
|
500
508
|
return newJDKSObject
|
501
509
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
@@ -514,10 +522,10 @@ class JSON_DUPLICATE_KEYS:
|
|
514
522
|
for k, v in JDKSObject.getObject().items():
|
515
523
|
if type(v) == str and type(value) == str:
|
516
524
|
if re.search(value, v):
|
517
|
-
newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
|
525
|
+
newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
|
518
526
|
else:
|
519
527
|
if value == v:
|
520
|
-
newJDKSObject.set(k, v, separator="§§"+separator+"§§", parse_index="§§"+parse_index+"§§", ordered_dict=ordered_dict)
|
528
|
+
newJDKSObject.set(k, v, separator=u"§§"+separator+u"§§", parse_index=u"§§"+parse_index+u"§§", ordered_dict=ordered_dict)
|
521
529
|
|
522
530
|
return newJDKSObject
|
523
531
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
@@ -544,7 +552,7 @@ class JSON_DUPLICATE_KEYS:
|
|
544
552
|
|
545
553
|
dupSign_end_escape_regex = re.escape(json.dumps({dupSign_end:""})[2:-6])
|
546
554
|
|
547
|
-
return re.sub('
|
555
|
+
return re.sub(dupSign_start_escape_regex+'_\\d+_'+dupSign_end_escape_regex+'":', '":', json.dumps(self.getObject(), skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, allow_nan=allow_nan, cls=cls, indent=indent, separators=separators, default=default, sort_keys=sort_keys))
|
548
556
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
549
557
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
550
558
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
@@ -557,8 +565,8 @@ class JSON_DUPLICATE_KEYS:
|
|
557
565
|
Jstr = self.dumps(dupSign_start=dupSign_start, dupSign_end=dupSign_end, _isDebug_=_isDebug_, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, allow_nan=allow_nan, cls=cls, indent=indent, separators=separators, default=default, sort_keys=sort_keys)
|
558
566
|
|
559
567
|
try:
|
560
|
-
Jfile = open(Jfilepath, "
|
561
|
-
Jfile.write(Jstr)
|
568
|
+
Jfile = open(Jfilepath, "wb")
|
569
|
+
Jfile.write(Jstr.encode("utf-8"))
|
562
570
|
Jfile.close()
|
563
571
|
except Exception as e:
|
564
572
|
if _isDebug_: print("\x1b[31m[-] ExceptionError: {}\x1b[0m".format(e))
|
@@ -600,7 +608,7 @@ class JSON_DUPLICATE_KEYS:
|
|
600
608
|
else:
|
601
609
|
for k,v in Jobj.items():
|
602
610
|
_Jobj = v
|
603
|
-
_key =
|
611
|
+
_key = key+separator+k if key != None else k
|
604
612
|
|
605
613
|
__convert_Jobj_to_Jflat(_Jobj, _key)
|
606
614
|
elif type(Jobj) == list:
|
@@ -609,7 +617,7 @@ class JSON_DUPLICATE_KEYS:
|
|
609
617
|
else:
|
610
618
|
for i,v in enumerate(Jobj):
|
611
619
|
_Jobj = v
|
612
|
-
_key =
|
620
|
+
_key = key+separator+parse_index+str(i)+parse_index if key != None else parse_index+str(i)+parse_index
|
613
621
|
|
614
622
|
__convert_Jobj_to_Jflat(_Jobj, _key)
|
615
623
|
else:
|
@@ -1,47 +1,48 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: json-duplicate-keys
|
3
|
-
Version: 2025.
|
3
|
+
Version: 2025.9.9
|
4
4
|
Summary: Flatten/ Unflatten and Load(s)/ Dump(s) JSON File/ Object with Duplicate Keys
|
5
|
-
|
6
|
-
Author: TP Cyber Security
|
7
|
-
Author-email: tpcybersec2023@gmail.com
|
5
|
+
Author-email: TP Cyber Security <tpcybersec2023@gmail.com>
|
8
6
|
License: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/TPCyberSec/json-duplicate-keys
|
9
8
|
Keywords: TPCyberSec,json,duplicate keys,json duplicate keys,flatten,unflatten
|
10
9
|
Classifier: Programming Language :: Python :: 3
|
11
|
-
Classifier: Programming Language :: Python :: 2
|
12
10
|
Classifier: Programming Language :: Python :: Implementation :: Jython
|
13
11
|
Description-Content-Type: text/markdown
|
14
12
|
License-File: LICENSE
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
<
|
20
|
-
<a href="https://github.com/
|
21
|
-
<a href="#"><img src="https://img.shields.io/github/downloads/
|
22
|
-
<a href="#"><img src="https://img.shields.io/github/stars/
|
23
|
-
<a href="#"><img src="https://img.shields.io/github/forks/
|
24
|
-
<a href="https://github.com/
|
25
|
-
<a href="https://github.com/
|
14
|
+
<div align="center">
|
15
|
+
<h1>JSON Duplicate Keys - PyPI</h1>
|
16
|
+
<i>Flatten/ Unflatten and Load(s)/ Dump(s) JSON File/ Object with Duplicate Keys</i>
|
17
|
+
<br><br>
|
18
|
+
<a href="https://github.com/TPCyberSec/json-duplicate-keys/releases/"><img src="https://img.shields.io/github/release/TPCyberSec/json-duplicate-keys" height=30></a>
|
19
|
+
<a href="#"><img src="https://img.shields.io/github/downloads/TPCyberSec/json-duplicate-keys/total" height=30></a>
|
20
|
+
<a href="#"><img src="https://img.shields.io/github/stars/TPCyberSec/json-duplicate-keys" height=30></a>
|
21
|
+
<a href="#"><img src="https://img.shields.io/github/forks/TPCyberSec/json-duplicate-keys" height=30></a>
|
22
|
+
<a href="https://github.com/TPCyberSec/json-duplicate-keys/issues?q=is%3Aopen+is%3Aissue"><img src="https://img.shields.io/github/issues/TPCyberSec/json-duplicate-keys" height=30></a>
|
23
|
+
<a href="https://github.com/TPCyberSec/json-duplicate-keys/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed/TPCyberSec/json-duplicate-keys" height=30></a>
|
26
24
|
<br>
|
27
25
|
<a href="#"><img src="https://img.shields.io/pypi/v/json-duplicate-keys" height=30></a>
|
26
|
+
<a href="#"><img src="https://img.shields.io/pypi/pyversions/json-duplicate-keys" height=30></a>
|
28
27
|
<a href="#"><img src="https://img.shields.io/pypi/dm/json-duplicate-keys" height=30></a>
|
29
|
-
</
|
28
|
+
</div>
|
30
29
|
|
31
|
-
|
30
|
+
---
|
31
|
+
# 🛠️ Installation
|
32
32
|
#### From PyPI:
|
33
33
|
```console
|
34
34
|
pip install json-duplicate-keys
|
35
35
|
```
|
36
36
|
#### From Source:
|
37
37
|
```console
|
38
|
-
git clone https://github.com/
|
38
|
+
git clone https://github.com/TPCyberSec/json-duplicate-keys.git --branch <Branch/Tag>
|
39
39
|
cd json-duplicate-keys
|
40
|
-
python
|
41
|
-
python
|
40
|
+
python -m build
|
41
|
+
python -m pip install dist/json_duplicate_keys-<version>-py3-none-any.whl
|
42
42
|
```
|
43
43
|
|
44
|
-
|
44
|
+
---
|
45
|
+
# 📘 Basic Usage
|
45
46
|
### normalize_key(`name`, `dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False)
|
46
47
|
_Normalize Key name_
|
47
48
|
- `name`: key name
|
@@ -54,8 +55,8 @@ import json_duplicate_keys as jdks
|
|
54
55
|
print(jdks.normalize_key("version{{{_2_}}}"))
|
55
56
|
# OUTPUT: version
|
56
57
|
```
|
57
|
-
---
|
58
58
|
|
59
|
+
---
|
59
60
|
### loads(`Jstr`, `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `skipDuplicated`=False, `_isDebug_`=False)
|
60
61
|
_Deserialize a JSON format string to a class `JSON_DUPLICATE_KEYS`_
|
61
62
|
- `Jstr`: a JSON format string
|
@@ -74,8 +75,8 @@ JDKSObject = jdks.loads(Jstr)
|
|
74
75
|
print(JDKSObject)
|
75
76
|
# OUTPUT: <json_duplicate_keys.JSON_DUPLICATE_KEYS object at 0x00000270AE987940>
|
76
77
|
```
|
77
|
-
---
|
78
78
|
|
79
|
+
---
|
79
80
|
### load(`Jfilepath`, `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `skipDuplicated`=False, `_isDebug_`=False)
|
80
81
|
_Deserialize a JSON format string from a file to a class `JSON_DUPLICATE_KEYS`_
|
81
82
|
- `Jfilepath`: The path to the file containing the JSON format string
|
@@ -96,8 +97,8 @@ JDKSObject = jdks.load(Jfilepath)
|
|
96
97
|
print(JDKSObject)
|
97
98
|
# OUTPUT: <json_duplicate_keys.JSON_DUPLICATE_KEYS object at 0x00000270AE986D40>
|
98
99
|
```
|
99
|
-
---
|
100
100
|
|
101
|
+
---
|
101
102
|
### JSON_DUPLICATE_KEYS.getObject()
|
102
103
|
_Get the JSON object_
|
103
104
|
```python
|
@@ -110,8 +111,8 @@ JDKSObject = jdks.loads(Jstr)
|
|
110
111
|
print(JDKSObject.getObject())
|
111
112
|
# OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan', 'version': '22.3.3', 'release': [{'version': 'latest'}]}}
|
112
113
|
```
|
113
|
-
---
|
114
114
|
|
115
|
+
---
|
115
116
|
### JSON_DUPLICATE_KEYS.get(`name`, `case_insensitive`=False, `separator`="||", `parse_index`="$", `_isDebug_`=False)
|
116
117
|
_Get value in the JSON object by `name`_
|
117
118
|
- `name`: the key name of the JSON object. Supported flatten key name format
|
@@ -135,8 +136,8 @@ print(JDKSObject.get("release||$0$"))
|
|
135
136
|
print(JDKSObject.get("snapshot||author"))
|
136
137
|
# OUTPUT: {'name': 'snapshot||author', 'value': 'truocphan'}
|
137
138
|
```
|
138
|
-
---
|
139
139
|
|
140
|
+
---
|
140
141
|
### JSON_DUPLICATE_KEYS.set(`name`, `value`, `case_insensitive`=False, `separator`="||", `parse_index`="$", `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `_isDebug_`=False)
|
141
142
|
_Set a new `name` and `value` for the JSON object_
|
142
143
|
- `name`: new key name for the JSON object. Supported flat key name format
|
@@ -181,8 +182,8 @@ JDKSObject.set("snapshot||author", "truocphan")
|
|
181
182
|
print(JDKSObject.getObject())
|
182
183
|
# OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan'}}
|
183
184
|
```
|
184
|
-
---
|
185
185
|
|
186
|
+
---
|
186
187
|
### JSON_DUPLICATE_KEYS.insert(`name`, `value`, `position`=None, `case_insensitive`=False, `separator`="||", `parse_index`="$", `dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False)
|
187
188
|
_Insert `value` at `position` in value list of `name`_
|
188
189
|
- `name`: the key name of the JSON object. Supported flatten key name format
|
@@ -209,9 +210,19 @@ JDKSObject.insert("snapshot||release", {'version': '2025.1.1'}, 0)
|
|
209
210
|
|
210
211
|
print(JDKSObject.getObject())
|
211
212
|
# OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}, {'version': '2025.1.1'}], 'snapshot': {'author': 'truocphan', 'version': '22.3.3', 'release': [{'version': '2025.1.1'}, {'version': 'latest'}]}}
|
213
|
+
|
214
|
+
|
215
|
+
JDKSObject = jdks.loads("[]")
|
216
|
+
|
217
|
+
JDKSObject.insert(None, {"release": []})
|
218
|
+
JDKSObject.insert(None, {"author": "truocphan"}, 0)
|
219
|
+
JDKSObject.insert("$1$||release", {"version": "2025.9.9"})
|
220
|
+
|
221
|
+
print(JDKSObject.getObject())
|
222
|
+
# OUTPUT: [{'author': 'truocphan'}, {'release': [{'version': '2025.9.9'}]}]
|
212
223
|
```
|
213
|
-
---
|
214
224
|
|
225
|
+
---
|
215
226
|
### JSON_DUPLICATE_KEYS.update(`name`, `value`, `case_insensitive`=False, `allow_new_key`=False, `separator`="||", `parse_index`="$", `dupSign_start`="{{{", `dupSign_end`="}}}", `ordered_dict`=False, `_isDebug_`=False)
|
216
227
|
_Update new `value` for existing `name` or Set a new `name` in the JSON object_
|
217
228
|
- `name`: the key name of the JSON object. Supported flatten key name format
|
@@ -240,8 +251,8 @@ JDKSObject.update("snapshot||version", "latest")
|
|
240
251
|
print(JDKSObject.getObject())
|
241
252
|
# OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': ['22.3.3', 'latest'], 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan', 'version': 'latest', 'release': [{'version': 'latest'}]}}
|
242
253
|
```
|
243
|
-
---
|
244
254
|
|
255
|
+
---
|
245
256
|
### JSON_DUPLICATE_KEYS.delete(`name`, `case_insensitive`=False, `separator`="||", `parse_index`="$", `_isDebug_`=False)
|
246
257
|
_Delete a key-value pair in a JSON object by key `name`_
|
247
258
|
- `name`: the key name of the JSON object. Supported flatten key name format
|
@@ -266,8 +277,8 @@ JDKSObject.delete("snapshot")
|
|
266
277
|
print(JDKSObject.getObject())
|
267
278
|
# OUTPUT: {'author': 'truocphan', 'version{{{_2_}}}': 'latest', 'release': []}
|
268
279
|
```
|
269
|
-
---
|
270
280
|
|
281
|
+
---
|
271
282
|
### JSON_DUPLICATE_KEYS.filter_keys(`name`, `separator`="||", `parse_index`="$", `ordered_dict`=False)
|
272
283
|
_Return a `JSON_DUPLICATE_KEYS` object with keys matching a pattern_
|
273
284
|
- `name`:
|
@@ -287,8 +298,8 @@ print(JDKSObject.filter_keys("version").dumps())
|
|
287
298
|
print(JDKSObject.dumps())
|
288
299
|
# OUTPUT: {"author": "truocphan", "version": "22.3.3", "version": "latest", "release": [{"version": "latest"}], "snapshot": {"author": "truocphan", "version": "22.3.3", "release": [{"version": "latest"}]}}
|
289
300
|
```
|
290
|
-
---
|
291
301
|
|
302
|
+
---
|
292
303
|
### JSON_DUPLICATE_KEYS.filter_values(`value`, `separator`="||", `parse_index`="$", `ordered_dict`=False)
|
293
304
|
_Return a `JSON_DUPLICATE_KEYS` object with values matching a pattern_
|
294
305
|
- `value`:
|
@@ -308,8 +319,8 @@ print(JDKSObject.filter_values("latest").dumps())
|
|
308
319
|
print(JDKSObject.dumps())
|
309
320
|
# OUTPUT: {"author": "truocphan", "version": "22.3.3", "version": "latest", "release": [{"version": "latest"}], "snapshot": {"author": "truocphan", "version": "22.3.3", "release": [{"version": "latest"}]}}
|
310
321
|
```
|
311
|
-
---
|
312
322
|
|
323
|
+
---
|
313
324
|
### JSON_DUPLICATE_KEYS.dumps(`dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False, `skipkeys`=False, `ensure_ascii`=True, `check_circular`=True, `allow_nan`=True, `cls`=None, `indent`=None, `separators`=None, `default`=None, `sort_keys`=False)
|
314
325
|
_Serialize a JSON object to a JSON format string_
|
315
326
|
- `dupSign_start`: Start symbol for marking duplicates (default: `{{{`)
|
@@ -333,8 +344,8 @@ JDKSObject.delete("snapshot")
|
|
333
344
|
print(JDKSObject.dumps())
|
334
345
|
# OUTPUT: {"author": "truocphan", "version": "latest", "release": []}
|
335
346
|
```
|
336
|
-
---
|
337
347
|
|
348
|
+
---
|
338
349
|
### JSON_DUPLICATE_KEYS.dump(`Jfilepath`, `dupSign_start`="{{{", `dupSign_end`="}}}", `_isDebug_`=False, `skipkeys`=False, `ensure_ascii`=True, `check_circular`=True, `allow_nan`=True, `cls`=None, `indent`=None, `separators`=None, `default`=None, `sort_keys`=False)
|
339
350
|
_Serialize a JSON object to a JSON format string and write to a file_
|
340
351
|
- `Jfilepath`: the path to the file to save the JSON format string
|
@@ -363,8 +374,8 @@ JDKSObject_load = jdks.load(Jfilepath)
|
|
363
374
|
print(JDKSObject_load.getObject())
|
364
375
|
# OUTPUT: {'author': 'truocphan', 'version': 'latest', 'release': []}
|
365
376
|
```
|
366
|
-
---
|
367
377
|
|
378
|
+
---
|
368
379
|
### JSON_DUPLICATE_KEYS.flatten(`separator`="||", `parse_index`="$", `ordered_dict`=False, `_isDebug_`=False)
|
369
380
|
_Flatten a JSON object to a single key-value pairs_
|
370
381
|
- `separator`: Separator for flatten keys (default: `||`)
|
@@ -386,8 +397,8 @@ JDKSObject.flatten()
|
|
386
397
|
print(JDKSObject.getObject())
|
387
398
|
# OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release||$0$||version': 'latest', 'snapshot||author': 'truocphan', 'snapshot||version': '22.3.3', 'snapshot||release||$0$||version': 'latest'}
|
388
399
|
```
|
389
|
-
---
|
390
400
|
|
401
|
+
---
|
391
402
|
### JSON_DUPLICATE_KEYS.unflatten(`separator`="||", `parse_index`="$", `ordered_dict`=False, `_isDebug_`=False)
|
392
403
|
_Unflatten a flattened JSON object back to a JSON object_
|
393
404
|
- `separator`: Separator for flatten keys (default: `||`)
|
@@ -409,33 +420,41 @@ JDKSObject.unflatten()
|
|
409
420
|
print(JDKSObject.getObject())
|
410
421
|
# OUTPUT: {'author': 'truocphan', 'version': '22.3.3', 'version{{{_2_}}}': 'latest', 'release': [{'version': 'latest'}], 'snapshot': {'author': 'truocphan', 'version': '22.3.3', 'release': [{'version': 'latest'}]}}
|
411
422
|
```
|
423
|
+
|
412
424
|
---
|
425
|
+
# 📝 CHANGELOG
|
426
|
+
### [json-duplicate-keys v2025.9.9](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.9.9)
|
427
|
+
- **Fixed**: Inserting a value with an `empty` or `null` name
|
413
428
|
|
414
|
-
|
415
|
-
|
416
|
-
-
|
417
|
-
- [**Updated**] Allow loading of JSON data in byte string format
|
418
|
-
- [**Updated**] Issue with getting and setting an empty list
|
429
|
+
### [json-duplicate-keys v2025.8.19](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.8.19)
|
430
|
+
- **Updated**: Add an exception when loading a non-existent file
|
431
|
+
- **Updated**: Dump Unicode characters to a file
|
419
432
|
|
420
|
-
|
421
|
-
-
|
433
|
+
### [json-duplicate-keys v2025.7.1](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.7.1)
|
434
|
+
- **Updated**: Fixed some issues when loading JSON strings with `skipDuplicated` option
|
435
|
+
- **Updated**: Allow loading of JSON data in byte string format
|
436
|
+
- **Updated**: Issue with getting and setting an empty list
|
422
437
|
|
423
|
-
|
438
|
+
### [json-duplicate-keys v2025.6.6](https://github.com/TPCyberSec/json-duplicate-keys/tree/2025.6.6)
|
439
|
+
- **Updated** Added `skipDuplicated` parameter to `load` and `loads` functions to improve performance when parsing large JSON strings by skipping duplicate keys.
|
440
|
+
|
441
|
+
### [json-duplicate-keys v2024.12.12](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.12.12)
|
424
442
|
- **New**: _insert_ function
|
425
443
|
|
426
|
-
|
444
|
+
### [json-duplicate-keys v2024.11.28](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.11.28)
|
427
445
|
- **Fixed**: Add subkey name to empty dict of existing key name
|
428
446
|
|
429
|
-
|
447
|
+
### [json-duplicate-keys v2024.11.19](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.11.19)
|
430
448
|
- **Updated**: Allows getting (`JSON_DUPLICATE_KEYS.get`), setting (`JSON_DUPLICATE_KEYS.set`), updating (`JSON_DUPLICATE_KEYS.update`), deleting (`JSON_DUPLICATE_KEYS.delete`) JSON_DUPLICATE_KEYS objects with case-insensitive key names
|
431
449
|
|
432
|
-
|
433
|
-
- **Fixed**: issue
|
450
|
+
### [json-duplicate-keys v2024.7.17](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.7.17)
|
451
|
+
- **Fixed**: issue #3 break the set function when the key's value is empty. Thanks [ptth222](https://github.com/ptth222) for reporting this issue.
|
434
452
|
|
435
|
-
|
453
|
+
### [json-duplicate-keys v2024.4.20](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.4.20)
|
436
454
|
- **New**: _filter_values_
|
437
455
|
- **Updated**: _filter_keys_
|
438
456
|
|
439
|
-
|
457
|
+
### [json-duplicate-keys v2024.3.24](https://github.com/TPCyberSec/json-duplicate-keys/tree/2024.3.24)
|
440
458
|
- **Updated**: _normalize_key_, _loads_, _get_, _set_, _update_, _delete_
|
459
|
+
|
441
460
|
---
|
@@ -0,0 +1,6 @@
|
|
1
|
+
json_duplicate_keys/__init__.py,sha256=Ns_b4ZkssTizVwPQmpStuspo_FRLhJOWy_raNJ7I63I,30311
|
2
|
+
json_duplicate_keys-2025.9.9.dist-info/LICENSE,sha256=_hudSGMciUc27wGR8EMKfeb3atJRlf6rbhJtLnel-nc,1093
|
3
|
+
json_duplicate_keys-2025.9.9.dist-info/METADATA,sha256=SXON-ghmCMYFVuxKsEFIbF4tjfsyJZKdZDp8CY5Yx5E,23508
|
4
|
+
json_duplicate_keys-2025.9.9.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
5
|
+
json_duplicate_keys-2025.9.9.dist-info/top_level.txt,sha256=vdsGrPLVS_l-BFL1i4hCJBY5_-gq4Cwp-11yegA750Y,20
|
6
|
+
json_duplicate_keys-2025.9.9.dist-info/RECORD,,
|
@@ -1,6 +0,0 @@
|
|
1
|
-
json_duplicate_keys/__init__.py,sha256=ClhnGD0jyYwBRsOs9zHevi6WWGtnMEOjczwkUC0BMv8,30753
|
2
|
-
json_duplicate_keys-2025.7.1.dist-info/LICENSE,sha256=_hudSGMciUc27wGR8EMKfeb3atJRlf6rbhJtLnel-nc,1093
|
3
|
-
json_duplicate_keys-2025.7.1.dist-info/METADATA,sha256=wvDz2_ia5VuzhLvNiVZnrI7YJEVfjGVwy07RGb2-dQk,22717
|
4
|
-
json_duplicate_keys-2025.7.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
5
|
-
json_duplicate_keys-2025.7.1.dist-info/top_level.txt,sha256=vdsGrPLVS_l-BFL1i4hCJBY5_-gq4Cwp-11yegA750Y,20
|
6
|
-
json_duplicate_keys-2025.7.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{json_duplicate_keys-2025.7.1.dist-info → json_duplicate_keys-2025.9.9.dist-info}/top_level.txt
RENAMED
File without changes
|