Subject: [netmod] YANG 'must' Xpaths, predicates and wildcards

From: "Sterne, Jason (Nokia - CA/Ottawa)" <[email-masked]>
Date: Wed, 28 Mar 2018 00:10:10 +0000

Hi all,

I'm pretty sure that this xpath (e.g. in a must statement) isn't correct:

              (A) ../container-a/list-b[name=*]/some-leaf

and should just be this instead:

              (B) ../container-a/list-b/some-leaf

Or is the * an allowable wildcard for a key value in a predicate ?

I also had a question about whether the following "must" correctly checks that at least one entry exists in a-list.

  container c1 {
    leaf foo {
      must "a-list";
      type uint16;
    }
    list a-list {
      key "entry";
      leaf entry {
        type uint16;
      }
      leaf another-entry {
        type uint32;
      }
    }
  }

I think I could also replace that must with the following:
      must "count(a-list) > 1";
but does must "a-list"; achieve the same thing ?

Rgds,
Jason

---

From: Alex Campbell <[email-masked]>
Date: Wed, 28 Mar 2018 01:56:52 +0000

Hi,

For one thing, it should be ../a-list since a-list is not a child of foo.

Also - if foo is not configured and has no default value, then any must expressions in foo are not evaluated because it is not part of the "accessible tree". (I tested this in ConfD)

Apart from these issues, yes it will behave as you expect - it will fail if a-list contains no entries.

must "count(a-list) > 1"; is not equivalent since it requires at least two entries.

However, you can more simply add a min-elements 1; statement to a-list to achieve the same goal - no XPath required.

________________________________
From: netmod <[email-masked]> on behalf of Sterne, Jason (Nokia - CA/Ottawa) <[email-masked]>
Sent: Wednesday, 28 March 2018 1:10 p.m.
To: [email-masked]
Subject: [netmod] YANG 'must' Xpaths, predicates and wildcards

Hi all,

  container c1 {
    leaf foo {
      must "a-list";
      type uint16;
    }
    list a-list {
      key "entry";
      leaf entry {
        type uint16;
      }
      leaf another-entry {
        type uint32;
      }
    }
  }

Rgds,
Jason

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 28 Mar 2018 08:26:24 +0200 (CEST)

Hi,

>               (B) ../container-a/list-b/some-leaf

Assuming all list entries has a 'name', yes, it is the same.

> Or is the * an allowable wildcard for a key value in a predicate ?

"*" is syntactically legal, but is not a wildcard on all values of the
node; it is a wildcard for all nodes.

So if all list entries has a name, A will evaluate to the same nodeset
as B, since "name = *" is a node-set comparison, and the node "name"
will be present in the node set from "*" (node set comparisons are not
always intuitive; read the spec for all details ;-)

> I also had a question about whether the following "must" correctly
> checks that at least one entry exists in a-list.
> 
>   container c1 {
>     leaf foo {
>       must "a-list";
>       type uint16;
>     }
>     list a-list {
>       key "entry";
>       leaf entry {
>         type uint16;
>       }
>       leaf another-entry {
>         type uint32;
>       }
>     }
>   }
> 

Yes, but if the list is big, the simple "a-list" may be more
efficient, since "count()" will actually count all instances
(modulo existance of optimizations in the evaluator).

/martin

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 28 Mar 2018 08:28:46 +0200 (CEST)

> (modulo existance of optimizations in the evaluator).

Whoops, I was too quick; see Alex's email for a better answer!

/martin

---

From: "Sterne, Jason (Nokia - CA/Ottawa)" <[email-masked]>
Date: Wed, 28 Mar 2018 16:11:45 +0000

Thanks Alex.  Sorry about those sloppy mistakes.  I agree about the ../a-list and I should have said count > 0.

In the 2nd part of my email, my intention was to only allow foo to be configured if a-list has at least one entry configured.   So I don't think min-elements 1 would work.  I don't want to always require an entry in a-list.  I only want to require one if foo is configured.

I guess this also achieves the same thing right ?
      must "../a-list[entry=*]";

If foo has a default value, then does that mean the "must" is evaluated even if foo is deleted from the config ?
    leaf foo {
      must "../a-list";   <- always evaluated because of default ?
      type uint16;
      default 5;
    }
If the must is always evaluated then it would be the equivalent of having min-elements 1 in a-list.

Rgds,
Jason

From: Alex Campbell [mailto:[email-masked]]
Sent: Tuesday, March 27, 2018 9:57 PM
To: Sterne, Jason (Nokia - CA/Ottawa) <[email-masked]>; [email-masked]
Subject: Re: YANG 'must' Xpaths, predicates and wildcards

Hi,

________________________________
From: netmod <[email-masked]<mailto:[email-masked]>> on behalf of Sterne, Jason (Nokia - CA/Ottawa) <[email-masked]<mailto:[email-masked]>>
Sent: Wednesday, 28 March 2018 1:10 p.m.
To: [email-masked]<mailto:[email-masked]>
Subject: [netmod] YANG 'must' Xpaths, predicates and wildcards

Hi all,

  container c1 {
    leaf foo {
      must "a-list";
      type uint16;
    }
    list a-list {
      key "entry";
      leaf entry {
        type uint16;
      }
      leaf another-entry {
        type uint32;
      }
    }
  }

Rgds,
Jason

---

From: "Sterne, Jason (Nokia - CA/Ottawa)" <[email-masked]>
Date: Wed, 28 Mar 2018 16:19:46 +0000

Thx Martin.  Pls see below.
Jason

> -----Original Message-----
> From: Martin Bjorklund [mailto:[email-masked]]
> Sent: Wednesday, March 28, 2018 2:26 AM
> To: Sterne, Jason (Nokia - CA/Ottawa) <[email-masked]>
> Cc: [email-masked]
> Subject: Re: [netmod] YANG 'must' Xpaths, predicates and wildcards
> 
> Hi,
> 
> "*" is syntactically legal, 

[>>JTS: ] That surprises me. I've seen the use of * described in XPath docs but it always seems to be in cases outside any predicates.  I couldn't find somewhere that shows * as a wildcard in a predicate (or examples of them).
[>>JTS: ] Does this [xyz=*] work for all types of keys (strings, integers, etc) ?  (i.e. will match on all entries in the list)

but is not a wildcard on all values of the
> always intuitive; read the spec for all details ;-)

[>>JTS: ] I'll try to dig through the specs but this subtlety (wildcard for all nodes, vs wildcard for all values) is beyond me at the moment.  
[>>JTS: ] You mention "if all list entries has a name".  I assume you mean that all list-b entries have a name.  I wasn't clear enough above but in my example, 'name' is the key for list-b.   So all entries have a name (ignoring config false lists that can have no keys for the moment).

---

From: Ladislav Lhotka <[email-masked]>
Date: Wed, 28 Mar 2018 18:36:01 +0200

On Wed, 2018-03-28 at 16:19 +0000, Sterne, Jason (Nokia - CA/Ottawa) wrote:
> [>>JTS: ] That surprises me. I've seen the use of * described in XPath docs
> but it always seems to be in cases outside any predicates.  I couldn't find
> somewhere that shows * as a wildcard in a predicate (or examples of them).
> [>>JTS: ] Does this [xyz=*] work for all types of keys (strings, integers,
> etc) ?  (i.e. will match on all entries in the list)
> 

It really doesn't matter, the asterisk is a special case of location path that
selects all element children of the context node, see 

https://www.w3.org/TR/1999/REC-xpath-19991116/#location-paths

If used in a predicate like [xyz=*], then the rules (quite complex) for equality
expressions have to be taken into account.

Lada

> [>>JTS: ] I'll try to dig through the specs but this subtlety (wildcard for
> all nodes, vs wildcard for all values) is beyond me at the moment.  
> [>>JTS: ] You mention "if all list entries has a name".  I assume you mean
> that all list-b entries have a name.  I wasn't clear enough above but in my
> example, 'name' is the key for list-b.   So all entries have a name (ignoring
> config false lists that can have no keys for the moment).
> 
> > 
> _______________________________________________
> netmod mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/netmod
-- 
Ladislav Lhotka
Head, CZ.NIC Labs
PGP Key ID: 0xB8F92B08A9F76C67

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 28 Mar 2018 19:27:50 +0200 (CEST)

"Sterne, Jason (Nokia - CA/Ottawa)" <[email-masked]> wrote:
> Thanks Alex.  Sorry about those sloppy mistakes.  I agree about the
> ../a-list and I should have said count > 0.
> 
> In the 2nd part of my email, my intention was to only allow foo to be
> configured if a-list has at least one entry configured.  So I don't
> think min-elements 1 would work.  I don't want to always require an
> entry in a-list.  I only want to require one if foo is configured.
> 

Yes, if all a-list entries has a node called "entry".  But if that't
what you want, do:

       must "../a-list[entry]";

> If foo has a default value, then does that mean the "must" is
> evaluated even if foo is deleted from the config ?
>     leaf foo {

Correct.

/martin

> To: Sterne, Jason (Nokia - CA/Ottawa) <[email-masked]>;
> netmod@ietf..org
> Also - if foo is not configured and has no default value, then any
> must expressions in foo are not evaluated because it is not part of
> the "accessible tree". (I tested this in ConfD)
> 
> However, you can more simply add a min-elements 1; statement to a-list
> to achieve the same goal - no XPath required.
> 
> 
> 
> From: netmod <[email-masked]<mailto:[email-masked]>>
> on behalf of Sterne, Jason (Nokia - CA/Ottawa)
> <[email-masked]<mailto:[email-masked]>>

---

From: "Sterne, Jason (Nokia - CA/Ottawa)" <[email-masked]>
Date: Wed, 28 Mar 2018 17:46:37 +0000

Thx.  In the case I'm most concerned about, a-list (and all descendants) is config true and 'entry' is the key leaf.  So all a-list entries have a node called 'entry' by definition.

(I'm regretting using the name 'entry' for my key now in this example 😊

In this case it seems all the following result in the equivalent behavior (checking that a-list has at least one entry):
	must "../a-list";
	must "../a-list[entry=*]";
	must "../a-list[entry]";  <- this confuses me but I'll take your word for it
	must "../a-list/entry";
	must "../a-list[entry=*]/entry";
	must "../a-list[entry]/entry";  <- not sure about this one

Rgds,
Jason

> Sent: Wednesday, March 28, 2018 1:28 PM
> Cc: [email-masked]; [email-masked]

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 28 Mar 2018 19:50:54 +0200 (CEST)

"Sterne, Jason (Nokia - CA/Ottawa)" <[email-masked]> wrote:
> Thx.  In the case I'm most concerned about, a-list (and all
> descendants) is config true and 'entry' is the key leaf.

No need to check for a key's existance!

> So all
> a-list entries have a node called 'entry' by definition.
> 

Yes.  As would:

    must "../a-list[1=1]/entry";
    must "../a-list[count(*) > 0]/entry";

etc; if you want to have a confusing expression instead of the simple:

    must "../a-list";

/martin

---

From: Alex Campbell <[email-masked]>
Date: Wed, 28 Mar 2018 21:22:50 +0000

Hi Jason,

In that case I would just use must "../a-list" - or optionally must "count(../a-list) > 0"; if you're concerned readers might not understand the former.

Regards,

  Alex

(Am I the only one who feels these signatures are silly?)

________________________________
From: Sterne, Jason (Nokia - CA/Ottawa) <[email-masked]>
Sent: Thursday, 29 March 2018 5:11 a.m.
To: Alex Campbell; [email-masked]
Subject: RE: YANG 'must' Xpaths, predicates and wildcards

Rgds,
Jason

Hi,

Hi all,

  container c1 {
    leaf foo {
      must "a-list";
      type uint16;
    }
    list a-list {
      key "entry";
      leaf entry {
        type uint16;
      }
      leaf another-entry {
        type uint32;
      }
    }
  }

Rgds,
Jason