Filtering with URN logic

The CitableBase package identifies three kinds of URN comparison: equality, containment and similarity. We want to be able to apply that logic to query our new ReadingList type. If your citable collection includes objects cited by Cite2Urn or CtsUrn, this is as simple as filtering the collection using their urnequals, urncontains or urnsimilar functions. Since we have defined a custom Isbn10Urn type, we'll need to implement those functions for our new URN type. We'll digress briefly with that implementation before turning to filtering our citable collection.

Note

For an introduction to defining URN types and implementing the UrnComparable trait, see the documentation for the CitableBase package

Digression: implementing URN comparison on Isbn10Urn

The CitableBase package provides a concrete implementation of urnequals, but we need to import and define functions for urncontains and urnsimilar

Containment

For our ISBN type, we'll define "containment" as true when two ISBNS belong to the same initial-digit group (0 - 4). We'll use the components functions from CitableBase to extract the third part of the URN string, and compare its first character.

import CitableBase: urncontains
function urncontains(u1::Isbn10Urn, u2::Isbn10Urn)
    initial1 = components(u1.isbn)[3][1]
    initial2 = components(u2.isbn)[3][1]

    initial1 == initial2
end
urncontains (generic function with 3 methods)

Both Distant Horizons and Enumerations are in ISBN group 0.

urncontains(distanthorizons, enumerations)
true

But Can We Be Wrong? is in ISBN group 1.

urncontains(distanthorizons, wrong)
false

Similarity

We'll define "similarity" as belonging to the same language area. In this definition, both 0 and 1 indicate English-language countries.

# True if ISBN starts with `0` or `1`
function english(urn::Isbn10Urn)
    langarea = components(urn.isbn)[3][1]
    langarea == '0' || langarea == '1'
end

import CitableBase: urnsimilar
function urnsimilar(u1::Isbn10Urn, u2::Isbn10Urn)
    initial1 = components(u1.isbn)[3][1]
    initial2 = components(u2.isbn)[3][1]

    (english(u1) && english(u2)) ||  initial1 == initial2
end
urnsimilar (generic function with 2 methods)

Both Distant Horizons and Can We Be Wrong? are published in English-language areas.

urnsimilar(distanthorizons, wrong)
true

Filtering a citable collection

Whether you use Cite2Urns, CtsUrns, or define your own URN type, as we did for ISBNs, filtering a collection of your content with URN logic is straightforward. All you need to do is define functions for urnequals, urncontains and urnsimilar that take a URN parameter to filter with (here, an Isbn10Urn), and a citable collection to filter (here, a ReadingList). If no objects match, we'll return nothing; otherwise, we'll return a list of content matching your URN.

function urnequals(isbn::Isbn10Urn, rlist::ReadingList)
    matches = filter(i -> i == isbn, rlist.reff)
    isempty(matches) ? nothing : matches
end

function urncontains(isbn::Isbn10Urn, rlist::ReadingList)
    matches = filter(i -> urncontains(i, isbn), rlist.reff)
    isempty(matches) ? nothing : matches
end

function urnsimilar(isbn::Isbn10Urn, rlist::ReadingList)
    matches = filter(i -> urnsimilar(i, isbn), rlist.reff)
    isempty(matches) ? nothing : matches
end
urnsimilar (generic function with 3 methods)
urnequals(jane, rl)
1-element Vector{Main.Isbn10Urn}:
 Main.Isbn10Urn("urn:isbn:0141395203")
group1 = Isbn10Urn("urn:isbn:1")
urncontains(group1, rl)
1-element Vector{Main.Isbn10Urn}:
 Main.Isbn10Urn("urn:isbn:1108922036")
urnsimilar(group1, rl)
5-element Vector{Main.Isbn10Urn}:
 Main.Isbn10Urn("urn:isbn:022661283X")
 Main.Isbn10Urn("urn:isbn:022656875X")
 Main.Isbn10Urn("urn:isbn:022656875X")
 Main.Isbn10Urn("urn:isbn:1108922036")
 Main.Isbn10Urn("urn:isbn:0141395203")