@@ -5,9 +5,9 @@ use time::macros::format_description;
5
5
6
6
use crate :: {
7
7
bibliography:: {
8
- Bibliography , Book , Chapter , Common , ConferencePaper , Date , Document , JournalArticle ,
9
- LString , MagazineArticle , NewspaperArticle , NumberOrString , Pagination , Periodical , Person ,
10
- Reference , Thesis , WebPage ,
8
+ identifier_info , Bibliography , Book , Chapter , Common , ConferencePaper , Date , Document ,
9
+ JournalArticle , LString , MagazineArticle , NewspaperArticle , NumberOrString , Pagination ,
10
+ Periodical , Person , Reference , Thesis , WebPage ,
11
11
} ,
12
12
intl:: INTL ,
13
13
nvec:: OneOrMore ,
@@ -27,8 +27,26 @@ pub type InlineCiteRenderer = Box<dyn Fn(&str, Option<Markup>) -> Markup + Send
27
27
28
28
pub type RenderedBibliography = BTreeMap < String , RenderedEntry > ;
29
29
30
+ fn backfill_isbn ( reference : & Reference ) -> Cow < ' _ , Reference > {
31
+ match reference {
32
+ Reference :: Book ( Book {
33
+ isbn : Some ( isbn) , ..
34
+ } ) => {
35
+ let mut result = reference. clone ( ) ;
36
+ result
37
+ . common_mut ( )
38
+ . identifiers
39
+ . insert ( format ! ( "isbn:{}" , isbn. 0 ) ) ;
40
+ return Cow :: Owned ( result) ;
41
+ }
42
+ _ => { }
43
+ }
44
+
45
+ Cow :: Borrowed ( reference)
46
+ }
47
+
30
48
fn backfill_doi ( reference : & Reference ) -> Cow < ' _ , Reference > {
31
- if reference. doi ( ) . is_none ( ) {
49
+ if reference. identifier ( "doi:" ) . is_none ( ) {
32
50
if let Some ( url) = reference. common ( ) . url . as_deref ( ) {
33
51
if let Some ( doi) = url. strip_prefix ( "https://doi.org/" ) {
34
52
let mut r = reference. clone ( ) ;
@@ -42,7 +60,7 @@ fn backfill_doi(reference: &Reference) -> Cow<'_, Reference> {
42
60
}
43
61
44
62
fn backfill_handle ( reference : & Reference ) -> Cow < ' _ , Reference > {
45
- if reference. hdl ( ) . is_none ( ) {
63
+ if reference. identifier ( "hdl:" ) . is_none ( ) {
46
64
if let Some ( url) = reference. common ( ) . url . as_deref ( ) {
47
65
if let Some ( hdl) = url. strip_prefix ( "https://hdl.handle.net/" ) {
48
66
// n2t doesn't handle handles with query strings
@@ -84,6 +102,7 @@ pub fn to_rendered(bib: &Bibliography) -> RenderedBibliography {
84
102
. unwrap_or_default ( ) ;
85
103
86
104
let reference = backfill_doi ( reference) ;
105
+ let reference = backfill_isbn ( & reference) ;
87
106
let reference = backfill_handle ( & reference) ;
88
107
let reference = render_ref ( key, & reference) ;
89
108
@@ -166,40 +185,46 @@ fn inline_cite(reference: &Reference) -> Option<InlineCiteRenderer> {
166
185
167
186
fn book_item_type ( book : & Book ) -> & ' static str {
168
187
if book. volume . is_none ( ) {
169
- "Book bibo:Book"
188
+ "Book bibo:Book fabio:Book "
170
189
} else {
171
- "Book bibo:Book PublicationVolume"
172
- }
173
- }
174
-
175
- fn thesis_item_type ( thesis : & Thesis ) -> & ' static str {
176
- if thesis. volume . is_none ( ) {
177
- "Thesis bibo:Thesis"
178
- } else {
179
- "Thesis bibo:Thesis PublicationVolume"
190
+ "Book PublicationVolume bibo:Book fabio:Book"
180
191
}
181
192
}
182
193
183
194
fn item_type ( reference : & Reference ) -> & ' static str {
184
195
match reference {
185
196
Reference :: ConferencePaper ( _) => "ScholarlyArticle bibo:AcademicArticle" ,
186
197
Reference :: JournalArticle ( _) => "ScholarlyArticle bibo:AcademicArticle" ,
187
- Reference :: NewspaperArticle ( _) | Reference :: MagazineArticle ( _) => "Article" ,
188
- Reference :: Book ( b) => book_item_type ( b) ,
189
- Reference :: Thesis ( t) => thesis_item_type ( t) ,
190
- Reference :: Chapter ( _) => "Chapter bibo:Chapter" ,
191
- Reference :: Patent ( _) => "CreativeWork bibo:Patent" ,
192
- Reference :: Document ( _) => "CreativeWork bibo:Document" ,
193
- Reference :: WebPage ( _) => "WebPage bibo:Webpage" ,
198
+ Reference :: NewspaperArticle ( _) => "Article bibo:Article fabio:NewspaperArticle" ,
199
+ Reference :: MagazineArticle ( _) => "Article bibo:Article fabio:MagazineArticle" ,
200
+ Reference :: Book ( b) => {
201
+ if b. volume . is_none ( ) {
202
+ "Book bibo:Book fabio:Book"
203
+ } else {
204
+ "Book PublicationVolume bibo:Book fabio:Book"
205
+ }
206
+ }
207
+ Reference :: Thesis ( t) => {
208
+ if t. volume . is_none ( ) {
209
+ "Thesis bibo:Thesis fabio:Thesis"
210
+ } else {
211
+ "Thesis PublicationVolume bibo:Thesis fabio:Thesis"
212
+ }
213
+ }
214
+ Reference :: Chapter ( _) => "Chapter bibo:Chapter fabio:BookChapter" ,
215
+ Reference :: Patent ( p) => {
216
+ if p. issued . is_some ( ) {
217
+ "CreativeWork bibo:Patent fabio:Patent"
218
+ } else {
219
+ "CreativeWork bibo:Patent fabio:PatentApplication"
220
+ }
221
+ }
222
+ Reference :: Document ( _) => "CreativeWork bibo:Document fabio:Work" ,
223
+ Reference :: WebPage ( _) => "WebPage bibo:Webpage fabio:WebPage" ,
194
224
}
195
225
}
196
226
197
227
fn item_resource ( reference : & Reference ) -> Option < String > {
198
- if let Some ( doi) = reference. doi ( ) {
199
- // DOI can be treated as a URN, since it is registered
200
- return Some ( format ! ( "urn:{doi}" ) ) ;
201
- }
202
-
203
228
match reference {
204
229
// Reference books with ISBNs via URN
205
230
Reference :: Book ( Book {
@@ -235,9 +260,8 @@ fn render_ref(key: &str, reference: &Reference) -> Markup {
235
260
( render_container( key, reference) )
236
261
( render_genre( reference) )
237
262
( render_publisher( key, reference) )
238
- ( render_isbn( reference) )
239
- ( render_original( reference) )
240
263
( render_identifiers( reference) )
264
+ ( render_original( reference) )
241
265
}
242
266
}
243
267
}
@@ -539,7 +563,7 @@ fn render_date(reference: &Reference) -> Markup {
539
563
abbr title="circa" { "c." }
540
564
" "
541
565
}
542
- ( date. year( ) . to_string( ) )
566
+ span property= "fabio:hasPublicationYear" { ( date. year( ) . to_string( ) ) }
543
567
@if date. attr( ) . old_style {
544
568
" ["
545
569
abbr title="old-style" { "OS" }
@@ -670,8 +694,8 @@ fn render_series(r: &Reference) -> Markup {
670
694
671
695
html ! {
672
696
"; "
673
- span property="isPartOf" typeof="BookSeries" {
674
- @let title = render_lstr( & series. title, None , Some ( "name" ) , Some ( "alternateName" ) ) ;
697
+ span property="isPartOf dcterms:isPartOf frbr:partOf " typeof="BookSeries bibo:Series fabio: BookSeries" {
698
+ @let title = render_lstr( & series. title, None , Some ( "name dcterms:title " ) , Some ( "alternateName" ) ) ;
675
699
@if let Some ( url) = & series. url {
676
700
a property="url" href=( url) { ( title) }
677
701
} @else {
@@ -681,7 +705,7 @@ fn render_series(r: &Reference) -> Markup {
681
705
" ("
682
706
abbr. initialism { "ISSN" }
683
707
" "
684
- span property="issn" { ( issn. to_string( false ) ) }
708
+ span property="issn bibo:issn " { ( issn. to_string( false ) ) }
685
709
")"
686
710
}
687
711
@if let Some ( volume) = & series. volume {
@@ -736,8 +760,16 @@ fn render_container(key: &str, r: &Reference) -> Markup {
736
760
| Reference :: MagazineArticle ( MagazineArticle {
737
761
page, periodical, ..
738
762
} ) => {
763
+ let pt = if matches ! ( r, Reference :: JournalArticle ( _) ) {
764
+ PeriodicalType :: Journal
765
+ } else if matches ! ( r, Reference :: NewspaperArticle ( _) ) {
766
+ PeriodicalType :: NewsPaper
767
+ } else {
768
+ PeriodicalType :: Magazine
769
+ } ;
770
+
739
771
html ! {
740
- ( render_periodical( key, periodical) )
772
+ ( render_periodical( key, periodical, pt ) )
741
773
@if let Some ( page) = page {
742
774
@if matches!( page, Pagination :: Num ( _) ) {
743
775
": page "
@@ -789,7 +821,7 @@ fn render_container(key: &str, r: &Reference) -> Markup {
789
821
} ) => html ! {
790
822
@if let Some ( title) = container_title {
791
823
"On the website "
792
- span property="isPartOf dcterms:isPartOf" typeof="WebSite bibo:Website" {
824
+ span property="isPartOf dcterms:isPartOf frbr:partOf " typeof="WebSite bibo:Website fabio:WebSite " {
793
825
( render_lstr_cite( title, None , Some ( "name dcterms:title" ) , Some ( "alternateName" ) ) )
794
826
}
795
827
@@ -801,7 +833,7 @@ fn render_container(key: &str, r: &Reference) -> Markup {
801
833
@let iso_date = access_date. format( format_description!( "[year]-[month]-[day]" ) ) . unwrap( ) ;
802
834
@let nice_date = format!( "{}, {} {} {}" , access_date. weekday( ) , ordinal( access_date. day( ) as u64 ) , access_date. month( ) , access_date. year( ) ) ;
803
835
" (accessed "
804
- time property="lastReviewed" datetime=( iso_date) { ( nice_date) }
836
+ time property="lastReviewed fabio:hasDepositDate " datetime=( iso_date) { ( nice_date) }
805
837
")"
806
838
}
807
839
@@ -820,7 +852,7 @@ fn render_book(key: &str, book: &Book, item_prop: &str) -> Markup {
820
852
let bookr = & Reference :: Book ( book. clone ( ) ) ;
821
853
let key = key. to_string ( ) + "-book" ;
822
854
html ! {
823
- span property=( item_prop) typeof=( book_item_type( book) ) {
855
+ span property=( item_prop) typeof=( book_item_type( book) ) resource= [ bookr . common ( ) . resource_id ( ) ] {
824
856
( render_title( bookr) )
825
857
@if let Ok ( authors) = bookr. authors( ) . try_into( ) {
826
858
", " ( render_people( & authors, false , "author" ) )
@@ -836,7 +868,13 @@ fn render_book(key: &str, book: &Book, item_prop: &str) -> Markup {
836
868
}
837
869
}
838
870
839
- fn render_periodical ( key : & str , p : & Periodical ) -> Markup {
871
+ enum PeriodicalType {
872
+ Journal ,
873
+ NewsPaper ,
874
+ Magazine ,
875
+ }
876
+
877
+ fn render_periodical ( key : & str , p : & Periodical , pt : PeriodicalType ) -> Markup {
840
878
let date_part = if matches ! ( p. issued, Date :: YearMonthDay { .. } | Date :: YearMonth { .. } ) {
841
879
html ! {
842
880
", "
@@ -848,56 +886,82 @@ fn render_periodical(key: &str, p: &Periodical) -> Markup {
848
886
Markup :: default ( )
849
887
} ;
850
888
889
+ let periodical_resource = if let Some ( issn) = & p. issn {
890
+ format ! ( "urn:issn:{}" , issn. to_string( false ) )
891
+ } else {
892
+ format ! ( "#{key}-periodical" )
893
+ } ;
894
+
895
+ let periodical_type = match pt {
896
+ PeriodicalType :: Journal => "Periodical bibo:Journal fabio:Journal" ,
897
+ PeriodicalType :: NewsPaper => "Periodical bibo:Newspaper fabio:Newspaper" ,
898
+ PeriodicalType :: Magazine => "Periodical bibo:Magazine fabio:Magazine" ,
899
+ } ;
900
+
901
+ let volume_type = match pt {
902
+ PeriodicalType :: Journal => "PublicationVolume bibo:CollectedDocument fabio:JournalVolume" ,
903
+ PeriodicalType :: NewsPaper => {
904
+ "PublicationVolume bibo:CollectedDocument fabio:NewspaperVolume"
905
+ }
906
+ PeriodicalType :: Magazine => "PublicationVolume bibo:CollectedDocument fabio:MagazineVolume" ,
907
+ } ;
908
+
909
+ let issue_type = match pt {
910
+ PeriodicalType :: Journal => "PublicationIssue bibo:Issue fabio:JournalIssue" ,
911
+ PeriodicalType :: NewsPaper => "PublicationIssue bibo:Issue fabio:NewspaperIssue" ,
912
+ PeriodicalType :: Magazine => "PublicationIssue bibo:Issue fabio:MagazineIssue" ,
913
+ } ;
914
+
851
915
html ! {
852
916
@match ( p. issue, & p. volume) {
853
917
( Some ( issue) , Some ( volume) ) => {
854
- span typeof="Periodical" resource={ "#" ( key ) "-periodical" } {
855
- link property="publisher" href={ "#" ( key) "-publisher" } ;
918
+ span typeof=( periodical_type ) resource=( periodical_resource ) {
919
+ link property="publisher dc:publisher " href={ "#" ( key) "-publisher" } ;
856
920
( render_lstr_cite( & p. title, None , Some ( "name" ) , Some ( "alternateName" ) ) )
857
921
}
858
922
" "
859
- span typeof="PublicationVolume" resource={ "#" ( key) "-volume" } {
860
- link property="isPartOf" href={ "#" ( key ) "-periodical" } ;
923
+ span typeof=( volume_type ) resource={ "#" ( key) "-volume" } {
924
+ link property="isPartOf frbr:partOf " href=( periodical_resource ) ;
861
925
abbr title="volume" { "vol." }
862
926
" "
863
- span property="volumeNumber" { ( volume. to_string( true ) ) }
927
+ span property="volumeNumber bibo:volume " { ( volume. to_string( true ) ) }
864
928
}
865
929
" "
866
- span typeof="PublicationIssue" property="isPartOf" {
867
- link property="isPartOf" href={ "#" ( key) "-volume" } ;
868
- "(" span property="issueNumber" { ( INTL . format_number( issue) ) } ")"
930
+ span typeof=( issue_type ) property="isPartOf frbr:partOf " {
931
+ link property="isPartOf frbr:partOf " href={ "#" ( key) "-volume" } ;
932
+ "(" span property="issueNumber bibo:issue " { ( INTL . format_number( issue) ) } ")"
869
933
( date_part)
870
934
}
871
935
}
872
936
( Some ( issue) , None ) => {
873
- span typeof="Periodical" resource={ "#" ( key ) "-periodical" } {
874
- link property="publisher" href={ "#" ( key) "-publisher" } ;
937
+ span typeof=( periodical_type ) resource=( periodical_resource ) {
938
+ link property="publisher dc:publisher " href={ "#" ( key) "-publisher" } ;
875
939
( render_lstr_cite( & p. title, None , Some ( "name" ) , Some ( "alternateName" ) ) )
876
940
}
877
941
" "
878
- span typeof="PublicationIssue" property="isPartOf" {
879
- link property="isPartOf" href={ "#" ( key ) "-periodical" } ;
880
- "(" span property="issueNumber" { ( INTL . format_number( issue) ) } ")"
942
+ span typeof=( issue_type ) property="isPartOf frbr:partOf " {
943
+ link property="isPartOf frbr:partOf " href=( periodical_resource ) ;
944
+ "(" span property="issueNumber bibo:issue " { ( INTL . format_number( issue) ) } ")"
881
945
( date_part)
882
946
}
883
947
}
884
948
( None , Some ( volume) ) => {
885
- span typeof="Periodical" resource={ "#" ( key ) "-periodical" } {
886
- link property="publisher" href={ "#" ( key) "-publisher" } ;
949
+ span typeof=( periodical_type ) resource=( periodical_resource ) {
950
+ link property="publisher dc:publisher " href={ "#" ( key) "-publisher" } ;
887
951
( render_lstr_cite( & p. title, None , Some ( "name" ) , Some ( "alternateName" ) ) )
888
952
}
889
953
" "
890
- span typeof="PublicationVolume" property="isPartOf" {
891
- link property="isPartOf" href={ "#" ( key ) "-periodical" } ;
954
+ span typeof=( volume_type ) property="isPartOf frbr:partOf " {
955
+ link property="isPartOf" href=( periodical_resource ) ;
892
956
abbr title="volume" { "vol." }
893
957
" "
894
- span property="volumeNumber" { ( volume. to_string( true ) ) }
958
+ span property="volumeNumber bibo:volume " { ( volume. to_string( true ) ) }
895
959
( date_part)
896
960
}
897
961
}
898
962
( None , None ) => {
899
- span typeof="Periodical" property="isPartOf" {
900
- link property="publisher" href={ "#" ( key) "-publisher" } ;
963
+ span typeof=( periodical_type ) resource= ( periodical_resource ) property="isPartOf frbr:partOf " {
964
+ link property="publisher dc:publisher " href={ "#" ( key) "-publisher" } ;
901
965
( render_lstr_cite( & p. title, None , Some ( "name" ) , Some ( "alternateName" ) ) )
902
966
( date_part)
903
967
}
@@ -1019,10 +1083,19 @@ fn render_isbn(r: &Reference) -> Markup {
1019
1083
fn render_identifiers ( r : & Reference ) -> Markup {
1020
1084
html ! {
1021
1085
@for id in & r. common( ) . identifiers {
1086
+ @let info = identifier_info( id) ;
1022
1087
" "
1023
- span. id {
1024
- a property="sameAs" href={ "https://n2t.net/" ( id) } {
1025
- span property="dcterms:identifier" { ( id) }
1088
+ @if info. digital {
1089
+ span. id {
1090
+ a property="sameAs" href=( info. url) {
1091
+ span property=( info. property) { ( info. presentation_form. as_deref( ) . unwrap_or( id) ) }
1092
+ }
1093
+ }
1094
+ } @else {
1095
+ @let ( prefix, suffix) = id. split_once( ':' ) . unwrap( ) ;
1096
+ abbr. initialism { ( prefix. to_ascii_uppercase( ) ) } ": "
1097
+ a. isbn property="sameAs" href=( info. url) {
1098
+ span property=( info. property) { ( info. presentation_form. as_deref( ) . unwrap_or( suffix) ) }
1026
1099
}
1027
1100
}
1028
1101
". "
0 commit comments