libelektra: YAJL: Invalid JSON Sequence

A key creation sequence involving a object followed by a array creates invalid json.

Steps to Reproduce the Problem

kdb set /org/freedesktop/openicc/one/key val
#> Using name user/org/freedesktop/openicc/one/key
#> Create a new key user/org/freedesktop/openicc/one/key with string "val"

kdb set /org/freedesktop/openicc/#1/key other
#> Using name user/org/freedesktop/openicc/#1/key
#> Create a new key user/org/freedesktop/openicc/#1/key with string "other"

kdb ls /org/freedesktop/openicc
#> The command kdb ls failed while accessing the key database with the info:
#> Sorry, the error (#77) occurred ;(
#> Description: Yajl parser error
#> Reason: parse error: after array element, I expect ',' or ']'
#>                          }             }         }     } } 
#>                     (right here) ------^
#>
#> Ingroup: plugin
#> Module: yajl
#> At: /tmp/libelektra/src/plugins/yajl/yajl_parse.c:381
#> Mountpoint: user/org/freedesktop/openicc
#> Configfile: ~/.config/color/settings/openicc.json

Expected Result

Return just an error for the array index on a object path. Or use the #1 index to access a existing object, but do not create a array if a a object is already in place.

Actual Result

The below JSON contains a opening array ‘[’ without closing ‘]’.

{
    "org": {
        "freedesktop": {
            "openicc": [
                {
                    "key": "other",
                    "key": "val"
                }
            }
        }
    }
}

System Information

  • Elektra Version: master
  • yajl-2.1

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 16 (14 by maintainers)

Commits related to this issue

Most upvoted comments

Why do you add “key”?

I added key, because it was part of the initial issue description.

Oh, the sequence was only a example. No need to name a key “key” from my side

{
  "KEY_abc": "VALUE_def",
  "my_entry": "a_value"
}

should be enough 😄

Why do you add “key”?

I added key, because it was part of the initial issue description.

Isn’t this enough: …

Yep, that simpler JSON object also shows how to handle the issue.

How do you currently handle this problem in your YAML plugins?

None of the YAML plugins handle this situation (in the set direction) properly. In my opinion the best solution to solve this problem is to just use a map containing the keys #1 and one.

"#1":
  key: other
one:
  key: val

. In the get direction this already works in YAML CPP, Yan LR, YAMBi, YAwn and YAy PEG:

kdb mount config.yaml user/tests/yaml yamlcpp
printf '"#1":\n'        >  `kdb file user/tests/yaml`
printf '  key: other\n' >> `kdb file user/tests/yaml`
printf 'one:\n'         >> `kdb file user/tests/yaml`
printf '  key: val\n'   >> `kdb file user/tests/yaml`
kdb ls user/tests/yaml
#> user/tests/yaml/#1/key
#> user/tests/yaml/one/key

. The same strategy should also work for YAJL. The JSON version of the YAML file above looks like this:

{
  "#1": {
    "key": "other"
  },
  "one": {
    "key": "other"
  }
}

. Unfortunately YAJL does not handle this situation in the get direction properly:

kdb mount config.json user/tests/yajl yajl
printf '{'                  2> /dev/null >  `kdb file user/tests/yajl` 
printf '  "#1": {'          2> /dev/null >> `kdb file user/tests/yajl` 
printf '    "key": "other"' 2> /dev/null >> `kdb file user/tests/yajl` 
printf '  },'               2> /dev/null >> `kdb file user/tests/yajl` 
printf '  "one": {'         2> /dev/null >> `kdb file user/tests/yajl` 
printf '    "key": "other"' 2> /dev/null >> `kdb file user/tests/yajl` 
printf '  }'                2> /dev/null >> `kdb file user/tests/yajl` 
printf '}'                  2> /dev/null >> `kdb file user/tests/yajl` 
kdb ls user/tests/yajl
#> user/tests/yajl
#> user/tests/yajl/#1
#> user/tests/yajl/#2
#> user/tests/yajl/#2/key
#> user/tests/yajl/#3
#> user/tests/yajl/one
#> user/tests/yajl/one/key

.

Nope. I think this problem should be fixed inside YAJL and not in the Directory Value plugin.

Doesn’t kdb ls --max-depth=1 /org/freedesktop/openicc/ do what you want? (Count array or map members?)

Indeed it works:

kdb ls --max-depth=1 /org/freedesktop/openicc/display/display_white_point_XYZ/
#> user/org/freedesktop/openicc/display/display_white_point_XYZ/#0
#> user/org/freedesktop/openicc/display/display_white_point_XYZ/#1
#> user/org/freedesktop/openicc/display/display_white_point_XYZ/#2

What exactly does the oyjl tool do?

It is only a low level JSON editor for scripting, API design and testing.

In Elektra we want exactly one unique key for every configuration setting. We could add syntactic sugar on top to refer to the “first” map entry with #0. But JSON does not define any order (only Elektra does), and the order is subject to be changed if an “object”/map gets additional members. So it seems to be quite dangerous to index by number if only a string is unambiguous?

Correct. However arrays are quite practical and can be used reasonably. JSON is a serialisation syntax. So I am still optimistic and guess most users will not shuffle keys or arrays.