Using links() with item|group value of $Prototype="x"

Note A (source) is linked to Note B (destination). Note B has a prototype of “Reference”.

I would like to create a Rule for Note A, that checks if Note B has a prototype of ‘Reference’, and if so then populates a User-defined attribute of $citation (instead of Rule which checks for link type citation) for Note A with the $Name of Note B.

Is this possible? I have tried the following two rules, but they return nothing.

$citation=links($Prototype="Reference").outbound..$Name;
$citation=links($Prototype(destination)="Reference").outbound..$Name;

I thought this should be possible, because according to this TB Ref page, the item|group argument may be an unquoted attribute holding an appropriate string value.

I think you’re referring to these examples in the linked article:

links(find(descendedFrom("Some note")).inbound.my_link.$SomeAttribute 
links(find(descendedFrom("Some note")&$MyDate==$StartDate).outbound..$Width 
links($MySet).outbound.example.$Name 
links($MyList).inbound.note.$WordCount 

Note that in the first two, they use a query within find(). The query terms are essentially true/false tests. It is the find that returns a list of paths which are a valid group input to links().

That said I think you may also be confusing scope. For each $Rule you want—for this note—to report the $Name of all notes that are linked to from this note. But you also want to add a query into defining the group of linked-to notes. Your code above, even if it returned what you expect would make each notes’s rule apply to the group of all notes for all sources which is not what you want. So, you’re not misunderstanding the notes on links() but rather you’re trying to do something for which links() wasn’t designed. The only filter as to which linked notes are sampled is an optional filter on link type(s)

A more useful approach here is to use collect() with a find()-based query. In pseudo-code terms:

$citation = collect(find(_query_),$Name);

where the _query_ is something like

$Prototype="Reference" the tested note has $Prototype value set to “Reference”
& => AND
linkedFrom(that) => is the currently tested note linked to by the note calling the find

The query now tests every note in the document. First returns the path of those with right prototype setting; it then further filters that list retaining those with a link inbound from the calling note (i.e. the note running the find).

Now to test that…

Yes, this seems to find your desired data:

$MyList=collect(find($Prototype=="Reference"&linkedFrom(that)),$Name);

In my test, the rule was run in note ‘aa’. There are three notes with the ‘Reference’ prototype (bb, cc, dd) but only _two (bb, dd) are also linked from ‘aa’. In the code, for a rule running in ‘aa’ the ‘that’ designator refers to ‘aa’.

Note how the testing for links is reversed within the query. Although we want to test fro those notes linked to from the current note, within the query we’re testing other notes and so have to test for an inbound link, thus use of linkedFrom where you might have assumed linkedTo(0 would be appropriate.

This worked perfectly. And thank you for the explanation, Mark. I now understand the mechanisms a bit better.

$MyList=collect(find($Prototype==“Reference”&linkedFrom(that)),$Name); This does not seem to work in version 9.5.2, if you have 2 $Prototype==“Reference” in the note :frowning:

Why would you have two same-named prototypes? Can you explain your scenario a bit better? “This does not seem to work” doesn’t give us much to go on. Could you perhaps post a small test document showing the problem and including a note describing whay you expected vs what you got?

Dear Mark,
Thank you for your reply. Please see attachment and see note called “trm- Ferric Derisomaltose”. Let’s say I wanted to add another reference in the note, I’d like both references to appear in the Citation attribute, separated by a semicolon. It used to do so in Version 9.3.0. Thank you. Much appreciated.
2023-05-16 Test.tbx (210.2 KB)

$Citations=collect(
     find($Prototype=="p_reference"&linkedFrom(that)),
     $ReferenceShortTitle);

The note trm- Ferric Derisomaltose has one outbound link, to @EMC2023IVIron. So, we expect $Citations to collect the $ReferenceShortTitle of that note. But @ EMC2023IVIron has no $ReferenceShortTitle, so $Citations remains empty.

Ah, confusion re prototype resolved. Doc most useful.

Further to @Eeastgate’s point, $Citations likely should be a Set and not a List (you don’t want a term to list a reference more than one. But there seems to be an issue with collect().This ought to get the linked reference’s $Name, but doesn’t:

$Citations=collect(find($Prototype=="p_reference"&linkedFrom(that)),$Name);

Late here, but having verified the find()z generates the expected path, collect() definitely ought to be able to ‘collect’ the $Name of the note at that path. Odd.

Typo here: the second argument of collect is the attribute name. What you want is:

$Citations=collect(find($Prototype=="p_reference"&linkedFrom(that)),"Name");

Good morning. Thank you both. @eastgate. I have tried with “Name”, it still doesn’t work. Please find attached version 2, with $ReferenceShortTitle added. Both Citations appear when using TBX version 9.3.0, but not in the latest version (9.5.2). Thank you for your help. Much appreciated.
2023-05-16 Test V2.tbx (209.0 KB)

The @ you’re putting into your reference names may be causing troubles for the parser. If you really want that, I think it’s better to append it in the $DisplayNameExpression and leave the name alone.

More later.

Turns out, it’s not the @ in the reference but rather the v9.5.0 fix to make collect() use find() properly (qv RNs for b605) appears broken again in v9.5.2. . Last night I had a hunch the collect()+find() might be the issue but it took some close tear-down today to state that with confidence. Anyway, the revision below works, so you don’t now need to worry about the cause.

For now the fix, for @dissander is this:

  • Amend you p_term rule code to this
$Citations=collect(find($Prototype=="p_reference"&linkedFrom(that)),$ReferenceShortTitle);
var:list vList1;
var:list vList2;
vList1 = find($Prototype=="p_reference"&linkedFrom(that));
vList1.each(anItem){
  vList2+=$ReferenceShortTitle(anItem);
};
$Citations = vList2;
  • Once the find-with-collect is fixed you can delete the new code and uncomment the old.
  • The ‘Resources’ OnAdd set a prototype of ‘p_folder’ but it doesn’t exist.
  • The ‘References’ container OnAdd has a stray closing parenthesis ) (which syntax highlighting picks up.

Here is your file with those fixes, including reverting the @ prefixes to reference notes which proved to not be the case.

TBX: 2023-05-16 Test V2-ed.tbx (311.1 KB)

OK: next backstage release will resolve this.

1 Like

Thank you Mark. It worked like a charm.
Much appreciated.

1 Like

Jolly good.
Thank you.

1 Like