Add Dumas JSON utility batch
This commit is contained in:
@@ -43,6 +43,21 @@ def _get_json_path_value(data, path):
|
||||
return current
|
||||
|
||||
|
||||
def _has_json_path(data, path):
|
||||
current = data
|
||||
for segment in _parse_json_path(path):
|
||||
if isinstance(segment, int):
|
||||
if not isinstance(current, list) or segment >= len(current):
|
||||
return False
|
||||
current = current[segment]
|
||||
continue
|
||||
|
||||
if not isinstance(current, dict) or segment not in current:
|
||||
return False
|
||||
current = current[segment]
|
||||
return True
|
||||
|
||||
|
||||
def _build_missing_container(next_segment):
|
||||
return [] if isinstance(next_segment, int) else {}
|
||||
|
||||
@@ -104,6 +119,50 @@ def _set_json_path_value(data, path, value):
|
||||
return _set_json_path_value_recursive(data, segments, value)
|
||||
|
||||
|
||||
def _remove_json_path_value_recursive(current, segments):
|
||||
if not segments:
|
||||
return _clone_container(current)
|
||||
|
||||
segment = segments[0]
|
||||
is_last = len(segments) == 1
|
||||
|
||||
if isinstance(segment, int):
|
||||
if not isinstance(current, list) or segment >= len(current):
|
||||
return None
|
||||
|
||||
result = list(current)
|
||||
if is_last:
|
||||
del result[segment]
|
||||
return result
|
||||
|
||||
updated = _remove_json_path_value_recursive(result[segment], segments[1:])
|
||||
if updated is None:
|
||||
return None
|
||||
result[segment] = updated
|
||||
return result
|
||||
|
||||
if not isinstance(current, dict) or segment not in current:
|
||||
return None
|
||||
|
||||
result = dict(current)
|
||||
if is_last:
|
||||
del result[segment]
|
||||
return result
|
||||
|
||||
updated = _remove_json_path_value_recursive(result[segment], segments[1:])
|
||||
if updated is None:
|
||||
return None
|
||||
result[segment] = updated
|
||||
return result
|
||||
|
||||
|
||||
def _remove_json_path_value(data, path):
|
||||
segments = _parse_json_path(path)
|
||||
if not segments:
|
||||
return _clone_container(data)
|
||||
return _remove_json_path_value_recursive(data, segments)
|
||||
|
||||
|
||||
def _merge_json_objects(base_object, overlay_object):
|
||||
if not isinstance(base_object, dict) or not isinstance(overlay_object, dict):
|
||||
return None
|
||||
@@ -118,6 +177,46 @@ def _merge_json_objects(base_object, overlay_object):
|
||||
return merged
|
||||
|
||||
|
||||
def _flatten_json_value(value, prefix="", result=None):
|
||||
if result is None:
|
||||
result = {}
|
||||
|
||||
if isinstance(value, dict):
|
||||
if not value and prefix:
|
||||
result[prefix] = {}
|
||||
return result
|
||||
for key, nested_value in value.items():
|
||||
next_prefix = f"{prefix}.{key}" if prefix else str(key)
|
||||
_flatten_json_value(nested_value, next_prefix, result)
|
||||
return result
|
||||
|
||||
if isinstance(value, list):
|
||||
if not value and prefix:
|
||||
result[prefix] = []
|
||||
return result
|
||||
for index, nested_value in enumerate(value):
|
||||
next_prefix = f"{prefix}.{index}" if prefix else str(index)
|
||||
_flatten_json_value(nested_value, next_prefix, result)
|
||||
return result
|
||||
|
||||
result[prefix] = value
|
||||
return result
|
||||
|
||||
|
||||
def _unflatten_json_object(flat_object):
|
||||
if not isinstance(flat_object, dict):
|
||||
return None
|
||||
|
||||
result = {}
|
||||
for path, value in flat_object.items():
|
||||
if not isinstance(path, str):
|
||||
return None
|
||||
result = _set_json_path_value(result, path, value)
|
||||
if result is None:
|
||||
return None
|
||||
return result
|
||||
|
||||
|
||||
def _resolve_iteration_index(index, mode, total_items):
|
||||
if total_items <= 0:
|
||||
return -1
|
||||
@@ -216,6 +315,69 @@ class DumasJSONSetValueNode:
|
||||
return (_set_json_path_value(json_object, path, value),)
|
||||
|
||||
|
||||
class DumasJSONHasKeyNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "has_key"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_object": ("JSON",),
|
||||
"path": ("STRING", {"default": "", "multiline": False}),
|
||||
}
|
||||
}
|
||||
|
||||
def has_key(self, json_object, path):
|
||||
return (_has_json_path(json_object, path),)
|
||||
|
||||
|
||||
class DumasJSONRemoveKeyNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON",)
|
||||
FUNCTION = "remove_key"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_object": ("JSON",),
|
||||
"path": ("STRING", {"default": "", "multiline": False}),
|
||||
}
|
||||
}
|
||||
|
||||
def remove_key(self, json_object, path):
|
||||
return (_remove_json_path_value(json_object, path),)
|
||||
|
||||
|
||||
class DumasJSONPickFieldsNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON",)
|
||||
FUNCTION = "pick_fields"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_object": ("JSON",),
|
||||
"paths": ("STRING", {"multiline": True, "default": ""}),
|
||||
}
|
||||
}
|
||||
|
||||
def pick_fields(self, json_object, paths):
|
||||
result = {}
|
||||
for raw_path in paths.splitlines():
|
||||
path = raw_path.strip()
|
||||
if not path or not _has_json_path(json_object, path):
|
||||
continue
|
||||
value = _get_json_path_value(json_object, path)
|
||||
result = _set_json_path_value(result, path, value)
|
||||
if result is None:
|
||||
return (None,)
|
||||
return (result,)
|
||||
|
||||
|
||||
class DumasJSONMergeObjectsNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON",)
|
||||
@@ -274,6 +436,56 @@ class DumasJSONArrayLengthNode:
|
||||
return (len(json_array),)
|
||||
|
||||
|
||||
class DumasJSONArrayAppendNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON",)
|
||||
FUNCTION = "append_item"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_array": ("JSON",),
|
||||
"value_json": ("STRING", {"multiline": True, "default": "null"}),
|
||||
}
|
||||
}
|
||||
|
||||
def append_item(self, json_array, value_json):
|
||||
if not isinstance(json_array, list):
|
||||
return (None,)
|
||||
try:
|
||||
value = json.loads(value_json)
|
||||
except json.JSONDecodeError as exc:
|
||||
print(f"[DumasNodes] Error decoding JSON value: {exc}")
|
||||
return (None,)
|
||||
result = list(json_array)
|
||||
result.append(value)
|
||||
return (result,)
|
||||
|
||||
|
||||
class DumasJSONArraySliceNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON",)
|
||||
FUNCTION = "slice_array"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_array": ("JSON",),
|
||||
"start": ("INT", {"default": 0, "step": 1}),
|
||||
"end": ("INT", {"default": 0, "step": 1}),
|
||||
"step": ("INT", {"default": 1, "step": 1, "min": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
def slice_array(self, json_array, start, end, step):
|
||||
if not isinstance(json_array, list):
|
||||
return (None,)
|
||||
actual_end = None if end == 0 else end
|
||||
return (json_array[start:actual_end:step],)
|
||||
|
||||
|
||||
class DumasJSONArrayIteratorNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON", "INT", "INT")
|
||||
@@ -331,16 +543,57 @@ class DumasJSONObjectIteratorNode:
|
||||
return (key, value, current_index, total_items)
|
||||
|
||||
|
||||
class DumasJSONFlattenNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON",)
|
||||
FUNCTION = "flatten_json"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_input": ("JSON",),
|
||||
}
|
||||
}
|
||||
|
||||
def flatten_json(self, json_input):
|
||||
return (_flatten_json_value(json_input),)
|
||||
|
||||
|
||||
class DumasJSONUnflattenNode:
|
||||
CATEGORY = "Dumas/JSON"
|
||||
RETURN_TYPES = ("JSON",)
|
||||
FUNCTION = "unflatten_json"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"flat_json_object": ("JSON",),
|
||||
}
|
||||
}
|
||||
|
||||
def unflatten_json(self, flat_json_object):
|
||||
return (_unflatten_json_object(flat_json_object),)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"DumasJSONStringToObject": DumasJSONStringToObjectNode,
|
||||
"DumasJSONObjectToString": DumasJSONObjectToStringNode,
|
||||
"DumasJSONGetValue": DumasJSONGetValueNode,
|
||||
"DumasJSONSetValue": DumasJSONSetValueNode,
|
||||
"DumasJSONHasKey": DumasJSONHasKeyNode,
|
||||
"DumasJSONRemoveKey": DumasJSONRemoveKeyNode,
|
||||
"DumasJSONPickFields": DumasJSONPickFieldsNode,
|
||||
"DumasJSONMergeObjects": DumasJSONMergeObjectsNode,
|
||||
"DumasJSONKeys": DumasJSONKeysNode,
|
||||
"DumasJSONArrayLength": DumasJSONArrayLengthNode,
|
||||
"DumasJSONArrayAppend": DumasJSONArrayAppendNode,
|
||||
"DumasJSONArraySlice": DumasJSONArraySliceNode,
|
||||
"DumasJSONArrayIterator": DumasJSONArrayIteratorNode,
|
||||
"DumasJSONObjectIterator": DumasJSONObjectIteratorNode,
|
||||
"DumasJSONFlatten": DumasJSONFlattenNode,
|
||||
"DumasJSONUnflatten": DumasJSONUnflattenNode,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -348,9 +601,16 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"DumasJSONObjectToString": "Dumas JSON Object to String",
|
||||
"DumasJSONGetValue": "Dumas JSON Get Value",
|
||||
"DumasJSONSetValue": "Dumas JSON Set Value",
|
||||
"DumasJSONHasKey": "Dumas JSON Has Key",
|
||||
"DumasJSONRemoveKey": "Dumas JSON Remove Key",
|
||||
"DumasJSONPickFields": "Dumas JSON Pick Fields",
|
||||
"DumasJSONMergeObjects": "Dumas JSON Merge Objects",
|
||||
"DumasJSONKeys": "Dumas JSON Keys",
|
||||
"DumasJSONArrayLength": "Dumas JSON Array Length",
|
||||
"DumasJSONArrayAppend": "Dumas JSON Array Append",
|
||||
"DumasJSONArraySlice": "Dumas JSON Array Slice",
|
||||
"DumasJSONArrayIterator": "Dumas JSON Array Iterator",
|
||||
"DumasJSONObjectIterator": "Dumas JSON Object Iterator",
|
||||
"DumasJSONFlatten": "Dumas JSON Flatten",
|
||||
"DumasJSONUnflatten": "Dumas JSON Unflatten",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user