How to use a logical operator in WikiText to select a tiddler with one OR another tag? - tiddlywiki

The TiddlyWiki documentation provides an example of the tag operator:
[tag[task]]
This selects all tiddlers that have been tagged as task.
How though would one select all tiddlers tagged with one OR another tag; so for instance I want to select all tiddlers that are tagged either dog or cat? None of the below attempts succeed:
[tag[cat]||[dog]]
[tag[cat]OR[dog]]
[tag[cat, dog]]
For context, I'm looking to use this within a list, along the lines of:
<$list filter="[tag[cat]||[dog]]">
<$view field="title"/>
</$list>

A bit late but in case it's still useful...
There are various ways to combine the results of different lists, and in this case one just needs the simple union of lists which is represented with a space between two filter expressions:
<$list filter="[tag[cat]] [tag[dog]]">
<$view field="title"/>
</$list>
The document about filters is rich but a bit messy, I think that this is explained in "Introduction to filter notation" but there are other relevant parts in "Filter expression", also here and possibly in other places.

Related

how to select 2nd set of <ol> list with xpath

I'm trying to scrape the tips sections of these exercises but a lot of the pages are different resulting in a blank field.
The only thing they all have in common is that the tips are always in the 2nd oldered list. The 1st ordered list is the instructions. 2nd ordered list are the tips.
Here are some of the xpath that I have tried:
//ol (this selects both ordered lists)
//ol[2] (this doesn't work at all for some reason)
//h3[contains(text(),'​Exercise Tips:')]/following::ol (some of the pages it didn't pick up tips section)
//DIV[#class="field field-name-body field-type-text-with-summary field-label-hidden"]/DIV[1]/DIV[1]/OL[2] (again some of the pages it returned blank)
Link to the some of the exercises that the page are different:
https://www.muscleandstrength.com/exercises/one-arm-kettlebell-floor-press
https://www.muscleandstrength.com/exercises/overhead-tricep-extension.html
I would try //div[contains(#class, "exercise-tips")]//li/text().
Based on your example xpaths, you could use //div[contains(#class, "exercise-tips")]//ol if you truly want to select the ol element and not the text of the tips.
//ol[2] doesn't select any nodes because both ol nodes are the first ol child of their respective parents, not the second. (//ol)[2] does work, however. See https://stackoverflow.com/a/52166328/5225301 for more details.

Sort authors via last name in Tiddlywiki

It would be good to sort lists using an author's last name.
I have this code in one of the tiddlers, it lists all the tiddlers tagged 'author' and sorts alphabetically:
<$list filter='[tag[author]sort[title]]'>
</$list>
e.g.
Adam Robinson
Andrew Adonis
Benjamin Franklin
Dale Carnegie
Daniel Priestley
George Leonard
I would like the list to be sorted by last name, so it looks like this:
Adonis, Andrew
Carnegie, Dale
Franklin, Benjamin
Leonard, George
Priestley, Daniel
Robinson, Adam
Any ideas how to do this?
Easy option: Add a ByLastName field populated the way you want and sort on that.
Medium option: Introduce the notion of generated fields into tiddlywiki.
Hard option: Modify the sort filter to call a macro with whatever data you specify and then sort the original list based on the result.
In recent versions of TiddlyWiki, you can do this with the sortsub operator, which sorts based on the results of applying a filter expression to the inputs. Note that when you use this operator (or any other operator that takes a subfilter), you have to define the subfilter using a macro, or there's no way for TiddlyWiki to tell which square brackets are part of the main filter and which are part of the subfilter.
Here's a minimal working version:
\define myfilt() [split[ ]last[]]
<$list filter="[tag[author]sortsub<myfilt>]">
...
</$list>
To get the display to show up as "Lastname, Firstname", as in your example, rather than just showing the title of the tiddler as is:
\define myfilt() [split[ ]last[]]
<$list filter="[tag[author]sortsub<myfilt>]">
<$set name=formattedName value={{{ [all[current]split[ ]last[]addsuffix[, ]] [all[current]split[ ]butlast[]] +[join[]] }}}>
<$link to=<<currentTiddler>>><<formattedName>></$link><br>
</$set>
</$list>
We calculate the new format using a filter in {{{ triple curly braces }}} and assign it to a variable (note the use of butlast[] rather than first[] so that if someone has more than two names, the middle ones go on the end rather than disappearing). Then we create a link whose text is that new formatted version, and whose target is the original tiddler name.

Retrieve an xpath text contains using text()

I've been hacking away at this one for hours and I just can't figure it out. Using XPath to find text values is tricky and this problem has too many moving parts.
I have a webpage with a large table and a section in this table contains a list of users (assignees) that are assigned to a particular unit. There is nearly always multiple users assigned to a unit and I need to make sure a particular user is assigned to any of the units on the table. I've used XPath for nearly all of my selectors and I'm half way there on this one. I just can't seem to figure out how to use contains with text() in this context.
Here's what I have so far:
//td[#id='unit']/span [text()='asdfasdfasdfasdfasdf (Primary); asdfasdfasdfasdfasdf, asdfasdfasdfasdf; 456, 3456'; testuser]
The XPath Query above captures all text in the particular section I am looking at, which is great. However, I only need to know if testuser is in that section.
text() gets you a set of text nodes. I tend to use it more in a context of //span//text() or something.
If you are trying to check if the text inside an element contains something you should use contains on the element rather than the result of text() like this:
span[contains(., 'testuser')]
XPath is pretty good with context. If you know exactly what text a node should have you can do:
span[.='full text in this span']
But if you want to do something like regular expressions (using exslt for example) you'll need to use the string() function:
span[regexp:test(string(.), 'testuser')]

xpath return all non-blank text nodes not descendant of `a`, `style` or `script`

What expression would select all text nodes which are:
not blank
not inside a, or script or style?
Use:
//*[not(self::a or self::script or self::style)]/text()[normalize-space()]
Not only is this expression shorter than the one in the currently accepted answer, but it also may be much more efficient.
Do note that the expression doesnt use any (back/up)-ward axes at all.
This should do, assuming "not inside" means the text node is not supposed to be a descendant of an "a" or "script" or "style" element. If "not inside" only means not supposed to be a child then use parent::a and so on instead of ancestor::a.
//text()[normalize-space() and not(ancestor::a | ancestor::script | ancestor::style)]
I used Dimitre Novatchev's answer, but then i stumbled upon the problem described by the topic starter:
not descendant of a, style or script
Dimitre's answer excludes style tag but includes its children.
This version excludes also style, script, noscript tags and their descendants:
//div[#id='???']//*[not(ancestor-or-self::script or ancestor-or-self::noscript or ancestor-or-self::style)]/text()
Anyway, thanks to Dimitre Novatchev.

using xpath to obtain complex values

Given the following, I'd like to extract VarVal1, VarVa5 and VarText where FixedVals are, well, fixed :)
<TypeA Attr1="VarVal1">
<TypeB Attr2="FixedVal2">
<TypeC Attr3="FixedVal3">
<TypeD Attr4="FixedVal4" Attr5="VarVal5">
VarText
</TypeD>
</TypeC>
</TypeB>
</TypeA>
Notice that the big problem for me is that the context is important. I want the complete pattern. There may be other TypeA nodes, but I'm not interested in their values unless they're followed by
<TypeB Attr2="FixedVal2">
<TypeC Attr3="FixedVal3">
<TypeD Attr4="FixedVal4" Attr5="VarVal5">
VarText
</TypeD>
</TypeC>
</TypeB>
In other words, what I'm interested in is a set of tripletts, each of them in the form of (VarVal1, VarVal5, VarText)
These XPath expressions:
//TypeA
[TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]]
/#Attr1
Then those already posted:
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]
/#Attr5
And
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]
You could also combine them with | union set operator. But depending on the host language, you should better select the TypeA elements you want (first expression with out last /#Attr1 part) and then query each of those to extract the remaining values.
I think you need a couple of queries for this (could be wrong though)
for VarVal1
//TypeA/#Attr1
for VarVal5
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]
/#Attr5
Think these should do the trick
EDIT - missed VarText!
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]

Resources