How to reference a choice selection in YANG?

Hello,

I’m looking for some help/advice on how to reference a choice in YANG.

I have a two containers “elements” and “sub-elements” each containing a list (element-instance and sub-element-instance). Each element must be of a type (choice elemnent–type), and each sub-element must belong to an existing element and has different attributes depending on which element it belongs to.

For each sub-element, I have defined a “belongs-to-element-name” and “belongs-to-element-type” leafs and I need to constrain these to values based on the existing elements.

It seems that I cannot use a leafref or a must statement to constrain the value of the “belongs-to-element-type” leaf to whatever choice was made in the elements list. (Note: I need to use the choice in both containers as in my model each choice case calls other modules and attributes through a uses statement).

I have attached a sample use-case below. Any suggestions on how to make this work?

Thanks,
Mariusz

SAMPLE YANG USE-CASE:

container configuration {
    list configuration-branch {
        key "key-1 key-2 key-3 key-4 key-5 key-6";
        leaf key-1 {type string;}
        leaf key-2 {type string;}
        leaf key-3 {type string;}
        leaf key-4 {type string;}
        leaf key-5 {type string;}
        leaf key-6 {type string;}
        container elements {
            list element-instance {
                key element--name;
                leaf element--name {type string;}
                choice element--type {
                    case element-type-1 {
                        leaf element-type-1-attribute {type string;}
                    }
                    case element-type-2 {
                        leaf element-type-2-attribute {type string;}
                    }
                    case element-type-3 {
                        leaf element-type-3-attribute {type string;}
                    }
                    case element-type-4 {
                        leaf element-type-4-attribute {type string;}
                    }
                }
            }
        }
        container sub-elements {
            list sub-element-instance {
                key sub-element--name;
                leaf sub-element--name {type string;}
                leaf belongs-to-element-name {
                    type leafref {
                        path "../../../../configuration-branch"
                         + "[key-1=current()/../../../key-1][key-2=current()/../../../key-2][key-3=current()/../../../key-3]"
                         + "[key-4=current()/../../../key-4][key-5=current()/../../../key-5][key-6=current()/../../../key-6]"
                         + "/elements/element-instance/element--name";
                    }                  
                }
                leaf belongs-to-element-type {
                    type leafref {
                        path "../../../../configuration-branch"
                         + "[key-1=current()/../../../key-1][key-2=current()/../../../key-2][key-3=current()/../../../key-3]"
                         + "[key-4=current()/../../../key-4][key-5=current()/../../../key-5][key-6=current()/../../../key-6]"                         
						 + "/elements/element-instance[name=current()/../belongs-to-element-name]/element--type";
                        }                  
                    must "../belongs-to-subsystem-type=../subsystem--type";
                }
                choice element--type {                                 
                    case element-type-1 {
                        leaf element-type-1-sub-element-attribute {type string;}
                    }
                    case element-type-2 {
                        leaf element-type-2-sub-element-attribute {type string;}
                    }
                    case element-type-3 {
                        leaf element-type-3-sub-element-attribute {type string;}
                    }
                    case element-type-4 {
                        leaf element-type-4-sub-element-attribute {type string;}
                    }
                }
            }
        }
    }
}

For your ‘list element-instance’, have you considered using either an enum or identityref rather than having a choice with leafs representing the element type. Then you can have a simple attribute type and look at the type field to interpret it.

Also for the sub-elements, you could consider using a ‘when’ statement for the different types, or have a simple choice statement where you comment what should be present for each type, and you can use a validation callback to check that the user has sent the correct choice for the type.

Thanks for your suggestion. I did not consider this approach but based on my understanding of your comment, I have updated my example below. Is this in line with your suggestion?

I have to admit that I’m not very familiar with identityref (although I have read the relevant RFC 7950 sections). Were you suggesting that I define ‘element-type-1’, ‘element-type-2’, etc… as identities, then the “element–type” leaf as an identityref type and use the same ‘when’ statements?

If yes, then is the advantage of using identityref simply that you can derive types as opposed to not having this possibility with enums? Are there other reasons to use one or the other?

UPDATED YANG USE-CASE:

container configuration {
    list configuration-branch {
        key "key-1 key-2 key-3 key-4 key-5 key-6";
        leaf key-1 {type string;}
        leaf key-2 {type string;}
        leaf key-3 {type string;}
        leaf key-4 {type string;}
        leaf key-5 {type string;}
        leaf key-6 {type string;}
        container elements {
            list element-instance {
                key element--name;
                leaf element--name {type string;}
                leaf element--type {
                    type enumeration {
                        enum element-type-1;
                        enum element-type-2;
                        enum element-type-3;
                        enum element-type-4;
                    }
                }
                container element-type-1-attributes {
                    when "../element--type='element-type-1'";
                    leaf element-type-1-attribute {type string;}                        
                }
                container element-type-2-attributes {
                    when "../element--type='element-type-2'";
                    leaf element-type-2-attribute {type string;}                        
                }
                container element-type-3-attributes {
                    when "../element--type='element-type-3'";
                    leaf element-type-3-attribute {type string;}                        
                }
                container element-type-4-attributes {
                    when "../element--type='element-type-4'";
                    leaf element-type-4-attribute {type string;}                        
                }
            }
        }
        container sub-elements {
            list sub-element-instance {
                key sub-element--name;
                leaf sub-element--name {type string;}
                leaf belongs-to-element-name {
                    type leafref {
                        path "../../../../configuration-branch"
                         + "[key-1=current()/../../../key-1][key-2=current()/../../../key-2][key-3=current()/../../../key-3]"
                         + "[key-4=current()/../../../key-4][key-5=current()/../../../key-5][key-6=current()/../../../key-6]"
                         + "/elements/element-instance/element--name";
                    }                  
                }
                leaf belongs-to-element-type {
                    type leafref {
                        path "../../../../configuration-branch"
                         + "[key-1=current()/../../../key-1][key-2=current()/../../../key-2][key-3=current()/../../../key-3]"
                         + "[key-4=current()/../../../key-4][key-5=current()/../../../key-5][key-6=current()/../../../key-6]"
                         + "/elements/element-instance[element--name=current()/../belongs-to-element-name]/element--type";
                    }                  
                    must "../belongs-to-element-type=../../../elements/element-instance[element--name=current()/../belongs-to-element-name]/element--type";
                }
                container element-type-1-sub-element-attributes {
                    when "../belongs-to-element-type='element-type-1'";
                    leaf element-type-1-sub-element-attribute {type string;}                        
                }
                container element-type-2-sub-element-attributes {
                    when "../belongs-to-element-type='element-type-2'";
                    leaf element-type-2-sub-element-attribute {type string;}                        
                }
                container element-type-3-sub-element-attributes {
                    when "../belongs-to-element-type='element-type-3'";
                    leaf element-type-3-sub-element-attribute {type string;}                        
                }
                container element-type-4-sub-element-attributes {
                    when "../belongs-to-element-type='element-type-4'";
                    leaf element-type-4-sub-element-attribute {type string;}                        
                }
            }
        }
    }
}