CZ-NIC / yangson

GNU Lesser General Public License v3.0
53 stars 20 forks source link

Get list of valid data nodes for leafref #107

Closed christian-herber closed 3 years ago

christian-herber commented 3 years ago

I am looking for a way to do the following: Given a certain leafref node, I would like to have the list of values/data nodes, that can be referred to be the leafref.

I don't see any build in function for that, and honestly I do not see a clear way to do this in any way right now. Any suggestions on how to achieve this?

llhotka commented 3 years ago

You can get that nodeset by evaluating the leafref's type path expression. Try e.g. this in the docs/examples/ex4 directory:

import json
from yangson import DataModel

dm = DataModel.from_file('yang-library-ex4.json', mod_path=['.', '../../../yang-modules/ietf'])
rsn = dm.get_schema_node('/example-4-a:bag/opts/example-4-b:fooref/fooref')
with open('example-data.json') as infile:
    ri = json.load(infile)
inst = dm.from_raw(ri)
bsn = rsn.data_parent()
lr = inst["example-4-a:bag"]["example-4-b:fooref"]
ns = rsn.type.path.evaluate(lr)
print(repr(ns))

The result in this case contains only one instance node, but it should work for more as well.

christian-herber commented 3 years ago

Correct me if I am wrong, but i think we are referring to two different things.

llhotka commented 3 years ago

The ns value is a list containing just one entry, because there is no other choice. More entries should be present, if you refer, for example, to the key of a list with multiple entries.

As for the possible value, in the example above it is the value of that ObjectMember (42).

christian-herber commented 3 years ago

What confuses me here is that in

rsn.type.path.evaluate(lr)

you are actually passing instance data of the leafref node. Is that necessary? And if yes, why? Given the situation, that the leafref node does not exist in my data instance, would I be able to answer the question, what are the possible values for the leafref?

I would have expected that passing the data e.g. at the root would be sufficient.

llhotka commented 3 years ago

you are actually passing instance data of the leafref node. Is that necessary? And if yes, why?

The leafref path is an XPath expression that has to be evaluated with a given context node. The result may be different for a relative path, e.g. a leafref that's inside a list and the path is ../foo. Then the referenced foo leaf is always in the same list entry as the leafref instance.

Another way of writing the above expression is

lr.schema_node.type.path.evaluate(lr)

Here the leafref instance is the only variable.

If the leafref instance doesn't exist, you can create a dummy one - with the zipper structure it is cheap and doesn't affect the real data.

christian-herber commented 3 years ago

I can confirm that this is working. In general, I think it would be nice if any instance data at any node could be passed (e.g.) root, so that you are not relying on the user to have a data node already existing.