├── README.md
├── tests
├── test-runner.xq
└── test-search.xqm
├── index.xhtml
├── user-stories
└── user-stories.txt
└── modules
└── search.xqm
/README.md:
--------------------------------------------------------------------------------
1 | # catalogers-workbench
2 | Currently in development, this will be an open source productivity tool and prototype BIBFRAME editor for library catalogers. Designed to be an eXist-db app built using the XRX approach (with XForms, RESTXQ, and XQuery).
3 |
--------------------------------------------------------------------------------
/tests/test-runner.xq:
--------------------------------------------------------------------------------
1 | xquery version "3.0";
2 |
3 | (: This main module fires off the tests stored in tests.xql :)
4 |
5 | import module namespace test = "http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";
6 | import module namespace inspect = "http://exist-db.org/xquery/inspection";
7 | import module namespace wb-test-search = "http://libserv6.princeton.edu/exist/apps/workbench/test/search" at "test-search.xqm";
8 |
9 | let $test-search-modules := (
10 | xs:anyURI("/db/apps/workbench/tests/test-search.xqm")
11 | )
12 | let $test-search-functions := $test-search-modules ! inspect:module-functions(.)
13 | return
14 | test:suite($test-search-functions)
--------------------------------------------------------------------------------
/index.xhtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
11 |
12 | Cataloger's Workbench
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Test
26 |
27 |
28 | Success.
29 |
30 | Submission error ()
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Title
40 |
41 |
42 | Search
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/user-stories/user-stories.txt:
--------------------------------------------------------------------------------
1 | Cataloger's Workbench User Stories
2 | Revised: 2015-02-13
3 |
4 | Data Entry Stories
5 |
6 | General Cataloging Stories
7 | 1. As a user cataloging books, journals, etc., I want to search WorldCat for catalog records so that I can save time by finding LC and member copy.
8 | Search by defined fields
9 | ISBN, ISSN, standard number, title, personal name, and corporate/conference name
10 | Sort results for quality and completeness
11 | LC copy, PCC, full-level member copy, incomplete member copy, non-English records, etc.
12 | 2. As a user cataloging books, journals, etc., I want to select results from WorldCat search.
13 | For LC/PCC records or full-level member copy, pre-select the record
14 | For "bad" member copy, attempt to normalize it (ensuring that data fields are consistent with control fields, etc.
15 | For non-English records, attempt to extract enough relevant info to create a well-structured brief record in English
16 | 3. As a user cataloging books, journals, etc., I want to save results from WorldCat search so that I can edit or accept a catalog record.
17 | Save as MARCXML, convert to binary MARC for import into Voyager
18 | To edit records, convert data to BF using LC conversion scripts, then load data into XForm
19 | 4. As a user cataloging books, journals, etc., I want to save data from the Web form.
20 | Save to triplestore as BF
21 | Convert BF to MARCXML and save to eXist
22 | Convert MARCXML to binary MARC for import into Voyager
23 | 5. As a user cataloging books, journals, etc., if no records in WorldCat, I want to query public APIs like Open Library for available metadata.
24 | If available, load imported metadata into Web form to create a brief record
25 | 6. As a user cataloging books, journals, etc., if no external data available, I want to produce a blank Web form so that I can create a new bibliographic description.
26 |
27 | DVD Cataloging Stories
28 | 1. As a user cataloging DVDs, if no records in WorldCat, I want to query DBpedia and/or other APIs (like OMDb) for available metadata.
29 | If available, load imported metadata into Web form to create a brief record
30 | 2. As a user cataloging DVDs, if no external data available, I want to produce a blank Web form so that I can create a new bibliographic description.
31 |
32 |
--------------------------------------------------------------------------------
/modules/search.xqm:
--------------------------------------------------------------------------------
1 | xquery version "3.0";
2 |
3 | (:~
4 | : This module defines the RESTXQ functions and endpoints used when executing a search
5 | : against the WorldCat Search API. It accepts submissions from an XForms search interface
6 | : and queries the API to retrieve MARCXML records.
7 | :
8 | : @see http://www.oclc.org/developer/develop/web-services/worldcat-search-api.en.html
9 | : @author tat2
10 | : @version 0.1
11 | :)
12 |
13 | module namespace wb-search = "http://libserv6.princeton.edu/exist/apps/workbench/search";
14 |
15 | import module namespace functx="http://www.functx.com";
16 |
17 | declare namespace rest = "http://exquery.org/ns/restxq";
18 | declare namespace httpclient = "http://exist-db.org/xquery/httpclient";
19 | declare namespace http = "http://expath.org/ns/http-client";
20 | declare namespace oclc-sru = "http://www.loc.gov/zing/srw/";
21 | declare namespace wb = "http://libserv6.princeton.edu/exist/apps/workbench";
22 |
23 | declare variable $wb-search:oclc-uri := "http://www.worldcat.org/webservices/catalog/search/sru?query=";
24 | declare variable $wb-search:oclc-key := "&wskey=YOUR KEY HERE";
25 |
26 | (:~
27 | : Accepts an XML document submitted from the XForms interface and uses it to query the WorldCat Search API.
28 | : Possible fields to query are title, personal name, corporate/conference name, ISBN, ISSN, or standard number (e.g., EAN).
29 | : Title and name can be searched in combination with each other.
30 | :
31 | : @param $query An XML document POSTed from XForms submission
32 | : @return Either MARCXML, a notification that there were no results, or an appropriate error message (server or client)
33 | :)
34 |
35 | declare
36 | %rest:path("/query")
37 | %rest:POST("{$query}")
38 | %rest:consumes("application/xml")
39 | %rest:produces("application/xml")
40 | function wb-search:oclc-search($query as document-node()) as element()* {
41 |
42 | let $uri := $wb-search:oclc-uri
43 | let $key := $wb-search:oclc-key
44 |
45 | (: Assign POSTed values to variables. :)
46 | let $title := $query//wb:title
47 | let $persname := $query//wb:persName
48 | let $corpname := $query//wb:corpName
49 | let $isbn := $query//wb:isbn
50 | let $issn := $query//wb:issn
51 | let $sn := $query//wb:sn
52 |
53 | (: Encode $title string for URI and concat with SRU syntax. :)
54 | let $encoded-title := encode-for-uri(concat("srw.ti = "", $title, """))
55 | let $search-uri := concat($uri, $encoded-title, $key)
56 | let $request :=
57 | let $response := http:send-request($request)
58 | let $head := $response[1]
59 |
60 | return
61 | if ($head/@status = "200") then
62 | {
63 | if ($response//oclc-sru:record)
64 | then for $r in $response
65 | return $r//oclc-sru:record/functx:add-attributes(., xs:QName("wb-search:test"), "false")
66 | else Sorry, there were no results for your search.
67 | }
68 | else
69 | Oops, something went wrong!{ $head }
70 |
71 | };
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/tests/test-search.xqm:
--------------------------------------------------------------------------------
1 | xquery version "3.0";
2 |
3 | (:~
4 | : This library module contains XQSuite tests for the wb-search module stored in modules/search.xqm.
5 | :
6 | : @author tat2
7 | : @version 0.1
8 | :)
9 |
10 | module namespace wb-test-search = "http://libserv6.princeton.edu/exist/apps/workbench/test/search";
11 |
12 | import module namespace wb-search = "http://libserv6.princeton.edu/exist/apps/workbench/search" at "../modules/search.xqm";
13 |
14 | declare namespace test = "http://exist-db.org/xquery/xqsuite";
15 | declare namespace wb = "http://libserv6.princeton.edu/exist/apps/workbench";
16 |
17 | (: Set up test data. :)
18 |
19 | declare
20 | %test:setUp
21 | function wb-test-search:_test-setup() {
22 | xmldb:create-collection("/db/apps/workbench/tests", "test-records"),
23 | xmldb:store("/db/apps/workbench/tests/test-records", "search-test-1.xml",
24 |
25 | Pérez, Henock
26 | Província Camiliana Brasileira
27 | Land of Shant
28 | 9786124165139
29 | 19968663
30 | 7898114691107
31 | ),
32 | xmldb:store("/db/apps/workbench/tests/test-records", "search-test-2.xml",
33 |
34 | Pérez, Henock
35 | Província Camiliana Brasileira
36 | adfadfadsf
37 | 9786124165139
38 | 19968663
39 | 7898114691107
40 | )
41 | };
42 |
43 | (: Remove test data. :)
44 |
45 | declare
46 | %test:tearDown
47 | function wb-test-search:_test-teardown() {
48 | xmldb:remove("/db/apps/workbench/tests/test-records")
49 | };
50 |
51 | (:~
52 | : Given an XML document with elements containing search strings,
53 | : run a search against the World Search API (using SRU query params).
54 | : Test to see whether one or more MARCXML records has been returned.
55 | :::: If a MARCXML record has been returned,
56 | :::: the result should have a child element.
57 | :)
58 |
59 | declare
60 | %test:args("/db/apps/workbench/tests/test-records/search-test-1.xml")
61 | %test:assertXPath("count($result/*[local-name() = 'record']) >= 1")
62 | function wb-test-search:oclc-test-for-results($query-path as xs:string) {
63 | let $arg := doc($query-path)
64 | return
65 | wb-search:oclc-search($arg)
66 | };
67 |
68 | (:~
69 | : Given an XML document with elements containing search strings,
70 | : run a search against the World Search API (using SRU query params).
71 | : Test for a server response code of 200.
72 | :::: If the server response code is not 200,
73 | :::: an element with an error message should be produced.
74 | :)
75 |
76 | declare
77 | %test:args("/db/apps/workbench/tests/test-records/search-test-1.xml")
78 | %test:assertXPath("not($result/error)")
79 | function wb-test-search:oclc-test-for-server($query-path as xs:string) {
80 | let $arg := doc($query-path)
81 | return
82 | wb-search:oclc-search($arg)
83 | };
84 |
85 | (:~
86 | : Given an XML document with elements containing search strings,
87 | : run a search against the World Search API (using SRU query params).
88 | : Test for a search with no results.
89 | :::: If no MARCXML records are returned,
90 | :::: a element should be returned, notifying the user that there were no results.
91 | :)
92 |
93 | declare
94 | %test:args("/db/apps/workbench/tests/test-records/search-test-2.xml")
95 | %test:assertXPath("exists($result/message)")
96 | function wb-test-search:oclc-test-for-no-results($query-path as xs:string) {
97 | let $arg := doc($query-path)
98 | return
99 | wb-search:oclc-search($arg)
100 | };
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------