Yesterday, musing about traversing my social graph through blogrolls, I suggested using OPML’s include attribute as a way of adding the blogrolls of the blogs I follow in my own blogroll. Ideally using a spec compliant OPML reader, you’d be able to seamlessly navigate from my blogroll, through the blogroll of one of the blogs I follow, to the blogroll of someone they follow, and presumably back to me at some point.
It does require having an OPML version of such blogrolls available. Peter publishes his blogroll as OPML as I do, allowing a first simple experiment: do includes get correctly parsed in some of the Outliner tools I have?

Adding an include into my OPML file

This little experiment starts with adding to my list of RSS feeds I follow a reference to Peter’s own OPML file of feeds he follows. I already follow two of Peter’s RSS feeds (blogposts and favourites) which I now placed in their own subfolder and to which I added an outline node of the include type, with the URL of Peter’s OPML file.


Screenshot of my OPML file listing the RSS feeds I follow. Click to enlarge. On line 22 you see the line that includes Peter’s OPML file by mentioning its URL.

Trying three outliners

Cloud Outliner (which I in the past used to first create outlines that could then be sent to Evernote) does not parse OPML includes correctly upon import. It also doesn’t maintain any additional attributes from OPML outline nodes, just the text attribute.


Screenshot of Cloud Outliner showing incorrect import of my OPML file. Click to enlarge.

Tinderbox like Cloud Outliner fails to load OPML includes as per spec. It does load some of the attributes (web url, and description, next to the standard text attribute), but not any others (such as the feed url for instance, the crucial element in a list of RSS feeds). It looks like it only picks up on attributes that are directly mappable on pre-existing default attributes within Tinderbox itself.


Screenshot of how Tinderbox imports my OPML file. It keeps some attributes but ignores most, and for includes just mentions the URL

Electric Drummer does correctly import the entire OPML outline. As Dave Winer is both the original creator of the OPML specification and more recently of the Electric Drummer app, this is consistent. Electric Drummer picks up on all attributes in an imported OPML file. Upon import it also fetches the external OPML files listed as includes from their URLs, and fully incorporates them into the imported outline.


Screenshot of Drummer, which incorporates the content of Peter’s OPML file I linked to in my OPML file. Click to enlarge.

Opening up options for tinkering

So at least there is 1 general outliner tool that can work with includes. It probably also means that Dave’s OPML package can do the same, which allows me to tinker at script level with this. One candidate for tinkering is, where a blogger has a blogroll, just not in OPML, to use the OPML package to convert scraped HTML to OPML, and include it locally. That allows me to traverse sets of blogrolls and see the overlap, closed triangles, feedback loops etc. I could also extend my own published blogroll by referencing all the published blogrolls of the bloggers I follow. For you my blogroll would then support exploration and discovery one step further outwards in the network. In parallel I can do something similar for federated bookshelves (both in terms of books as in terms of lists of people who’s booklists and their lists of people you follow)

Bookmarked Interoperable Personal Libraries and Ad Hoc Reading Groups by Maggie Appleton

I somehow missed Maggie Appleton’s blogpost (bookmarked above) about the IndieWeb pop-up session on personal libraries of a few weeks ago. During the session I found her suggestion for ad-hoc reading clubs very interesting, as an application of having book lists on your site. I first and foremost think about discovery in the context of publishing book lists: if I enjoy your blog, or know you and you share book lists those may contain good suggestions to read. Discovery is also why in my ‘data format‘ for such lists I allow for sharing the URLs of lists of others, as well as share the URL of where I found the recommendation for a specific book. What Maggie Appleton suggests is something else and interesting: what if you could see when several others in your network are also currently reading the same book you are reading, allowing an ad-hoc book reading club for that book. It would require a way to compare lists you follow. My sharing of lists I follow is a useful start for it I think, but you’d add a match detection layer on top of it. Whether that matching needs to take place in my site, I don’t know. To me it feels like a personal tool perhaps, alerting me to other readers, and allowing me to privately think about whether I’d want to form an ad-hoc book club with them at that time.

An idea I brought to the event and ended up hosting a session on was ad hoc reading groups – discussions and meetups facilitated by our public bookshelves.

Maggie Appleton

Having created a working flow to generate OPML booklists directly from the individual book notes in my PKM system, I did the first actual run in production of those scripts today.

It took a few steps to get to using the scripts in production.

  • I have over 300 book note files in my Obsidian vault.
  • Of course most lacked the templated inline data fields that allow me to create lists. For the 67 fiction books I read in 2021 I already had a manual list with links to the individual files. Where needed I added the templated data fields.
  • Having added those inline fields where they were missing I can easily build lists in Obsidian with the Dataview plugin. Using this code


    results in

  • The same inline data fields are used by my scripts to read the individual files and build the same list in OPML
  • That gets automatically posted to my website where the file is both machine and human readable.

Doing this in production made me discover a small typo in the script that builds the OPML, now fixed (also in the GitHub repository). It also made me realise I want to add a way of ordering the OPML outline entries by month read.

Lists to take into production next are those for currently reading (done), non-fiction 2021, and the anti-library. That last one will be the most work, I have a very long list of books to potentially read. I will approach that not as a task of building the list, but as an ongoing effort of evaluating books I have and why they are potentially of interest to me. A way, in short, to extend my learning, with the list as a useful side effect. The one for currently reading is the least work, and from it the lists for fiction 2022 and non-fiction 2022 will automatically follow. The work is in the backlog, getting history to conform to the convention I came up with, not in moving forward from this point.

In parallel it is great to see that Tom Critchlow is also looking at creating such book lists, in JSON, and at digesting such lists from others. The latter would implement the ‘federated’ part of federated bookshelves. Right now I just point to other people’s list and rss feeds in my ‘list of lists‘. To me getting to federation doesn’t require a ‘standard’. Because JSON, OPML and e.g. schema.org have enough specificity and overlap between them to allow both publishers of lists and parsers or such lists enough freedom to use or discard data fields as they see fit. But there is definitely a discussion to be had on identifying that overlap and how to use it best. Chris Aldrich is planning an IndieWeb event on this and other personal libraries related topics next month. I look forward to participating in that, quite a number of interesting people have expressed interest, and I hope we’ll get to not just talk but also experiment with book lists.

As a form of WAB* I’ve made it easier for myself to update my OPML book lists. I created those lists earlier this year as a proof of concept of publishing federated bookshelves. Updating OPML files residing on my hosted webserver is not a fun manual task. Ultimately I want to automate pushing lists from my personal working environment (notes in Obsidian) to my site. Given my limited coding skills I made a first easier step and created a webform in a php script that allows me to add a book to an opml list. It has a drop-down menu for the various OPML lists I keep (e.g. fiction2021, non-fiction2021, currently reading, anti-library), provides the right fields to add the right OPML data attributes, and then writes them to the correct list (each list is a separate file).

That now works well. Having a way to post to my book lists by submitting a form now, I can take the next step of generating such form submissions to replace manually filling out the form.

* Work Avoiding Behaviour, a continuation of the SAB, Study Avoiding Behaviour that I excelled in at university. WAB seems to fit very well with the current locked down last days until the end of year. The Dutch terms ‘studie/werk ontwijkend gedrag’ SOG/WOG lend themselves to the verb to ‘sog’ and to ‘wog’. Yesterday when Y asked E what she had been doing today, E said ‘I’ve been wogging’, and I realised I had been too.

TIL: In an xml style sheet, an xslt file, testing for the existence of an attribute is not the same as testing whether an attribute has content.

I have a machine readable file (OPML) with lines such as

<outline type="book" text="title by author" name="book title" author="author name" url="" comment="some remarks" authorurl="" inLanguage="en" />

I want to show that file in a browser for people to see, and I want to test for the attribute url in that line so that I can mark up the text with a web link in the human readable version.

What I first used to test for the presence of a link was:

<xsl:when test="@url">

I assumed this would test for the actual presence of a value for attribute ‘url’. But that is not correct. The statement actually tests whether the attribute ‘url’ is present in the line of machine readable code.

To test if the url attribute also has content in it, e.g. url=”https://weblink.tld/page” and not url=”” I need to check that the field is not empty:

<xsl:when test="@url!=''">

I experimentally create OPML lists of books I read (see why and how). For instance I have a ‘fiction 2021’ list. OPML files are meant to be read by machines, but I use the same file to make a human readable version. In the human readable version I want to link to a book and to an author if I have a direct link to a page about the book (by the publisher or author) and a link to the author’s website. I test for non-empty url attributes so I know when to construct a link in the human readable output. You can download the XSLT I use to do that and of course the OPML file that lists the fiction books for 2021 (also see right hand side column, in the feeds section).

When I wrote about outlining last weekend, I mentioned Dave Winer’s blog being an outline document. Yesterday, in the context of Drummer he referred to a 2013 posting “Two ways of looking at an outliner“. In it he goes into detail how outliners aren’t only creating files (a single outline, saved in a file), but can be viewed as file systems as well. At the end of that posting he talks about how his entire blog is an outline, all stored in a single opml file. When I mentioned how Dave Winer seems to blog by starting an outline each day, I was partly right. He’s starting a new branch (i.e. a day file) in a month branch (i.e. a folder), in a year branch (i.e. a folder), in the entirety of his blog that is a single OPML file.