ld4l-works_rdf 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +25 -0
  4. data/.travis.yml +14 -0
  5. data/CHANGES.md +3 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +170 -0
  9. data/Rakefile +2 -0
  10. data/ld4l-works_rdf.gemspec +42 -0
  11. data/lib/ld4l/works_rdf.rb +131 -0
  12. data/lib/ld4l/works_rdf/configuration.rb +41 -0
  13. data/lib/ld4l/works_rdf/models/bibframe/bibframe_identifier.rb +17 -0
  14. data/lib/ld4l/works_rdf/models/bibframe/bibframe_instance.rb +23 -0
  15. data/lib/ld4l/works_rdf/models/bibframe/bibframe_organization.rb +16 -0
  16. data/lib/ld4l/works_rdf/models/bibframe/bibframe_person.rb +16 -0
  17. data/lib/ld4l/works_rdf/models/bibframe/bibframe_place.rb +16 -0
  18. data/lib/ld4l/works_rdf/models/bibframe/bibframe_provider.rb +18 -0
  19. data/lib/ld4l/works_rdf/models/bibframe/bibframe_title.rb +18 -0
  20. data/lib/ld4l/works_rdf/models/bibframe/bibframe_work.rb +16 -0
  21. data/lib/ld4l/works_rdf/models/bibo/bibo_book.rb +19 -0
  22. data/lib/ld4l/works_rdf/models/bibo/bibo_document.rb +14 -0
  23. data/lib/ld4l/works_rdf/models/bibo/vivo_authorship.rb +15 -0
  24. data/lib/ld4l/works_rdf/models/bibo/vivo_book.rb +18 -0
  25. data/lib/ld4l/works_rdf/models/generic_work.rb +13 -0
  26. data/lib/ld4l/works_rdf/models/schema/oclc_schema_book.rb +16 -0
  27. data/lib/ld4l/works_rdf/models/schema/schema_book.rb +23 -0
  28. data/lib/ld4l/works_rdf/models/schema/schema_person.rb +17 -0
  29. data/lib/ld4l/works_rdf/models/schema/schema_publisher.rb +15 -0
  30. data/lib/ld4l/works_rdf/models/work_metadata.rb +212 -0
  31. data/lib/ld4l/works_rdf/services/attempt_generic_metadata_extraction.rb +41 -0
  32. data/lib/ld4l/works_rdf/services/conversion_services/get_rdfxml_from_marcxml.rb +44 -0
  33. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.ErrorCodes.xqy +56 -0
  34. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.MARCXML-2-MADSRDF.xqy +1702 -0
  35. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.MARCXML-2-RecordInfoRDF.xqy +216 -0
  36. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.MARCXMLBIB-2-BIBFRAME.xqy +140 -0
  37. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.MARCXMLBIB-BFUtils.xqy +3287 -0
  38. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.MBIB-2-BIBFRAME-Shared.xqy +4112 -0
  39. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.MBIB-Default-2-BF.xqy +61 -0
  40. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.MBIB-NotatedMusic-2-BF.xqy +105 -0
  41. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.RDFXML-2-ExhibitJSON.xqy +119 -0
  42. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.RDFXML-2-JSON.xqy +193 -0
  43. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.RDFXML-2-Ntriples.xqy +276 -0
  44. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/modules/module.RDFXMLnested-2-flat.xqy +380 -0
  45. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/xbin/ml.xqy +239 -0
  46. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/xbin/saxon.xqy +134 -0
  47. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/xbin/zorba.xqy +359 -0
  48. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/xbin/zorba2-0.xqy +249 -0
  49. data/lib/ld4l/works_rdf/services/conversion_services/marc2bibframe/xbin/zorba3-0.xqy +362 -0
  50. data/lib/ld4l/works_rdf/services/conversion_services/saxon/saxon9he.jar +0 -0
  51. data/lib/ld4l/works_rdf/services/get_metadata_from_marcxml_uri.rb +43 -0
  52. data/lib/ld4l/works_rdf/services/get_metadata_from_oclc_uri.rb +25 -0
  53. data/lib/ld4l/works_rdf/services/get_metadata_from_solr_query.rb +29 -0
  54. data/lib/ld4l/works_rdf/services/get_metadata_from_vivo_uri.rb +25 -0
  55. data/lib/ld4l/works_rdf/services/get_model_from_uri.rb +62 -0
  56. data/lib/ld4l/works_rdf/services/metadata_services/get_metadata_from_bibframe_models.rb +60 -0
  57. data/lib/ld4l/works_rdf/services/metadata_services/get_metadata_from_bibo_model.rb +42 -0
  58. data/lib/ld4l/works_rdf/services/metadata_services/get_metadata_from_generic_model.rb +41 -0
  59. data/lib/ld4l/works_rdf/services/metadata_services/get_metadata_from_oclc_model.rb +42 -0
  60. data/lib/ld4l/works_rdf/services/metadata_services/get_metadata_from_solr_doc.rb +67 -0
  61. data/lib/ld4l/works_rdf/services/metadata_services/get_metadata_from_vivo_model.rb +45 -0
  62. data/lib/ld4l/works_rdf/services/metadata_services/set_error_in_metadata.rb +27 -0
  63. data/lib/ld4l/works_rdf/services/model_services/populate_bibframe_models_from_repository.rb +46 -0
  64. data/lib/ld4l/works_rdf/services/model_services/populate_generic_model_from_repository.rb +30 -0
  65. data/lib/ld4l/works_rdf/services/model_services/populate_oclc_model_from_repository.rb +27 -0
  66. data/lib/ld4l/works_rdf/services/model_services/populate_vivo_model_from_repository.rb +27 -0
  67. data/lib/ld4l/works_rdf/services/negotiation_services/get_marcxml_from_uri.rb +35 -0
  68. data/lib/ld4l/works_rdf/services/negotiation_services/get_rdfxml_from_uri.rb +37 -0
  69. data/lib/ld4l/works_rdf/services/negotiation_services/get_solr_results_from_solr_query.rb +35 -0
  70. data/lib/ld4l/works_rdf/services/negotiation_services/get_turtle_from_uri.rb +37 -0
  71. data/lib/ld4l/works_rdf/services/negotiation_services/response_header.rb +51 -0
  72. data/lib/ld4l/works_rdf/services/repository_services/populate_graph_from_rdfxml.rb +22 -0
  73. data/lib/ld4l/works_rdf/services/repository_services/populate_graph_from_turtle.rb +21 -0
  74. data/lib/ld4l/works_rdf/services/repository_services/populate_repository_from_graph.rb +25 -0
  75. data/lib/ld4l/works_rdf/version.rb +5 -0
  76. data/lib/ld4l/works_rdf/vocab/bf.rb +29 -0
  77. data/lib/ld4l/works_rdf/vocab/bgn.rb +5 -0
  78. data/lib/ld4l/works_rdf/vocab/bibo.rb +10 -0
  79. data/lib/ld4l/works_rdf/vocab/library.rb +6 -0
  80. data/lib/ld4l/works_rdf/vocab/vitro.rb +5 -0
  81. data/lib/ld4l/works_rdf/vocab/vivo.rb +11 -0
  82. data/spec/ld4l/works_rdf/configuration_spec.rb +166 -0
  83. data/spec/ld4l/works_rdf/models/books/vivo_book_rdf_spec.rb +267 -0
  84. data/spec/ld4l/works_rdf/services/get_metadata_from_uri_spec.rb +39 -0
  85. data/spec/ld4l/works_rdf/services/get_model_from_uri_spec.rb +34 -0
  86. data/spec/ld4l/works_rdf_spec.rb +53 -0
  87. data/spec/spec_helper.rb +26 -0
  88. metadata +321 -0
@@ -0,0 +1,4112 @@
1
+ xquery version "1.0";
2
+ (:
3
+ : Module Name: MARCXML BIB to bibframe Shared functions
4
+ :
5
+ : Module Version: 1.0
6
+ :
7
+ : Date: 2014 Jan 30
8
+ :
9
+ : Copyright: Public Domain
10
+ :
11
+ : Proprietary XQuery Extensions Used: None
12
+ :
13
+ : Xquery Specification: January 2007
14
+ :
15
+ : Module Overview: Transforms a MARC Bib record
16
+ : into its bibframe parts.
17
+ :
18
+ :)
19
+
20
+ (:~
21
+ : Here are shared functions called by other modules in building bibframe resources
22
+ :
23
+ : Modified to receive $collection, consisting of a bib and it's holdings (optionally) 2014-12-16
24
+ :
25
+ : @author Kevin Ford (kefo@loc.gov)
26
+ : @author Nate Trail (ntra@loc.gov)
27
+ : @since January 14, 2014
28
+ : @version 1.0
29
+ :)
30
+
31
+ module namespace mbshared = 'info:lc/id-modules/mbib2bibframeshared#';
32
+
33
+ (: MODULES :)
34
+ import module namespace marcxml2madsrdf = "info:lc/id-modules/marcxml2madsrdf#" at "module.MARCXML-2-MADSRDF.xqy";
35
+ import module namespace marc2bfutils = "info:lc/id-modules/marc2bfutils#" at "module.MARCXMLBIB-BFUtils.xqy";
36
+
37
+
38
+ (: NAMESPACES :)
39
+ declare namespace marcxml = "http://www.loc.gov/MARC21/slim";
40
+ declare namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
41
+ declare namespace rdfs = "http://www.w3.org/2000/01/rdf-schema#";
42
+
43
+ declare namespace bf = "http://bibframe.org/vocab/";
44
+ declare namespace madsrdf = "http://www.loc.gov/mads/rdf/v1#";
45
+ declare namespace relators = "http://id.loc.gov/vocabulary/relators/";
46
+ declare namespace hld = "http://www.loc.gov/opacxml/holdings/" ;
47
+
48
+ (: VARIABLES :)
49
+ declare variable $mbshared:last-edit :="2015-01-16-T11:00:00";
50
+
51
+ (:rules have a status of "on" or "off":)
52
+ declare variable $mbshared:transform-rules :=(
53
+ <rules>
54
+ <rule status="on" id="1" label="isbn" category="instance-splitting">New instances on secondary unique ISBNs</rule>
55
+ <rule status="on" id="2" label="issn" category="instance-splitting">New instances on secondary unique ISSNs</rule>
56
+ <rule status="on" id="3" label="260" category="instance-splitting">New instances on multiple 260s (not serials)</rule>
57
+ <rule status="on" id="4" label="250" category="instance-splitting">New instances on multiple 250s</rule>
58
+ <rule status="on" id="4" label="300" category="instance-splitting">New instances on multiple 300s</rule>
59
+ <rule status="on" id="5" label="246" category="instance-node">246 domain is instance</rule>
60
+ <rule status="on" id="6" label="247" category="instance-node">247 domain is instance</rule>
61
+ <!--<rule status="on" id="7" label="856" category="instance-splitting">New instances on secondary 856s that are resources (ind2=0)</rule>??? -->
62
+ </rules>
63
+ );
64
+ declare variable $mbshared:named-notes:=("(502|505|506|507|508|511|513|518|522|524|525|541|546|555)");
65
+
66
+ (: this var plus all the simple-properties nodes are used to generate standalone 880s:)
67
+ declare variable $mbshared:addl-880-nodes:= (
68
+ <properties>
69
+ <node domain="work" property="note" tag="500" sfcodes="a">General Note</node>
70
+ <node domain="instance" property="note" tag="500" sfcodes="a">General Note</node>
71
+ <node domain="work" property="note" tag="505" sfcodes="t">complex note work title</node>
72
+ </properties>
73
+ );
74
+
75
+ (:these properties are transformed as either literals or appended to the @uri parameter inside their @domain:)
76
+ declare variable $mbshared:simple-properties:= (
77
+ <properties>
78
+ <node domain="instance" property="lccn" tag="010" sfcodes="a" uri="http://id.loc.gov/authorities/test/identifiers/lccn/" group="identifiers" >Library of Congress Control Number</node>
79
+ <node domain="instance" property="nbn" tag="015" sfcodes="a" group="identifiers" >National Bibliography Number</node>
80
+ <node domain="instance" property="nban" tag="016" sfcodes="a" group="identifiers" >National bibliography agency control number</node>
81
+ <node domain="instance" property="legalDeposit" tag="017" sfcodes="a" group="identifiers" >copyright or legal deposit number</node>
82
+ <node domain="instance" property="issn" tag="022" sfcodes="a" group="identifiers" >International Standard Serial Number</node>
83
+ <node domain="work" property="issnL" tag="022" sfcodes="l" group="identifiers" >linking International Standard Serial Number</node>
84
+ <node domain="instance" property="isrc" tag="024" sfcodes="a" ind1="0" group="identifiers">International Standard Recording Code</node>
85
+ <node domain="instance" property="upc" tag="024" sfcodes="a" ind1="1" group="identifiers">Universal Product Code</node>
86
+ <node domain="instance" property="ismn" tag="024" sfcodes="a" ind1="2" group="identifiers">International Standard Music Number</node>
87
+ <node domain="instance" property="ean" tag="024" sfcodes="a,z,d" ind1="3" group="identifiers" comment="(sep by -)" >International Article Identifier (EAN)</node>
88
+ <node domain="instance" property="sici" tag="024" sfcodes="a" ind1="4" group="identifiers">Serial Item and Contribution Identifier</node>
89
+ <node domain="instance" property="$2" tag="024" sfcodes="a" ind1="7" group="identifiers">contents of $2</node>
90
+ <node domain="instance" property="identifier" tag="024" sfcodes="a" ind1="8" group="identifiers">unspecified</node>
91
+ <node domain="instance" property="lcOverseasAcq" tag="025" sfcodes="a" group="identifiers" >Library of Congress Overseas Acquisition Program number</node>
92
+ <node domain="instance" property="fingerprint" tag="026" sfcodes="e" group="identifiers" >fingerprint identifier</node>
93
+ <node domain="instance" property="strn" tag="027" sfcodes="a" group="identifiers" >Standard Technical Report Number</node>
94
+ <node domain="instance" property="issueNumber" tag="028" sfcodes="a" ind1="0" group="identifiers">sound recording publisher issue number</node>
95
+ <node domain="instance" property="matrixNumber" tag="028" sfcodes="a" ind1="1" group="identifiers">sound recording publisher matrix master number</node>
96
+ <node domain="instance" property="musicPlate" tag="028" sfcodes="a" ind1="2" group="identifiers" >music publication number assigned by publisher</node>
97
+ <node domain="instance" property="musicPublisherNumber" tag="028" sfcodes="a" ind1="3" group="identifiers">other publisher number for music</node>
98
+ <node domain="instance" property="videorecordingNumber" tag="028" sfcodes="a" ind1="4" group="identifiers" >publisher assigned videorecording number</node>
99
+ <node domain="instance" property="publisherNumber" tag="028" sfcodes="a" ind1="5" group="identifiers" >other publisher assigned number</node>
100
+ <node domain="instance" property="coden" tag="030" sfcodes="a" group="identifiers" >CODEN</node>
101
+ <node domain="7xx" property="systemNumber" tag="776" sfcodes="w" group="identifiers" uri="http://www.worldcat.org/oclc/" >system number</node>
102
+ <node domain="7xx" property="issn" tag="776" sfcodes="x" group="identifiers" >issn</node>
103
+ <node domain="7xx" property="coden" tag="776" sfcodes="y" group="identifiers" >CODEN</node>
104
+ <node domain="7xx" property="isbn" tag="776" sfcodes="z" group="identifiers" >issn</node>
105
+ <node domain="instance" property="postalRegistration" tag="032" sfcodes="a" group="identifiers" >postal registration number</node>
106
+ <node domain="instance" property="systemNumber" tag="035" sfcodes="a" group="identifiers" uri="http://www.worldcat.org/oclc/" >system control number</node>
107
+ <node domain="instance" property="studyNumber" tag="036" sfcodes="a" group="identifiers" >original study number assigned by the producer of a computer file</node>
108
+ <node domain="instance" property="stockNumber" tag="037" sfcodes="a" group="identifiers" >stock number for acquisition</node>
109
+ <node domain="instance" property="reportNumber" tag="088" sfcodes="a" group="identifiers" >technical report number</node>
110
+ <node domain="annotation" property="descriptionSource" tag="040" sfcodes="a" uri="http://id.loc.gov/vocabulary/organizations/" group="identifiers" >Description source</node>
111
+ <node domain="annotation" property="descriptionModifier" tag="040" sfcodes="d" uri="http://id.loc.gov/vocabulary/organizations/" group="identifiers" >Description source</node>
112
+ <node domain="annotation" property="descriptionConventions" tag="040" sfcodes="e" uri="http://id.loc.gov/vocabulary/descriptionConventions/" >Description conventions</node>
113
+ <node domain="annotation" property="descriptionLanguage" tag="040" sfcodes="b" uri="http://id.loc.gov/vocabulary/languages/" >Description Language </node>
114
+
115
+ <node domain="classification" property="classificationSpanEnd" tag="083" sfcodes="c" >classification span end for class number</node>
116
+ <node domain="classification" property="classificationTableSeq" tag="083" sfcodes="y" >DDC table sequence number</node>
117
+ <node domain="classification" property="classificationTable" tag="083" sfcodes="z" >DDC table</node>
118
+ <node domain="classification" property="classificationAssigner" tag="083" sfcodes="q" >various orgs assigner</node><!-- uri="http://id.loc.gov/vocabulary/organizations/"-->
119
+
120
+ <node domain="classification" property="classificationLcc" tag="052" sfcodes="ab" stringjoin="." uri="http://id.loc.gov/authorities/classification/G" >geo class</node>
121
+ <node domain="title" property="titleQualifier" tag="210" sfcodes="b" >title qualifier</node>
122
+ <node domain="title" property="titleQualifier" tag="222" sfcodes="b" >title qualifier</node>
123
+ <node domain="title" property="partNumber" tag="245" sfcodes="n" >part number</node>
124
+ <node domain="title" property="partNumber" tag="246" sfcodes="n" >part number</node>
125
+ <node domain="title" property="partNumber" tag="247" sfcodes="n" >part number</node>
126
+
127
+ <node domain="title" property="titleValue" tag="130" sfcodes="a" >title itself</node>
128
+ <node domain="title" property="titleValue" tag="730" sfcodes="a" >title itself</node>
129
+ <node domain="title" property="titleValue" tag="240" sfcodes="a" >title itself</node>
130
+ <node domain="title" property="partNumber" tag="130" sfcodes="n" >part number</node>
131
+ <node domain="title" property="partNumber" tag="240" sfcodes="n" >part number</node>
132
+
133
+ <node domain="title" property="titleValue" tag="210" sfcodes="a" > title itself</node>
134
+ <node domain="title" property="titleValue" tag="222" sfcodes="a" > title itself</node>
135
+
136
+ <node domain="title" property="titleValue" tag="242" sfcodes="a" >title itself</node>
137
+ <!--<node domain="title" property="titleValue" tag="245" sfcodes="a" > title itself</node>-->
138
+ <node domain="title" property="titleValue" tag="246" sfcodes="a" >title itself</node>
139
+ <node domain="title" property="titleValue" tag="247" sfcodes="a" >title itself</node>
140
+ <!--<node domain="title" property="subtitle" tag="245" sfcodes="b" > subtitle </node>-->
141
+ <node domain="title" property="subtitle" tag="246" sfcodes="b" >subtitle</node>
142
+ <node domain="title" property="subtitle" tag="247" sfcodes="b" >subtitle</node>
143
+
144
+ <node domain="title" property="partTitle" tag="245" sfcodes="p" >part title</node>
145
+ <node domain="title" property="partTitle" tag="246" sfcodes="p" >part title</node>
146
+ <node domain="title" property="partTitle" tag="247" sfcodes="p" >part title</node>
147
+ <node domain="title" property="partTitle" tag="242" sfcodes="p" >part title</node>
148
+ <node domain="title" property="partTitle" tag="130" sfcodes="p" >part title</node>
149
+ <node domain="title" property="partTitle" tag="730" sfcodes="p" >part title</node>
150
+ <node domain="title" property="partTitle" tag="240" sfcodes="p" >part title</node>
151
+ <node domain="title" property="titleVariationDate" tag="246" sfcodes="f" >title variation date</node>
152
+ <node domain="title" property="titleVariationDate" tag="247" sfcodes="f" >title variation date</node>
153
+ <node domain="title" property="titleSource" tag="210" sfcodes="2" uri="http://id.loc.gov/vocabulary/organizations/" >title source</node>
154
+
155
+ <node domain="title" property="titleAttribute" tag="130" sfcodes="g" >title attributes</node>
156
+ <node domain="title" property="titleAttribute" tag="240" sfcodes="g" >Miscellaneous </node>
157
+
158
+ <!--<node domain="title" property="titleAttribute" tag="240" sfcodes="o" >arrangement</node>-->
159
+ <node domain="work" property="musicVersion" tag="130" sfcodes="s" >version</node>
160
+ <node domain="work" property="musicVersion" tag="240" sfcodes="s" >version</node>
161
+ <node domain="instance" property="titleStatement" tag="245" sfcodes="ab" >title Statement</node>
162
+
163
+ <!--<node domain="instance" property="responsibilityStatement" tag="245" sfcodes="c" >responsibility Statement</node> -->
164
+ <node domain="work" property="treatySignator" tag="710" sfcodes="g" >treaty Signator</node>
165
+ <node domain="instance" property="edition" tag="250" sfcodes="a" >Edition</node>
166
+
167
+ <node domain="instance" property="editionResponsibility" tag="250" sfcodes="b" >Edition Responsibility</node>
168
+ <node domain="cartography" property="cartographicScale" tag="255" sfcodes="a" >cartographicScale</node>
169
+ <node domain="cartography" property="cartographicScale" tag="034" sfcodes="" >cartographicScale</node>
170
+ <node domain="cartography" property="cartographicProjection" tag="255" sfcodes="b" >cartographicProjection</node>
171
+ <node domain="cartography" property="cartographicCoordinates" tag="255" sfcodes="c" >cartographicCoordinates</node>
172
+ <node domain="cartography" property="cartographicAscensionAndDeclination" tag="255" sfcodes="d" >cartographicAscensionAndDeclination</node>
173
+ <node domain="cartography" property="cartographicEquinox" tag="255" sfcodes="e" >cartographicEquinox</node>
174
+ <node domain="cartography" property="cartographicOuterGRing" tag="255" sfcodes="f" >cartographicOuterGRing</node>
175
+ <node domain="cartography" property="cartographicExclusionGRing" tag="255" sfcodes="g" >CartographicExclusionGRing</node>
176
+
177
+ <node domain="instance" property="providerStatement" tag="260" sfcodes="3abc" >Provider statement</node>
178
+ <node domain="instance" property="providerStatement" tag="264" sfcodes="3abc" >Provider statement</node>
179
+ <node domain="instance" property="extent" tag="300" sfcodes="3aef" >Physical Description</node>
180
+
181
+ <node domain="specialinstnc" property="mediaCategory" tag="337" sfcodes="a" uri="http://id.loc.gov/vocabulary/mediaTypes/" >Media Category</node>
182
+ <node domain="specialinstnc" property="mediaCategory" tag="337" sfcodes="b" uri="http://id.loc.gov/vocabulary/mediaTypes/" >Media Category</node>
183
+ <node domain="specialinstnc" property="carrierCategory" tag="338" sfcodes="b" uri="http://id.loc.gov/vocabulary/carriers/" >Physical Description</node>
184
+ <node domain="specialinstnc" property="carrierCategory" tag="338" sfcodes="a" uri="http://id.loc.gov/vocabulary/carriers/" >Physical Description</node>
185
+ <node domain="work" property="musicKey" tag="384" sfcodes="a" startwith="Transposed key: " ind1="1" > Key </node>
186
+ <node domain="work" property="musicKey" tag="384" sfcodes="a" ind1=" " > Key </node>
187
+ <node domain="work" property="musicKey" tag="384" sfcodes="a" ind1="0" > Key </node>
188
+ <node domain="work" property="musicKey" tag="130" sfcodes="r" > Key </node>
189
+ <node domain="work" property="musicKey" tag="240" sfcodes="r" > Key </node>
190
+ <node domain="work" property="formDesignation" tag="130" sfcodes="k" >Form subheading from title</node>
191
+ <node domain="work" property="formDesignation" tag="240" sfcodes="k" >Form subheading from title</node>
192
+ <node domain="related" property="formDesignation" tag="730" sfcodes="k" >Form Designation</node>
193
+ <node domain="work" property="musicMediumNote" tag="382" sfcodes="adp" > Music medium note </node>
194
+ <node domain="work" property="musicMediumNote" tag="130" sfcodes="m" > Music medium note </node>
195
+ <node domain="work" property="musicMediumNote" tag="730" sfcodes="m" > Music medium note </node>
196
+ <node domain="work" property="musicMediumNote" tag="240" sfcodes="m" > Music medium note </node>
197
+ <node domain="work" property="musicMediumNote" tag="243" sfcodes="m" > Music medium note </node>
198
+ <node domain="instance" property="dimensions" tag="300" sfcodes="c" >Physical Size</node>
199
+ <node domain="work" property="duration" tag="306" sfcodes="a" >Playing time</node>
200
+ <node domain="instance" property="frequencyNote" tag="310" sfcodes="ab" >Issue frequency</node>
201
+ <node domain="instance" property="aspectRatio" tag="345" sfcodes="a" >aspect ratio</node>
202
+ <!--<node domain="instance" property="frequencyNote" tag="321" sfcodes="ab" >Issue frequency</node>-->
203
+ <node domain="arrangement" property="materialPart" tag="351" sfcodes="3" >material Organization</node>
204
+ <node domain="arrangement" property="materialOrganization" tag="351" sfcodes="a" >material Organization</node>
205
+ <node domain="arrangement" property="materialArrangement" tag="351" sfcodes="b" >ImaterialArrangement</node>
206
+ <node domain="arrangement" property="materialHierarchicalLevel" tag="351" sfcodes="c" >materialHierarchicalLevel</node>
207
+
208
+ <node domain="contentcategory" property="carrierCategory" tag="130" sfcodes="h" >Nature of content</node>
209
+ <node domain="contentcategory" property="carrierCategory" tag="240" sfcodes="h" >Nature of content</node>
210
+ <node domain="contentcategory" property="carrierCategory" tag="243" sfcodes="h" >Nature of content</node>
211
+ <node domain="contentcategory" property="carrierCategory" tag="300" sfcodes="f" >Nature of content</node>
212
+ <node domain="contentcategory" property="contentCategory" tag="245" sfcodes="k" >Nature of content</node>
213
+ <node domain="contentcategory" property="genre" tag="513" sfcodes="a" >Nature of content</node>
214
+ <node domain="contentcategory" property="genre" tag="516" sfcodes="a" >Nature of content</node>
215
+
216
+ <node domain="related" property="carrierCategory" tag="730" sfcodes="h" >Nature of content</node>
217
+
218
+ <node domain="related" property="carrierCategory" tag="700" sfcodes="h" >Nature of content</node>
219
+ <node domain="related" property="carrierCategory" tag="710" sfcodes="h" >Nature of content</node>
220
+ <node domain="related" property="carrierCategory" tag="711" sfcodes="h" >Nature of content</node>
221
+ <node domain="work" property="originDate" tag="130" sfcodes="f" >Date of origin</node>
222
+ <node domain="related" property="originDate" tag="730" sfcodes="f" >Date of origin</node>
223
+ <node domain="work" property="originDate" tag="046" sfcodes="kl" stringjoin="-" >Date of origin</node>
224
+
225
+ <node domain="instance" property="formDesignation" tag="245" sfcodes="h" >Form Designation</node>
226
+ <node domain="instance" property="formDesignation" tag="245" sfcodes="k" >Form Designation</node>
227
+
228
+ <node domain="work" property="musicNumber" tag="130" sfcodes="n" >Music Number</node>
229
+ <node domain="work" property="partNumber" tag="730" sfcodes="n" >Music Number</node>
230
+ <node domain="work" property="musicVersion" tag="130" sfcodes="o" >Music Version</node>
231
+ <node domain="work" property="musicVersion" tag="240" sfcodes="o" >Music Version</node>
232
+ <node domain="work" property="legalDate" tag="130" sfcodes="d" >Legal Date</node>
233
+ <node domain="work" property="legalDate" tag="730" sfcodes="d" >Legal Date</node>
234
+ <node domain="work" property="dissertationNote" tag="502" sfcodes="a" >Dissertation Note</node>
235
+ <node domain="work" property="dissertationDegree" tag="502" sfcodes="b" >Dissertation Note</node>
236
+ <node domain="work" property="dissertationYear" tag="502" sfcodes="d" >Dissertation Note</node>
237
+ <node domain="work" property="dissertationNote" tag="502" sfcodes="g" >Dissertation Note</node>
238
+ <node domain="instance" property="contentsNote" tag="505" sfcodes="agrtu" ind2=" ">Formatted Contents Note</node>
239
+
240
+ <node domain="work" property="temporalCoverageNote" tag="513" sfcodes="b" >Period Covered Note</node>
241
+ <node domain="work" property="temporalCoverageNote" tag="648" sfcodes="a" >temporalCoverage Note</node>
242
+ <node domain="event" property="eventDate" tag="518" sfcodes="d" >Event Date</node>
243
+ <node domain="work" property="note" tag="518" sfcodes="a" >Event Date</node>
244
+ <node domain="work" property="geographicCoverageNote" tag="522" >Geographic Coverage Note</node>
245
+ <node domain="work" property="supplementaryContentNote" tag="525" sfcodes="a" >Supplement Note</node>
246
+ <node domain="findingaid" property="findingAidNote" tag="555" sfcodes="3abc" >Cumulative Index/Finding Aids Note </node>
247
+ <node domain="helditem" property="custodialHistory" tag="561" sfcodes="a" >Copy specific custodial history</node>
248
+ <node domain="work" property="awardNote" tag="586" sfcodes="3a" >Awards Note</node>
249
+ <node domain="instance" property="copyrightDate" tag="264" sfcodes="c" ind2="4">Copyright Date</node>
250
+ <node domain="instance" property="philatelicDataNote" tag="258" sfcodes="ab" >Philatelic data note</node>
251
+ <node domain="instance" property="illustrationNote" tag="300" sfcodes="b" >Illustrative content note</node>
252
+ <node domain="instance" property="aspectRatio" tag="345" sfcodes="a" >Aspect Ratio</node>
253
+
254
+ <node domain="instance" property="accessCondition" tag="506" sfcodes="3a" >Restrictions on Access Note</node>
255
+ <node domain="instance" property="graphicScaleNote" tag="507" sfcodes="a" >Scale Note for Graphic Material</node>
256
+ <node domain="instance" property="creditsNote" tag="508" startwith="Credits: " >Creation/Production Credits Note </node>
257
+ <node domain="instance" property="performerNote" tag="511" startwith="Cast: " >Participant or Performer Note </node>
258
+ <node domain="instance" property="preferredCitation" tag="524" >Preferred Citation of Described Materials Note</node>
259
+ <node domain="instance" property="immediateAcquisition" tag="541" sfcodes="3abcdfhno" >Immediate Source of Acquisition Note</node>
260
+
261
+ <node domain="instance" property="languageNote" tag="546" sfcodes="3a" stringjoin=": " >Language Note</node>
262
+ <node domain="instance" property="notation" tag="546" sfcodes="b" >Language Notation(script)</node>
263
+ <node domain="related" property="edition" tag="534" sfcodes="b" >Edition</node>
264
+ <node domain="related" property="note" tag="534" sfcodes="n" >Note</node>
265
+ <node domain="work" property="geographicCoverageNote" tag="662" sfcodes="abcdefg" stringjoin="--" >geographicCoverage Note</node>
266
+ <node domain="work" property="geographicCoverageNote" tag="662" sfcodes="h" >geographicCoverage Note</node>
267
+ <!--holdings-->
268
+ <node domain="holdings" property="heldBy" tag="852" sfcodes="a" >heldBy </node>
269
+ <node domain="holdings" property="subLocation" tag="852" sfcodes="b" >subLocation </node>
270
+ <node domain="holdings" property="barcode" tag="852" sfcodes="p" >bar code</node>
271
+ <node domain="holdings" property="shelfMark" tag="852" sfcodes="khlimt" >shelfMark code</node>
272
+
273
+ </properties>
274
+ ) ;
275
+
276
+
277
+ (:$related fields must have $t except 630,730,830 , 767? 740 ($a is title), :)
278
+ declare variable $mbshared:relationships :=
279
+ (
280
+ <relationships>
281
+ <!-- Work to Work relationships -->
282
+ <work-relateds all-tags="(400|410|411|430|440|490|533|534|630|700|710|711|730|740|760|762|765|767|770|772|773|774|775|777|780|785|787|800|810|811|830)">
283
+ <type tag="(700|710|711|730)" ind2="2" property="hasPart">isIncludedIn</type>
284
+ <type tag="(700|710|711|730)" ind2="( |0|1)" property="relatedResource">relatedWork</type>
285
+ <type tag="740" ind2=" " property="relatedWork">relatedWork</type>
286
+
287
+ <type tag="740" property="partOf" ind2="2">hasPart</type>
288
+ <type tag="760" property="subseriesOf">hasParts</type>
289
+ <type tag="762" property="subseries">hasParts</type>
290
+ <type tag="765" property="translationOf">hasTranslation</type>
291
+ <type tag="767" property="translation">translationOf</type>
292
+ <type tag="770" property="supplement">supplement</type>
293
+ <type tag="772" ind2=" " property="supplementTo">isSupplemented</type>
294
+
295
+ <type tag="773" property="partOf">hasConstituent</type>
296
+ <type tag="774" property="hasPart">has Part</type>
297
+ <type tag="775" property="otherEdition" >hasOtherEdition</type>
298
+ <type tag="787" property="relatedWork">relatedWork</type>
299
+
300
+ <!--???the generic preceeding and succeeding may not be here -->
301
+ <type tag="780" ind2="0" property="continues">continuationOf</type>
302
+ <type tag="780" ind2="1" property="continuesInPart">partiallyContinuedBy</type>
303
+ <type tag="780" ind2="2" property="supersedes">continuationOf</type>
304
+ <type tag="780" ind2="3" property="supersedesInPartBy">partiallyContinuedBy</type>
305
+ <type tag="780" ind2="4" property="unionOf">preceding</type>
306
+ <type tag="780" ind2="5" property="absorbed">isAbsorbedBy</type>
307
+ <type tag="780" ind2="6" property="absorbedInPartBy">isPartlyAbsorbedBy</type>
308
+ <type tag="780" ind2="7" property="separatedFrom">formerlyIncluded</type>
309
+ <type tag="785" ind2="0" property="continuedBy">continues</type>
310
+ <type tag="785" ind2="1" property="continuedInPartBy">partiallyContinues</type>
311
+ <type tag="785" ind2="2" property="supersededBy">continues</type>
312
+ <type tag="785" ind2="3" property="supersededInPartBy">partiallyContinues</type>
313
+ <type tag="785" ind2="4" property="absorbedBy">absorbs</type>
314
+ <type tag="785" ind2="5" property="absorbedInPartBy">partiallyAbsorbs</type>
315
+ <type tag="785" ind2="6" property="splitInto">splitFrom</type>
316
+ <type tag="785" ind2="7" property="mergedToForm">mergedFrom</type>
317
+ <type tag="785" ind2="8" property="succeededBy">formerlyNamed</type>
318
+ <type tag="786" property="dataSource"></type>
319
+ <type tag="533" property="reproduction"></type>
320
+ <type tag="534" property="originalVersion"></type>
321
+ <type tag="630" property="subject">isSubjectOf</type>
322
+ <type tag="(400|410|411|430|440|490|800|810|811|830)" property="series">hasParts</type>
323
+
324
+ </work-relateds>
325
+ <!--
326
+ <type tag="490" ind1="0" property="inSeries">hasParts</type>
327
+ <type tag="510" property="describedIn">isReferencedBy</type>
328
+ -->
329
+ <!-- Instance to Work relationships (none!) -->
330
+ <instance-relateds all-tags="(776|777)">
331
+ <!--<type tag="6d30" property="subject">isSubjectOf</type>-->
332
+ <type tag="776" property="otherPhysicalFormat">hasOtherPhysicalFormat</type>
333
+ <type tag="777" property="issuedWith">issuedWith</type>
334
+ </instance-relateds>
335
+ </relationships>
336
+ );
337
+
338
+ (:~
339
+ : This is the function generates an annotation from 520 u
340
+ :
341
+ : @param $marcxml element is the MARCXML record
342
+ : @return bf:* hasAnnotation element
343
+ :)
344
+ declare function mbshared:generate-abstract-annotation(
345
+ $marcxml as element(marcxml:record) ,
346
+ $workID as xs:string
347
+ ) as element (bf:hasAnnotation)*
348
+ {
349
+ for $d in $marcxml/marcxml:datafield[@tag="520"][marcxml:subfield[fn:matches(@code,"(a|c|u)")]]
350
+
351
+ let $abstract-type:=
352
+ if ($d/@ind1="") then "Summary" (:Summary:)
353
+ else if ($d/@ind1="0") then "Summary"(:Content Description:)
354
+ else if ($d/@ind1="1") then "Review"
355
+ else if ($d/@ind1="2") then "Summary" (:Scope and Content:)
356
+ else if ($d/@ind1="3") then "Summary" (:Abstract:)
357
+ else if ($d/@ind1="4") then "Summary" (:Content advice:)
358
+ else "Summary"
359
+
360
+ return (:link direction is reversed in nested2flat module, hasAnnotation becomes reviewOf, summaryOf:)
361
+ element bf:hasAnnotation {
362
+ element {fn:concat("bf:", $abstract-type)} {
363
+ element rdf:type {
364
+ attribute rdf:resource { fn:concat("http://bibframe.org/vocab/" , fn:replace($abstract-type, " ", "") ) }
365
+ },
366
+
367
+ element bf:label { $abstract-type},
368
+
369
+ if (fn:string($d/marcxml:subfield[@code="c"][1]) ne "") then
370
+ for $sf in $d/marcxml:subfield[@code="c"]
371
+ return element bf:annotationAssertedBy { fn:string($sf) }
372
+ else
373
+ element bf:annotationAssertedBy {
374
+ attribute rdf:resource {"http://id.loc.gov/vocabulary/organizations/dlc" }
375
+ },
376
+ (:??? annotationbody and literal aren't right:)
377
+ for $sf in $d/marcxml:subfield[@code="u"]
378
+ return element bf:annotationBody { attribute rdf:resource {fn:string($sf)} },
379
+ if ( $d/marcxml:subfield[@code="a"] ) then
380
+ element bf:annotationBody { fn:string-join($d/marcxml:subfield[@code="a" or @code="b"] ," ") }
381
+ else (),
382
+
383
+ let $property-name:=
384
+ if ($abstract-type="Summary") then "bf:summaryOf"
385
+ else if ($abstract-type="Review") then "bf:reviewOf"
386
+ else "bf:annotates"
387
+ return element {$property-name} {
388
+ attribute rdf:resource {$workID}
389
+ }
390
+ }
391
+ }
392
+ };
393
+ (:~
394
+ : This is the function generates administrative metadata about the record
395
+ :
396
+ : @param $marcxml element is the MARCXML record
397
+ : @return bf:* hasAnnotation element
398
+ :)
399
+ declare function mbshared:generate-admin-metadata(
400
+ $marcxml as element(marcxml:record) ,
401
+ $workID as xs:string
402
+ ) as element (bf:hasAnnotation)
403
+ {
404
+ (:let $biblink:=fn:concat(
405
+ $workID,
406
+ fn:normalize-space(fn:string($marcxml/marcxml:controlfield[@tag eq "001"]))
407
+ ):)
408
+ let $derivedFrom :=
409
+ element bf:derivedFrom {
410
+ attribute rdf:resource {
411
+ fn:concat($workID, ".marcxml.xml")
412
+ }
413
+ }
414
+ let $edited:= if ($marcxml/marcxml:controlfield[@tag="005"]) then
415
+ fn:concat(fn:substring(($marcxml/marcxml:controlfield[@tag="005"]),1,4),"-",fn:substring(($marcxml/marcxml:controlfield[@tag="005"]),5,2),"-",fn:substring(($marcxml/marcxml:controlfield[@tag="005"]),7,2),"T",fn:substring(($marcxml/marcxml:controlfield[@tag="005"]),9,2),":",fn:substring(($marcxml/marcxml:controlfield[@tag="005"]),11,2))
416
+ else
417
+ ()
418
+ let $changed:= ( element bf:generationProcess {fn:concat("DLC transform-tool:",$mbshared:last-edit)},
419
+ if ($edited) then
420
+ element bf:changeDate {$edited}
421
+ else ()
422
+ )
423
+
424
+ let $leader18:=fn:substring($marcxml/marcxml:leader,19,1)
425
+ let $cataloging-meta:=
426
+ (for $d in $marcxml/marcxml:datafield[@tag="040"]
427
+ return mbshared:generate-simple-property($d,"annotation")
428
+ ,
429
+ if ($leader18="a") then element bf:descriptionConventions { attribute rdf:resource {"http://id.loc.gov/vocabulary/descriptionConventions/aacr2"} }
430
+ else if ($leader18=" ") then element bf:descriptionConventions { attribute rdf:resource {"http://id.loc.gov/vocabulary/descriptionConventions/nonisbd"} }
431
+ else if ($leader18="c" or $leader18="i") then element bf:descriptionConventions { attribute rdf:resource {"http://id.loc.gov/vocabulary/descriptionConventions/isbd"}}
432
+ else ()
433
+ )
434
+
435
+ let $annotates:= element bf:annotates {attribute rdf:resource {$workID}}
436
+ return
437
+ element bf:hasAnnotation {
438
+ element bf:Annotation {
439
+ $derivedFrom,
440
+ $cataloging-meta,
441
+ $changed,
442
+ $annotates
443
+
444
+ }
445
+ }
446
+ };
447
+ (:~
448
+ : This is the function generates secondary instances from multiple 260/264
449
+ :
450
+ : @param $d element is the MARCXML 260/264{position>1]
451
+ : @param $workID uri for the derivedfrom
452
+ : @param $position nth position of the 260 in the record; match to 321s
453
+ : @return bf:* as element()
454
+ :)
455
+ declare function mbshared:generate-additional-instance(
456
+ $d as element(marcxml:datafield),
457
+ $workID as xs:string,
458
+ $position as xs:integer
459
+ ) as element ()
460
+ {
461
+
462
+ let $derivedFrom:=
463
+ element bf:derivedFrom {
464
+ attribute rdf:resource{fn:concat($workID,".marcxml.xml")}
465
+ }
466
+ let $instance-title :=
467
+ fn:concat(fn:string( $d/../marcxml:datafield[@tag="245"]/marcxml:subfield[@code="a"]), " " ,fn:string($d/marcxml:subfield[@code="3"]))
468
+ let $pub:= mbshared:generate-publication($d)
469
+ let $freq:= for $s in $d/../marcxml:datafield[@tag="321"][fn:position()=$position - 1]
470
+ return element bf:frequencyNote {fn:string-join($s/marcxml:subfield[@code="a" or @code="b"], " ")}
471
+ return element bf:Instance {element bf:instanceTitle{
472
+ element bf:Title{ element bf:titleValue{$instance-title}}},
473
+ $freq,
474
+ $pub,
475
+ $derivedFrom
476
+ }
477
+ };
478
+ (:~
479
+ : This is the function generates Instance resources when there are multiple 300s
480
+ :
481
+ : @param $d element is the MARCXML 300
482
+ : @param $workID uri for the derivedfrom
483
+ : @return bf:* as element()
484
+ :)
485
+ declare function mbshared:generate-addl-physical(
486
+ $d as element(marcxml:datafield),
487
+ $workID as xs:string,
488
+ $position as xs:integer
489
+ ) as element ()
490
+ {
491
+
492
+ let $derivedFrom:=
493
+ element bf:derivedFrom {
494
+ attribute rdf:resource{fn:concat($workID,".marcxml.xml")}
495
+ }
496
+ let $instance-title :=
497
+ ( element bf:titleValue {if (fn:contains($d/../marcxml:datafield[@tag="245"]/marcxml:subfield[@code="a"],"=")) then
498
+ fn:substring-before($d/../marcxml:datafield[@tag="245"]/marcxml:subfield[@code="a"],"=")
499
+ else
500
+ marc2bfutils:clean-title-string($d/../marcxml:datafield[@tag="245"]/marcxml:subfield[@code="a"])
501
+ },
502
+ (: ... this will probably need to change: :)
503
+ if ($d/marcxml:subfield[@code="3"]) then element bf:titleQualifier {fn:string($d/marcxml:subfield[@code="3"])} else ()
504
+ )
505
+ let $instance-types1:= mbshared:get-instanceTypes($d/ancestor::marcxml:record)
506
+
507
+ let $instance-types:=
508
+ for $i in fn:distinct-values($instance-types1)
509
+ return element rdf:type { attribute rdf:resource { fn:concat("http://bibframe.org/vocab/" ,$i)}}
510
+
511
+ return element bf:Instance {element bf:instanceTitle{
512
+ $instance-types,$instance-types1,
513
+ element bf:Title{ $instance-title}},
514
+ mbshared:generate-simple-property($d, "instance"),
515
+ $derivedFrom
516
+ }
517
+ };
518
+
519
+ (:~
520
+ : This is the function generates instance resources from publication data
521
+ : (first of: 260|261|262|264|300 )
522
+ :
523
+ : @param $d element is the MARCXML 260 or substitute
524
+ : @param $workID uri for the derivedfrom
525
+ : @return bf:* as element()
526
+ :)
527
+ declare function mbshared:generate-instance-from260(
528
+ $d as element(marcxml:datafield),
529
+ $workID as xs:string
530
+ ) as element ()
531
+ {
532
+ let $derivedFrom:=
533
+ element bf:derivedFrom {
534
+
535
+ (: attribute rdf:resource{fn:concat($workID,fn:normalize-space(fn:string($d/../marcxml:controlfield[@tag eq "001"])))}:)
536
+ attribute rdf:resource{fn:concat($workID,".marcxml.xml")}
537
+ }
538
+ let $instance-title :=
539
+ for $titles in $d/../marcxml:datafield[fn:matches(@tag,"(245|246|247|222|242|210)")]
540
+ for $t in $titles
541
+ return mbshared:get-title($t,"instance")
542
+
543
+ let $resp-statement880:= mbshared:generate-880-label($d/../marcxml:datafield[@tag = "245"][marcxml:subfield[@code="c"]],"responsibilityStatement")
544
+ let $resp-statement:=
545
+ for $r in $d/../marcxml:datafield[@tag = "245"]/marcxml:subfield[@code="c"]
546
+ return
547
+ if (fn:contains($r,"=")) then
548
+ fn:substring-before(fn:normalize-space($r),"=")
549
+ else
550
+ fn:normalize-space($r)
551
+ let $edition-instances:=
552
+ for $e in $d/../marcxml:datafield[@tag eq "250"][fn:not(1)]
553
+ return
554
+ (mbshared:generate-instance-from250($e,$workID),
555
+ element bf:relatedInstance {
556
+ element bf:Instance {
557
+ $instance-title,
558
+
559
+ $derivedFrom ,
560
+ (element bf:edition {marc2bfutils:clean-string($e/marcxml:subfield[@code="a"])},
561
+ if ($e/marcxml:subfield[@code="b"]) then element bf:editionResponsibility {fn:string($e/marcxml:subfield[@code="b"])}
562
+ else ()
563
+ )
564
+ }
565
+ }
566
+ )
567
+ let $edition-880:= for $ed in $d/../marcxml:datafield[@tag = "250"][marcxml:subfield[@code="a"]]
568
+ return mbshared:generate-880-label($ed,"edition")
569
+ let $publication:=
570
+ if (fn:matches($d/@tag, "(260|264)")) then
571
+ for $pub in $d/../marcxml:datafield[fn:matches(@tag, "(260|264)")]
572
+ return mbshared:generate-publication($pub)
573
+ else if (fn:matches($d/@tag, "(261|262)")) then mbshared:generate-26x-pub($d)
574
+ else ()
575
+
576
+
577
+ let $physMapData :=
578
+ (
579
+ for $i in $d/../marcxml:datafield[@tag eq "034"]/marcxml:subfield[@code eq "a"]
580
+
581
+ return element bf:cartographicScale {
582
+ if (fn:string($i)="a") then "Linear scale"
583
+ else if (fn:string($i)="b") then "Angular scale" else if (fn:string($i)="z") then "Other scale type" else "invalid"
584
+ }
585
+ ,
586
+ for $i in $d/../marcxml:datafield[@tag eq "034"]/marcxml:subfield[@code eq "b" or @code eq "c"]
587
+ return element bf:cartographicScale { fn:string($i)},
588
+
589
+ for $i in $d/../marcxml:datafield[@tag eq "255"]/marcxml:subfield[@code eq "a"]
590
+ return element bf:cartographicScale {fn:string($i)},
591
+
592
+ for $i in $d/../marcxml:datafield[@tag eq "255"]/marcxml:subfield[@code eq "b"]
593
+ return element bf:cartographicProjection {fn:string($i)},
594
+
595
+ for $i in $d/../marcxml:datafield[@tag eq "255"]/marcxml:subfield[@code eq "c"]
596
+ return element bf:cartographicCoordinates {fn:string($i)},
597
+
598
+ if ( $d/../marcxml:datafield[@tag eq "034"]/marcxml:subfield[@code eq "d" or @code eq "e" or @code eq "f" or @code eq "g"] ) then
599
+ element bf:cartographicCoordinates {fn:concat(fn:string-join($d/../marcxml:datafield[@tag eq "034"]/marcxml:subfield[@code eq "d" or @code eq "e" or @code eq "f" or @code eq "g"], '° '),'°')}
600
+ else ()
601
+ )
602
+
603
+ let $leader:=fn:string($d/../marcxml:leader)
604
+
605
+ let $leader7:=fn:substring($leader,8,1)
606
+
607
+ let $leader19:=fn:substring($leader,20,1)
608
+ let $instance-types:= mbshared:get-instanceTypes($d/ancestor::marcxml:record)
609
+
610
+ let $instance-types:=
611
+ for $i in fn:distinct-values($instance-types)
612
+ return element rdf:type { attribute rdf:resource { fn:concat("http://bibframe.org/vocab/" ,$i)}}
613
+
614
+ let $issuance:=
615
+ if (fn:matches($leader7,"(a|c|d)")) then "monographic"
616
+ else if ($leader7="b") then "continuing"
617
+ else if ($leader7="m" and fn:matches($leader19,"(a|b|c)")) then "multipart monograph"
618
+ else if ($leader7='m' and $leader19=' ') then "single unit"
619
+ else if ($leader7='i') then "integrating resource"
620
+ else if ($leader7='s') then "serial"
621
+ else ()
622
+ let $issuance :=
623
+ if ($issuance) then
624
+ element bf:modeOfIssuance {$issuance}
625
+ else ()
626
+ let $physform:= for $s in $d/../marcxml:datafield[@tag = "020"]/marcxml:subfield[@code="q"]
627
+ return marc2bfutils:clean-string(fn:normalize-space($s))
628
+
629
+
630
+ (:if ( $d/../marcxml:datafield[@tag = "020"][marcxml:subfield[@code="q"]]) then
631
+ marc2bfutils:clean-string(fn:normalize-space($d/../marcxml:datafield[@tag eq "020"]/marcxml:subfield[@code="q"]))
632
+ else ():)
633
+ let $physicalForm:=
634
+ for $form in $physform
635
+ return
636
+ if (fn:matches($form,"(pbk|softcover)","i")) then
637
+ element bf:format { "paperback"}
638
+ else if (fn:matches($form,"(hbk|hdbk|hardcover|hc|hard)","i") ) then
639
+ element bf:format {"hardback"}
640
+ else if (fn:matches($form,"(ebook|eresource|e-isbn|ebk)","i") ) then
641
+ element bf:format {"electronic resource"}
642
+ else if (fn:contains($form,"lib. bdg.") ) then
643
+ element bf:format { "library binding" }
644
+ else
645
+ ()
646
+
647
+ let $color:= if ($d/ancestor::marcxml:record/marcxml:controlfield[@tag="007"]) then
648
+ for $c in $d/ancestor::marcxml:record/marcxml:controlfield[@tag="007"][fn:matches(fn:substring(marcxml:record/marcxml:controlfield[@tag="007"],1,1) ,"(a|c|d|g|h|k|m|v)")]
649
+ let $colorcode:= if ( fn:substring($c,1,1)="h") then
650
+ fn:substring($c,9,1)
651
+ else
652
+ fn:substring($c,4,1)
653
+ return if ($colorcode= "a") then "One color"
654
+ else if ($colorcode= "b") then "Black-and-white"
655
+ else if ($colorcode= "c") then "Multicolored"
656
+ else if ($colorcode= "g") then "Gray scale"
657
+ else if ($colorcode= "h") then "Hand colored"
658
+ else if ($colorcode= "m") then "Mixed"
659
+ else if ($colorcode= "n") then "Not applicable"
660
+ else if ($colorcode= "u") then "Unknown"
661
+ else ()
662
+ else ()
663
+ let $color:= if ($color) then
664
+ element bf:colorContent {$color}
665
+ else ()
666
+ let $aspect:= if ($d/ancestor::marcxml:record/marcxml:controlfield[@tag="007"] )then
667
+ for $a in $d/ancestor::marcxml:record/marcxml:controlfield[@tag="007"][ fn:substring(text(),1,1)="m"]
668
+ let $aspectcode:= fn:substring($a,5,1)
669
+ return if ($aspectcode= "a" ) then "Standard sound aperture (reduced frame)"
670
+ else if ($aspectcode= "b") then "Nonanamorphic (wide-screen)"
671
+ else if ($aspectcode= "c") then "3D"
672
+ else if ($aspectcode= "d") then "Anamorphic (wide-screen)"
673
+ else if ($aspectcode= "e") then "Other wide-screen format"
674
+ else if ($aspectcode= "f") then "Standard silent aperture (full frame)"
675
+ else if ($aspectcode= "u") then "Unknown"
676
+ else ()
677
+ else ()
678
+ let $aspect:= for $a in $aspect
679
+ return element bf:aspectRatio {$aspect}
680
+
681
+ let $sound:=
682
+ if ($d/ancestor::marcxml:record/marcxml:controlfield[@tag="007"]) then
683
+ for $s in $d/ancestor::marcxml:record/marcxml:controlfield[@tag="007"][fn:matches(fn:substring(text(),1,1) ,"(c|g|m|v)")]
684
+ let $cf007-6:= if (fn:substring($s,1,1)="c") then "" else fn:substring($s,7,1)
685
+ return marc2bfutils:generate-soundContent( fn:substring($s,6,1), $cf007-6 )
686
+ else ()
687
+ let $sound:=
688
+ for $s in $sound[fn:string(.)!=""]
689
+ return element bf:soundContent {$s}
690
+
691
+
692
+ let $holdings := mbshared:generate-holdings($d/ancestor::marcxml:record, $workID)
693
+
694
+ let $instance-identifiers :=
695
+ (
696
+ mbshared:generate-identifiers($d/ancestor::marcxml:record,"instance")
697
+ )
698
+
699
+ let $general-notes := mbshared:generate-500notes($d/ancestor::marcxml:record, "instance")
700
+ let $standalone-880s:=mbshared:generate-standalone-880( $d/ancestor::marcxml:record ,"instance")
701
+ (:337, 338::)
702
+ let $physdesc := mbshared:generate-physdesc($d/ancestor::marcxml:record,"instance")
703
+
704
+ let $i504:=
705
+ for $i in $d/../marcxml:datafield[@tag="504"]
706
+ let $b:= if ($i/marcxml:subfield[@code="b"]) then
707
+ fn:concat("References: ", fn:string($i/marcxml:subfield[@code="b"]))
708
+ else ()
709
+ return
710
+ element bf:supplementaryContentNote {
711
+ fn:normalize-space(
712
+ fn:concat(fn:string($i/marcxml:subfield[@code="a"])," ", $b)
713
+ )
714
+ }
715
+ let $instance-relateds := mbshared:related-works($d/ancestor::marcxml:record,$workID,"instance")
716
+
717
+
718
+ let $instance-simples:= (:all but identifiers:)
719
+ ( mbshared:generate-simple-property($d/../marcxml:datafield[@tag="300"][1],"instance"),
720
+ for $i in $d/../marcxml:datafield[fn:not(fn:matches(@tag,"^0[1-9]")) ][@tag!="300"]
721
+ return mbshared:generate-simple-property($i,"instance")
722
+ )
723
+
724
+
725
+ return
726
+ element bf:Instance {
727
+ $instance-types,
728
+ $instance-title,
729
+
730
+ $resp-statement880,
731
+ $publication,
732
+ $edition-880,
733
+ $physMapData,
734
+ $physicalForm,
735
+ $color,
736
+ $aspect,
737
+ $sound,
738
+ $issuance,
739
+ $instance-relateds,
740
+ $instance-simples,
741
+ $general-notes,
742
+ $i504,
743
+ $instance-identifiers,
744
+ $physdesc,
745
+ $standalone-880s,
746
+ element bf:instanceOf {
747
+ attribute rdf:resource {$workID}
748
+ },
749
+ $derivedFrom,
750
+ $holdings
751
+ }
752
+ };
753
+
754
+ (:~
755
+ : This is the function generates other language labels from non-parallel 880s
756
+ : 880 with $6 containing 00: [tag]-00
757
+ : @param $marcxml element is the whole record tag *
758
+ : @return bf:* as element()
759
+ :
760
+ :)
761
+ declare function mbshared:generate-standalone-880
762
+ (
763
+ $marcxml as element(marcxml:record),
764
+ $domain as xs:string
765
+ ) as element ()*
766
+ {
767
+
768
+ if ($marcxml/marcxml:datafield[@tag='880'][fn:matches(marcxml:subfield[@code="6"],"^[0-9]{3}-00")] ) then
769
+ let $nodes:= ($mbshared:simple-properties//node[@domain=$domain],
770
+ $mbshared:addl-880-nodes//node[@domain=$domain])
771
+ let $taglist := fn:concat("(",fn:string-join(fn:distinct-values($nodes//@tag),"|"),")")
772
+ let $lang := fn:substring(fn:string($marcxml/marcxml:controlfield[@tag="008"]), 36, 3)
773
+ let $scr := fn:tokenize($marcxml/marcxml:subfield[@code="6"],"/")[2]
774
+ let $xmllang:= mbshared:generate-xml-lang($scr, $lang)
775
+
776
+ return
777
+
778
+ for $d in $marcxml/marcxml:datafield[@tag='880'][fn:matches(marcxml:subfield[@code="6"],"^[0-9]{3}-00$")]
779
+ let $tag-to-convert:= fn:substring($d/marcxml:subfield[@code="6"],1,3)
780
+
781
+ for $node880 in $nodes[fn:string(@tag)= $tag-to-convert]
782
+ let $return-codes:=
783
+ if ($node880/@sfcodes) then fn:string($node880/@sfcodes) else "a"
784
+
785
+ return element {fn:concat("bf:",fn:string($node880/@property))} {
786
+ if ($xmllang) then attribute xml:lang {$xmllang} else (),
787
+ fn:string($d/marcxml:subfield[fn:matches(@code,$return-codes)]),
788
+ fn:string($d/marcxml:subfield[@code="a"])
789
+ }
790
+
791
+ else
792
+ ()
793
+
794
+ };
795
+
796
+ (:~
797
+ : This is the function generates other language authlabel or label from associated 880s
798
+ : name, subject, title, authlabel; others: label
799
+ : if $6 on any tag =880-##, then go looking for the matching 880
800
+ : Will there ever only be one 880 per other field? Should this loop?
801
+ :
802
+ : @param $datafield element is the tag that may have an 880
803
+ : @param $node-name string is the type of datafield, name, subject, title
804
+ : @return bf:* as element()
805
+ :
806
+ :)
807
+ declare function mbshared:generate-880-label
808
+ (
809
+ $d as element(marcxml:datafield)*,
810
+ $node-name as xs:string
811
+ ) as element ()*
812
+ {
813
+
814
+ if (fn:starts-with($d/marcxml:subfield[@code="6"],"880")) then
815
+
816
+ let $hit-num := fn:substring(fn:tokenize($d/marcxml:subfield[@code="6"],'-')[2],1,2)
817
+
818
+ let $lang := fn:substring(fn:string($d/../marcxml:controlfield[@tag="008"]), 36, 3)
819
+
820
+ let $this-tag:= fn:string($d/@tag)
821
+ let $hit-num:=fn:tokenize($d/marcxml:subfield[@code="6"],"-")[2]
822
+ let $match:=$d/../marcxml:datafield[@tag="880" and fn:starts-with(marcxml:subfield[@code="6"] , fn:concat($this-tag ,"-", $hit-num ))]
823
+
824
+ let $scr := fn:tokenize($match/marcxml:subfield[@code="6"],"/")[2]
825
+ let $xmllang:= mbshared:generate-xml-lang($scr, $lang)
826
+
827
+ return
828
+
829
+ if ($node-name="name") then
830
+ element bf:authorizedAccessPoint {
831
+ attribute xml:lang {$xmllang},
832
+
833
+ if ($d/@tag!="534") then
834
+ marc2bfutils:clean-string(fn:string-join($match/marcxml:subfield[@code="a" or @code="b" or @code="c" or @code="d" or @code="q"] , " "))
835
+ else
836
+ marc2bfutils:clean-string($match/marcxml:subfield[@code="a"])
837
+ }
838
+ else if ($node-name="title") then
839
+ let $subfs :=
840
+ if ( fn:matches($d/@tag, "(130|210|222|240|245|242|243|246|490|630|730|740|830)") ) then
841
+ "(a|b|f|h|k|n|p)"
842
+ else
843
+ "(t|f|k|m|n|p|s)"
844
+ return
845
+ element bf:titleValue {
846
+ attribute xml:lang {$xmllang},
847
+ marc2bfutils:clean-title-string(fn:replace(fn:string-join($match/marcxml:subfield[fn:matches(@code,$subfs)] ," "),"^(.+)/$","$1"))
848
+ }
849
+ else if ($node-name="subject") then
850
+ element bf:authorizedAccessPoint{
851
+ attribute xml:lang {$xmllang},
852
+ marc2bfutils:clean-string(fn:string-join($match/marcxml:subfield[fn:not(@code="6")], " "))
853
+ }
854
+ else if ($node-name="place") then
855
+ for $sf in $match/marcxml:subfield[@code="a"]
856
+ let $text:= marc2bfutils:clean-string(fn:string($sf))
857
+
858
+ return (:inside bf:Place:)
859
+ element bf:label {
860
+ attribute xml:lang {$xmllang} ,
861
+ $text
862
+ }
863
+
864
+ else if ($node-name="provider") then
865
+ for $sf in $match/marcxml:subfield[@code="b"]
866
+ return
867
+ element bf:label {
868
+ attribute xml:lang {$xmllang},
869
+ marc2bfutils:clean-string(fn:string($sf))
870
+ }
871
+
872
+ else if ($node-name="responsibilityStatement") then
873
+ for $sf in $match/marcxml:subfield[@code="c"]
874
+ return
875
+ element bf:responsibilityStatement {
876
+ attribute xml:lang {$xmllang},
877
+ fn:string($sf)
878
+ }
879
+ else if ($node-name="providerDate") then
880
+ for $sf in $match/marcxml:subfield[@code="c"]
881
+ return
882
+ element bf:providerDate {
883
+ attribute xml:lang {$xmllang},
884
+ marc2bfutils:clean-string(fn:string($sf))
885
+ }
886
+ else
887
+ element { fn:concat("bf:",$node-name)} { attribute xml:lang {$xmllang} ,
888
+ fn:string($match/marcxml:subfield[@code="a"])
889
+ }
890
+ (:not 880:)
891
+ else ()
892
+
893
+ };
894
+
895
+
896
+ (:~
897
+ : This is the function generates 0xx data for instance or work, based on mappings in $work-identifiers
898
+ : and $instance-identifiers. Returns subfield $a,y,z,m,l,2,b,q
899
+ :
900
+ :: @param $marcxml element is the marcxml record
901
+ : @param $domain string is the "work" or "instance"
902
+ : skip isbn; do it on generate-instance from isbn, since it's a splitter and you don't want multiple per instance
903
+ : @return bf:* as element()
904
+ :)
905
+ declare function mbshared:generate-identifiers(
906
+ $marcxml as element(marcxml:record),
907
+ $domain as xs:string
908
+ ) as element ()*
909
+ {
910
+ let $identifiers:=
911
+ $mbshared:simple-properties//node[@domain=$domain][@group="identifiers"]
912
+
913
+ let $taglist:= fn:concat("(",fn:string-join(fn:distinct-values($identifiers//@tag),"|"),")")
914
+
915
+
916
+ let $bfIdentifiers :=
917
+ (:for $id in $identifiers[fn:not(@ind1)][@domain=$domain] (\:all but 024 and 028:\)
918
+ return
919
+ for $this-tag in $marcxml/marcxml:datafield[@tag eq $id/@tag] :)
920
+ (:for each matching marc datafield:)
921
+
922
+ (:invert the for loops for speed: 2014-03-20 :)
923
+ for $this-tag in $marcxml/marcxml:datafield[fn:matches( $taglist,fn:string(@tag) )]
924
+ return
925
+ for $id in $identifiers[fn:not(@ind1)][@domain=$domain][@tag=$this-tag/@tag] (:all but 024 and 028:)
926
+
927
+ (:if contains subprops, build class for $a else just prop w/$a:)
928
+ let $cancels:= for $sf in $this-tag/marcxml:subfield[fn:matches(@code,"(m|y|z)")]
929
+ return element {fn:concat("bf:",fn:string($id/@property)) }{
930
+ mbshared:handle-cancels($this-tag, $sf, fn:string($id/@property))
931
+ }
932
+ return (:need to construct blank node if there's no uri or there are qualifiers/assigners :)
933
+ if (fn:not($id/@uri) or $this-tag/marcxml:subfield[fn:matches(@code,"(b|q|2)")] or $this-tag[@tag="037"][marcxml:subfield[@code="c"]]
934
+ (:canadian stuff is not in id:)
935
+ or $this-tag[@tag="040"][fn:starts-with(fn:normalize-space(fn:string(marcxml:subfield[@code="a"])),'Ca')]
936
+ (:parenthetical in $a is idqualifier:)
937
+ or $this-tag/marcxml:subfield[@code="a"][fn:matches(text(),"^.+\(.+\).+$")])
938
+ then
939
+ (element {fn:concat("bf:",fn:string($id/@property)) }{
940
+ element bf:Identifier{
941
+ element bf:identifierScheme {
942
+ attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/identifiers/", fn:string($id/@property))}
943
+ },
944
+ if ($this-tag/marcxml:subfield[@code="a"]) then
945
+ if ( $this-tag/marcxml:subfield[@code="a"][fn:matches(text(),"^.+\(.+\).+$")]) then
946
+ let $val:=fn:replace($this-tag/marcxml:subfield[@code="a"],"(.+\()(.+)(\).+)","$1")
947
+ return element bf:identifierValue { fn:substring($val,1, fn:string-length($val)-1)}
948
+ else
949
+ element bf:identifierValue { fn:string($this-tag/marcxml:subfield[fn:matches(@code,$id/@sfcodes)][1]) }
950
+ else (),
951
+ for $sub in $this-tag/marcxml:subfield[@code="b" or @code="2"]
952
+ return element bf:identifierAssigner { fn:string($sub)},
953
+ for $sub in $this-tag/marcxml:subfield[@code="q" ][$this-tag/@tag!="856"]
954
+ return element bf:identifierQualifier {fn:string($sub)},
955
+ for $sub in $this-tag/marcxml:subfield[@code="a"][fn:matches(text(),"^.+\(.+\).+$")]
956
+ return element bf:identifierQualifier { fn:replace($sub,"(.+\()(.+)(\).+)","$2")},
957
+ for $sub in $this-tag[@tag="037"]/marcxml:subfield[@code="c"]
958
+ return element bf:identifierQualifier {fn:string($sub)}
959
+ }
960
+ },
961
+ $cancels
962
+ )
963
+ else (: not @code,"(b|q|2) , contains uri :)
964
+ ( mbshared:generate-simple-property($this-tag,$domain ) ,
965
+ $cancels
966
+ )(: END OF not @code,"(b|q|2), end of tags matching ids without @ind1:)
967
+
968
+ (:---------------------------------------- 024 and 028 , where ind1 counts----------------------------------------:)
969
+ (:024 had a z only; no $a: bibid;17332794:)
970
+ let $id024-028:=
971
+ for $this-tag at $x in $marcxml/marcxml:datafield[fn:matches(@tag,"(024|028)")][marcxml:subfield[@code="a" or @code="z"]]
972
+ let $this-id:= $identifiers[@tag=$this-tag/@tag][@ind1=$this-tag/@ind1] (: i1=7 has several ?:)
973
+ return
974
+ if ($this-id) then(: if there are any 024/028s on this record in this domain (work/instance):)
975
+ let $scheme:=
976
+ if ($this-tag/@ind1="7") then (:use the contents of $2 for the name: :)
977
+ fn:string($this-tag[@ind1=$this-id/@ind1]/marcxml:subfield[@code="2"])
978
+ else if ($this-tag/@ind1="8") then
979
+ "unspecified"
980
+ else (:use the $id name:)
981
+ fn:string($this-id[@tag=$this-tag/@tag][@ind1=$this-tag/@ind1]/@property)
982
+ let $property-name:=
983
+ (:unmatched scheme in $2:)
984
+ if ( ($this-tag/@ind1="7" and fn:not(fn:matches(fn:string($this-tag/marcxml:subfield[@code="2"]),"(ansi|doi|iso|istc|iswc|local)")))
985
+ or $this-tag/@ind1="8" ) then
986
+ "bf:identifier"
987
+ else fn:concat("bf:", $scheme)
988
+
989
+ let $cancels:=
990
+ for $sf in $this-tag/marcxml:subfield[fn:matches(@code,"z")]
991
+ return element {$property-name} { mbshared:handle-cancels($this-tag, $sf, $scheme)}
992
+
993
+ (:if 024 has a c, b, q, it needs a class else just prop w/$a Zs are handled in handle-cancels :)
994
+ return
995
+ ( if ( fn:not($this-tag/marcxml:subfield[@code="z"]) and ($this-tag/marcxml:subfield[@code="a"] and
996
+ ( fn:contains(fn:string($this-tag/marcxml:subfield[@code="c"]), "(") or
997
+ $this-tag/marcxml:subfield[@code="q" or @code="b" or @code="2"]
998
+ )
999
+
1000
+ or
1001
+ fn:not($this-id/@uri) or
1002
+ $scheme="unspecified" )
1003
+ ) then
1004
+ let $value:= if ($this-tag/marcxml:subfield[@code="a"] or $this-tag/marcxml:subfield[@code="d"]) then
1005
+ if ($this-tag/marcxml:subfield[@code="d"]) then
1006
+ element bf:identifierValue { fn:string-join($this-tag/marcxml:subfield[fn:matches(@code,"(a|d)")],"-") }
1007
+ else
1008
+ element bf:identifierValue{ fn:string($this-tag/marcxml:subfield[@code="a"])}
1009
+ else ()
1010
+ return
1011
+ element {$property-name} {
1012
+ element bf:Identifier{
1013
+ element bf:identifierScheme { attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/identifiers/", $scheme)} },
1014
+ $value,
1015
+ for $sub in $this-tag/marcxml:subfield[@code="b"]
1016
+ return element bf:identifierAssigner{fn:string($sub)},
1017
+ for $sub in $this-tag/marcxml:subfield[@code="q"]
1018
+ return element bf:identifierQualifier {fn:string($sub)}
1019
+ }
1020
+ }
1021
+ else (:not c,q,b 2 . (z yes ) :)
1022
+ let $property-name:= (:024 had a z only; no $a: bibid;17332794:)
1023
+ (:unmatched scheme in $2:)
1024
+ if ($this-tag/@ind1="7" and fn:not(fn:matches( fn:string($this-tag/marcxml:subfield[@code="2"]),"(ansi|doi|iso|isan|istc|iswc|local)" ))) then
1025
+ "bf:identifier"
1026
+ else fn:concat("bf:", $scheme)
1027
+
1028
+ return
1029
+ ( if ( $this-tag/marcxml:subfield[fn:matches(@code,"a")]) then
1030
+ for $s in $this-tag/marcxml:subfield[fn:matches(@code,"a")]
1031
+ return element {$property-name} {element bf:Identifier {
1032
+ element bf:identifierValue { fn:normalize-space(fn:string($s)) }
1033
+ }
1034
+ }
1035
+ else ()
1036
+ )
1037
+ , $cancels
1038
+ )
1039
+ else () (:end 024 / 028 none found :)
1040
+
1041
+
1042
+ return
1043
+ for $bfi in ($bfIdentifiers,$id024-028)
1044
+ return
1045
+ (: if (fn:name($bfi) eq "bf:Identifier") then
1046
+ element bf:identifier {$bfi}
1047
+ else:)
1048
+ $bfi
1049
+
1050
+ };
1051
+ (:~
1052
+ : This is the function that handles $0 in various fields
1053
+ : @param $sys-num element is the marc subfield $0
1054
+
1055
+ : @return element() either bf:systemNumber or bf:hasAuthority with uri
1056
+ :)
1057
+
1058
+ declare function mbshared:handle-system-number( $sys-num as element(marcxml:subfield) )
1059
+ {
1060
+ if (fn:starts-with(fn:normalize-space($sys-num),"(uri)")) then
1061
+ let $id:=fn:normalize-space(fn:tokenize(fn:string($sys-num),"\)")[2] )
1062
+ return element bf:hasAuthority {attribute rdf:resource{$id} }
1063
+ else
1064
+ if (fn:contains(fn:normalize-space($sys-num),"http://")) then
1065
+ let $id:=fn:normalize-space(fn:concat("http://",fn:substring-after(fn:string($sys-num),"http://") ) )
1066
+ return element bf:hasAuthority {attribute rdf:resource{$id} }
1067
+ else
1068
+ if (fn:starts-with(fn:normalize-space($sys-num),"(DE-588")) then
1069
+ let $id:=fn:normalize-space(fn:tokenize(fn:string($sys-num),"\)")[2] )
1070
+ return element bf:hasAuthority {attribute rdf:resource{fn:concat("http://d-nb.info/gnd/",$id)} }
1071
+ else if ( fn:matches(fn:normalize-space($sys-num), "$\(OCoLC\)" ) ) then
1072
+
1073
+ let $iStr := marc2bfutils:clean-string(fn:replace($sys-num, "\(OCoLC\)", ""))
1074
+ return element bf:systemNumber { attribute rdf:resource {fn:concat("http://www.worldcat.org/oclc/",fn:replace($iStr,"(^ocm|^ocn)","")) }}
1075
+ else
1076
+ element bf:systemNumber { element bf:Identifier {
1077
+ element bf:identifierValue {fn:string($sys-num)}
1078
+ }
1079
+ }
1080
+ };
1081
+ (:~
1082
+ : This is the function generates full Identifier classes from m,y,z cancel/invalid identifiers
1083
+ : @param $this-tag element is the marc data field
1084
+ : @param $sf subfield element
1085
+ : @param $scheme identifier name (lccn etc.)
1086
+ : @return bf:Identifier as element()
1087
+ :)
1088
+ declare function mbshared:handle-cancels($this-tag, $sf, $scheme)
1089
+ {
1090
+ if ($this-tag[fn:matches(@tag,"(010|015|016|017|020|024|027|030|035|088)")] and $sf[@code="z"]) then
1091
+ element bf:Identifier {
1092
+ element bf:identifierScheme { attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/identifiers/", $scheme)} },
1093
+ element bf:identifierValue { fn:normalize-space(fn:string($sf))},
1094
+ if ($this-tag[@tag="022"] and $sf[@code="y"]) then
1095
+ element bf:identifierStatus{"incorrect"}
1096
+ else if ($this-tag[@tag="022"] and $sf[@code="z"]) then
1097
+ element bf:identifierStatus{"canceled/invalid"}
1098
+ else if ($this-tag[@tag="022"] and $sf[@code="m"]) then
1099
+ element bf:identifierStatus {"canceled/invalid"}
1100
+ else if ($this-tag[fn:matches(@tag,"(010|015|016|017|020|024|027|030|035|088)")] and $sf[@code="z"] ) then
1101
+ element bf:identifierStatus{"canceled/invalid"}
1102
+ else
1103
+ ()
1104
+ }
1105
+ else if ( ($this-tag[@tag="022"] and $sf[fn:matches(@code,"m|y|z")]) ) then
1106
+ element bf:Identifier {
1107
+ element bf:identifierScheme { attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/identifiers/", $scheme)} },
1108
+ element bf:identifierValue { fn:normalize-space(fn:string($sf))},
1109
+ if ($sf[@code="y"]) then
1110
+ element bf:identifierStatus{"incorrect"}
1111
+ else if ( $sf[@code="z"]) then
1112
+ element bf:identifierStatus{"canceled/invalid"}
1113
+ else if ( $sf[@code="m"]) then
1114
+ element bf:identifierStatus {"canceled/invalid"}
1115
+ else
1116
+ ()
1117
+ }
1118
+ else ()
1119
+ };
1120
+ (:~
1121
+ : This is the function generates publication data for 261, 262
1122
+ :
1123
+
1124
+ :)
1125
+ declare function mbshared:generate-26x-pub
1126
+ (
1127
+ $d as element(marcxml:datafield)
1128
+ ) as element ()*
1129
+ {
1130
+
1131
+ (: 261 $f is place $a is producer name, $d is date,
1132
+ 262 is $a place, $b publisher $c date.:)
1133
+
1134
+ element bf:publication {
1135
+ element bf:Provider {
1136
+ for $pub in $d[@tag="261"]/marcxml:subfield[@code="a"][1] | $d[@tag="262"]/marcxml:subfield[@code="b"][1]
1137
+ return
1138
+ element bf:providerName {
1139
+ element bf:Organization {
1140
+ element bf:label {marc2bfutils:chopPunctuation(marc2bfutils:clean-string(fn:string($pub)),"")}
1141
+ }
1142
+ }
1143
+ ,
1144
+ for $pub in $d[@tag="261"]/marcxml:subfield[@code="f"][1] | $d[@tag="262"]/marcxml:subfield[@code="a"][1]
1145
+ return
1146
+ element bf:providerPlace {element bf:Place {
1147
+ element bf:label {
1148
+ marc2bfutils:chopPunctuation(marc2bfutils:clean-string(fn:string($pub)),"")}
1149
+ }
1150
+ }
1151
+ ,
1152
+ for $pub in $d[@tag="261"]/marcxml:subfield[@code="d"][1] | $d[@tag="262"]/marcxml:subfield[@code="c"][1]
1153
+ return
1154
+ element bf:providerDate {marc2bfutils:chopPunctuation(fn:string($pub),".")}
1155
+ }
1156
+ }
1157
+ };
1158
+ (:~
1159
+ : This is the function generates publication data for instance
1160
+ : Returns bf: node of elname
1161
+ : abc are repeatable!!! each repetition of b or c is another publication; should it be another instance????
1162
+ abc and def are parallel, so a and d are treated the same, etc, except the starting property name publication vs manufacture
1163
+ : @param $d element is the datafield 260 or 264
1164
+ : @param $resource string is the "work" or "instance"
1165
+ : @return bf:* element()
1166
+
1167
+ !!! work on ab abc bibid 468476
1168
+ !!! work on 880s in 260abc, efg
1169
+ :)
1170
+ declare function mbshared:generate-publication
1171
+ (
1172
+ $d as element(marcxml:datafield)
1173
+ ) as element ()*
1174
+ { (:first handle abc, for each b, set up a publication with any associated A's and Cs:)
1175
+ if ($d/marcxml:subfield[@code="b"]) then
1176
+
1177
+ for $pub at $x in $d/marcxml:subfield[@code="b"]
1178
+ let $propname :=
1179
+ if ($d/@tag="264" and $d/@ind2="3" ) then
1180
+ "bf:manufacture"
1181
+ else if ($d/@tag="264" and $d/@ind2="2" ) then
1182
+ "bf:distribution"
1183
+ else
1184
+ "bf:publication"
1185
+ (:if there's only one c, it applies to multiple ab's:)
1186
+ let $date:= if ($d/marcxml:subfield[@code="c"][$x]) then
1187
+ $d/marcxml:subfield[@code="c"][$x]
1188
+ else if ( $x gt 1 and $d/marcxml:subfield[@code="c"][$x - 1]) then
1189
+ $d/marcxml:subfield[@code="c"][$x - 1]
1190
+ else ()
1191
+ return
1192
+ element {$propname} {
1193
+ element bf:Provider {
1194
+ (:
1195
+ k-note: added call to clean-str here.
1196
+ We'll need to figure out where this is and
1197
+ isn't a problem
1198
+ :)
1199
+ element bf:providerName {
1200
+ element bf:Organization {
1201
+ element bf:label {marc2bfutils:chopPunctuation(marc2bfutils:clean-string(fn:string($pub)),"")},
1202
+ mbshared:generate-880-label($d,"provider")
1203
+ }
1204
+ }
1205
+ ,
1206
+ if ( $d/marcxml:subfield[@code="a"][$x]) then
1207
+ element bf:providerPlace {
1208
+ element bf:Place {
1209
+ element bf:label {
1210
+ marc2bfutils:chopPunctuation( marc2bfutils:clean-string($d/marcxml:subfield[@code="a"][$x]),"")},
1211
+ mbshared:generate-880-label($d,"place")
1212
+ }
1213
+ }
1214
+
1215
+ else (),
1216
+ if (fn:starts-with($date,"c")) then
1217
+ (:\D filters out "c" and other non-digits, but also ?, so switch to clean-string for now. may want "clean-date??:)
1218
+ element bf:copyrightDate {marc2bfutils:clean-string($date)}
1219
+ else if ( $date !="" and fn:not(fn:starts-with($date,"c") )) then
1220
+ ( element bf:providerDate {marc2bfutils:chopPunctuation($date,".")},
1221
+ mbshared:generate-880-label($d,"providerDate")
1222
+ )
1223
+ else ()
1224
+ (:if ($d/marcxml:subfield[@code="c"][$x] and fn:starts-with($d/marcxml:subfield[@code="c"][$x],"c") ) then
1225
+
1226
+ element bf:copyrightDate {marc2bfutils:clean-string($d/marcxml:subfield[@code="c"][$x])}
1227
+ else if ($d/marcxml:subfield[@code="c"][$x] and fn:not(fn:starts-with($d/marcxml:subfield[@code="c"][$x],"c") )) then
1228
+ element bf:providerDate {marc2bfutils:chopPunctuation($d/marcxml:subfield[@code="c"][$x],".")}
1229
+ else ():)
1230
+ }
1231
+ }
1232
+ (:there is no $b:)
1233
+ else if ($d/marcxml:subfield[fn:matches(@code,"(a|c)")]) then
1234
+ element bf:publication {
1235
+ element bf:Provider {
1236
+ for $pl in $d/marcxml:subfield[@code="a"]
1237
+ return element bf:providerPlace {
1238
+ element bf:Place {
1239
+ element bf:label {marc2bfutils:chopPunctuation(fn:string($pl),"")},
1240
+ mbshared:generate-880-label($d,"place")
1241
+ }
1242
+ },
1243
+
1244
+ for $pl in $d/marcxml:subfield[@code="c"]
1245
+ return
1246
+ if (fn:starts-with($pl,"c")) then
1247
+ element bf:providerDate {marc2bfutils:chopPunctuation($pl,".")}
1248
+ else
1249
+ element bf:copyrightDate {marc2bfutils:chopPunctuation($pl,".")}
1250
+ }
1251
+ }
1252
+ else (),
1253
+ (:handle $e,f,g like abc :)
1254
+ if ($d/marcxml:subfield[@code="e"]) then
1255
+ for $pub at $x in $d/marcxml:subfield[@code="e"]
1256
+ let $propname := "bf:manufacture"
1257
+ return
1258
+ element {$propname} {
1259
+ element bf:Provider {
1260
+ element bf:providerName {
1261
+ element bf:Organization {
1262
+ element bf:label {marc2bfutils:chopPunctuation(marc2bfutils:clean-string(fn:string($pub)),"")},
1263
+ mbshared:generate-880-label($d,"provider")
1264
+ }
1265
+ }
1266
+ ,
1267
+ if ( $d/marcxml:subfield[@code="f"][$x]) then
1268
+ element bf:providerPlace {
1269
+ element bf:Place {
1270
+ element bf:label { marc2bfutils:chopPunctuation( fn:string($d/marcxml:subfield[@code="f"][$x]),"")},
1271
+ mbshared:generate-880-label($d,"place")
1272
+ }
1273
+ }
1274
+ else (),
1275
+ if ($d/marcxml:subfield[@code="g"][$x]) then
1276
+ (element bf:providerDate {marc2bfutils:chopPunctuation($d/marcxml:subfield[@code="g"][$x],".")},
1277
+ mbshared:generate-880-label($d,"providerDate")
1278
+ )
1279
+ else if ($d/marcxml:subfield[@code="c"][$x]) then
1280
+ ( element bf:providerDate {marc2bfutils:chopPunctuation($d/marcxml:subfield[@code="c"][$x],".")},
1281
+ mbshared:generate-880-label($d,"providerDate")
1282
+ )
1283
+ else ()
1284
+ }
1285
+ }
1286
+ (:there is no $b:)
1287
+ else if ($d/marcxml:subfield[fn:matches(@code,"(e|f)")]) then
1288
+ element bf:publication {
1289
+ element bf:Provider {
1290
+ for $pl in $d/marcxml:subfield[@code="e"]
1291
+ return element bf:providerPlace {
1292
+ element bf:Place {
1293
+ element bf:label {marc2bfutils:chopPunctuation(fn:string($pl),"")},
1294
+ mbshared:generate-880-label($d,"place")
1295
+ }
1296
+ },
1297
+ for $pl in $d/marcxml:subfield[@code="g"]
1298
+ return (element bf:providerDate {marc2bfutils:chopPunctuation($pl,".")},
1299
+ mbshared:generate-880-label($d,"providerDate") )
1300
+ }
1301
+ }
1302
+
1303
+ else ()
1304
+
1305
+ };
1306
+ (:~
1307
+ : This is the function generates 337,338 data for instance or work, based on mappings in $physdesc-list
1308
+ : Returns bf: node of elname
1309
+ :
1310
+ : @param $marcxml element is the marcxml record
1311
+ : @param $resource string is the "work" or "instance"
1312
+ : @return bf:* element()
1313
+ :)
1314
+ declare function mbshared:generate-physdesc
1315
+ (
1316
+ $marcxml as element(marcxml:record),
1317
+ $resource as xs:string
1318
+ ) as element ()*
1319
+ {
1320
+ (
1321
+ (:---337,338:)
1322
+ if ($resource="instance") then
1323
+ ( (:-------------337----------------:)
1324
+ for $d in $marcxml/marcxml:datafield[@tag="337" ]
1325
+ let $src:=fn:string($d/marcxml:subfield[@code="2"])
1326
+
1327
+ return
1328
+ if ( $src="rdamedia" and $d/marcxml:subfield[@code="a"]) then
1329
+ for $s in $d/marcxml:subfield[@code="a"]
1330
+ let $media-code:=marc2bfutils:generate-mediatype-code(fn:string($s))
1331
+ return element bf:mediaCategory {attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/mediaTypes/",fn:encode-for-uri($media-code))}
1332
+ }
1333
+ else if ($d/marcxml:subfield[@code="a"]) then
1334
+ for $s in $d/marcxml:subfield[@code="a"]
1335
+ return element bf:mediaCategory {
1336
+ element bf:Category {
1337
+ element bf:label{fn:string($s)},
1338
+ element bf:categoryValue{fn:string($s)},
1339
+ element bf:categoryType{"media category"}
1340
+ }
1341
+ }
1342
+ else if ( $src="rdamedia" and $d/marcxml:subfield[@code="b"]) then
1343
+ for $s in $d/marcxml:subfield[@code="b"]
1344
+ return element bf:mediaCategory {attribute rdf:type {fn:concat("http://id.loc.gov/vocabulary/mediaTypes/",fn:encode-for-uri(fn:string($s)))}
1345
+ }
1346
+ else (),
1347
+ (:----------338-------------------:)
1348
+ for $d in $marcxml/marcxml:datafield[@tag="338"]
1349
+ let $src:=fn:string($d/marcxml:subfield[@code="2"])
1350
+
1351
+ return
1352
+ if ( $src="rdacarrier" and $d/marcxml:subfield[@code="a"]) then
1353
+ for $s in $d/marcxml:subfield[@code="a"]
1354
+ let $carrier-code:= marc2bfutils:generate-carrier-code(fn:string($s))
1355
+ return if ($carrier-code) then
1356
+ element bf:carrierCategory {attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/carriers/",fn:encode-for-uri($carrier-code))}
1357
+ }
1358
+ else element bf:carrierCategory { element bf:Category { element bf:categoryValue {fn:string($s)}}}
1359
+ else if ($d/marcxml:subfield[@code="a"]) then
1360
+ for $s in $d/marcxml:subfield[@code="a"]
1361
+ return element bf:carrierCategory {
1362
+ attribute rdf:resource {fn:concat("http://somecarrier.example.org/",
1363
+ fn:encode-for-uri(fn:string($s)))}
1364
+ }
1365
+ else if ( $src="rdacarrier" and $d/marcxml:subfield[@code="b"]) then
1366
+ for $s in $d/marcxml:subfield[@code="b"]
1367
+ return element bf:carrierCategory {attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/carriers/",fn:string($s))}
1368
+ }
1369
+ else (),
1370
+ (:---337, 338 end ---:)
1371
+ (: hyphens may also be inside the range! ex:
1372
+ (Mar. 21-27, 1996)- no. 30(Apr. 4-9, 1997) :)
1373
+ for $issuedate in $marcxml/marcxml:datafield[@tag="362"]
1374
+ let $subelement:=fn:string($issuedate/marcxml:subfield[@code="a"])
1375
+ return
1376
+ if ( $issuedate/@ind1="0" and fn:contains($subelement,"-") ) then
1377
+ let $first:=
1378
+ if ( fn:matches($subelement,"(.+\(.+-.+)-(.+\(.+\).+)") ) then
1379
+ fn:replace($subelement,"(.+\(.+-.+)-(.+\(.+\).+)","$1")
1380
+ else if (fn:contains($subelement,"-")) then
1381
+ fn:normalize-space( fn:substring-before($subelement,"-"))
1382
+ else $subelement
1383
+ let $last:= if ( fn:matches($subelement,"(.+\(.+-.+)-(.+\(.+\).+)")) then
1384
+ fn:replace($subelement,"(.+\(.+-.+)-(.+\(.+\).+)","$2")
1385
+ else if (fn:contains($subelement,"-")) then
1386
+ fn:normalize-space( fn:substring-after($subelement,"-"))
1387
+ else ()
1388
+ return (
1389
+ if ($first!="") then
1390
+ element bf:serialFirstIssue {$first }
1391
+ else (),
1392
+
1393
+ if ( $last!="") then
1394
+ element bf:serialLastIssue{ $last }
1395
+ else ()
1396
+ )
1397
+ else (:no hyphen or it's ind1=1:)
1398
+ (element bf:serialFirstIssue {
1399
+ fn:normalize-space( $subelement)
1400
+ },
1401
+ mbshared:generate-880-label($issuedate,"serialFirstIssue")
1402
+ ),
1403
+ for $d in $marcxml/marcxml:datafield[@tag="351"]
1404
+ return
1405
+ element bf:arrangement {
1406
+ element bf:Arrangement {
1407
+ mbshared:generate-simple-property($d,"arrangement")
1408
+ }
1409
+ }
1410
+ ) (:instance end:)
1411
+ else (: work-------------336----------------:)
1412
+ for $d in $marcxml/marcxml:datafield[@tag="336" ]
1413
+ let $src:=fn:string($d/marcxml:subfield[@code="2"])
1414
+
1415
+ return
1416
+ if ( $src="rdacontent" and $d/marcxml:subfield[@code="a"]) then
1417
+ for $s in $d/marcxml:subfield[@code="a"]
1418
+ let $content-code:=marc2bfutils:generate-content-code(fn:string($s))
1419
+ return element bf:contentCategory {attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/contentTypes/",fn:encode-for-uri($content-code))}
1420
+ }
1421
+ else if ($d/marcxml:subfield[@code="a"]) then
1422
+ for $s in $d/marcxml:subfield[@code="a"]
1423
+ return element bf:contentCategory {
1424
+ element bf:Category {
1425
+ element bf:categoryValue{fn:string($s)},
1426
+ element bf:categoryType{"content category"}
1427
+ }
1428
+ }
1429
+ else if ( $src="rdacontent" and $d/marcxml:subfield[@code="b"]) then
1430
+ for $s in $d/marcxml:subfield[@code="b"]
1431
+ return element bf:contentCategory {attribute rdf:type {fn:concat("http://id.loc.gov/vocabulary/contentTypes/",fn:encode-for-uri(fn:string($s)))}
1432
+ }
1433
+ else () ,
1434
+ for $node in $mbshared:simple-properties//node[fn:string(@domain)="contentcategory"]
1435
+ let $return-codes:=
1436
+ if ($node/@sfcodes) then fn:string($node/@sfcodes) else "a"
1437
+ for $s in $marcxml/marcxml:datafield[@tag=$node/@tag]/marcxml:subfield[fn:matches(@code,$return-codes)]
1438
+ return element bf:contentCategory {
1439
+ element bf:Category {
1440
+ element bf:categoryValue{fn:string($s)},
1441
+ element bf:categoryType{"content category"}
1442
+ }
1443
+ }
1444
+
1445
+ )
1446
+ };
1447
+
1448
+ (:~
1449
+ : This is the function generates isbn-based instance resources. (ie books???)
1450
+ : ntra 2013-03-13
1451
+ changed to just pass in the isbn string, in case it's not int hte data, plus marcxml:record instead of marcxml:subfield, for further processing
1452
+ and moved $instance (generating the rest of the instance from the 260 out
1453
+ : @param $d element is the 020 $a
1454
+ : @param $isbn-string is the isbn string; may have come from subfield or calculation
1455
+
1456
+ : @param $instance element bf:Instance is generated fromthe first 260
1457
+ : @return bf:* as element()
1458
+ :
1459
+ :work with this example, bibid 13891080
1460
+ :
1461
+ :)
1462
+ declare function mbshared:generate-instance-fromISBN(
1463
+ $d as element(marcxml:record),
1464
+ $isbn-set as element (bf:set),
1465
+ (:something needed to be a null instance???:)
1466
+ $instance as element (bf:Instance)?,
1467
+
1468
+ $workID as xs:string
1469
+ ) as element ()*
1470
+
1471
+ {
1472
+
1473
+ let $isbn-extra:=fn:normalize-space(fn:tokenize(fn:string($isbn-set/marcxml:subfield[1]),"\(")[2])
1474
+ let $volume:=
1475
+ (:too hard to parse :)
1476
+ (: if (fn:contains($isbn-extra,":")) then
1477
+ fn:replace(marc2bfutils:clean-string(fn:normalize-space(fn:tokenize($isbn-extra,":")[2])),"\)","")
1478
+ else:)
1479
+ fn:replace(marc2bfutils:clean-string(fn:normalize-space($isbn-extra)),"\)","")
1480
+ let $v-test:=
1481
+ fn:replace(marc2bfutils:clean-string(fn:normalize-space($isbn-extra)),"\)","")
1482
+
1483
+ let $volume-test:= ($v-test, fn:tokenize($v-test,":")[1],fn:tokenize($v-test,":")[2])
1484
+ let $volume-test:= fn:tokenize($v-test,":")[2]
1485
+
1486
+ let $volume-info-test:=
1487
+ if (fn:not(fn:empty($volume-test ))) then
1488
+ for $v in $volume-test
1489
+ for $content in $d/marcxml:datafield[@tag="505"]/marcxml:subfield[@code="a"]
1490
+ for $vol in fn:tokenize(fn:string($content),"--")[fn:contains(.,$v)][1]
1491
+ (:for $vol in fn:tokenize(fn:string($d/marcxml:datafield[@tag="505"]/marcxml:subfield[@code="a"]),"--")[fn:contains(.,$v)][1]:)
1492
+ return if (fn:contains($vol,$v)) then element bf:subtitle {fn:concat("experimental 505a matching to isbn:",$vol)} else ()
1493
+ else ()
1494
+
1495
+ let $volume-info:= ()
1496
+ (:bib id 467 has multiple matches for t 1: t 1, t 11, t12 etc:)
1497
+ (:if ($volume ) then
1498
+ for $vol in fn:tokenize(fn:string($d/marcxml:datafield[@tag="505"]/marcxml:subfield[@code="a"]),"--")[fn:contains(.,$volume)][1]
1499
+ return if (fn:contains($vol,$volume)) then element bf:subtitle {fn:concat("experimental 505a matching to isbn:",$vol)} else ()
1500
+ else ():)
1501
+
1502
+ let $physform:=
1503
+ if (fn:tokenize( $isbn-set/marcxml:subfield[1],"\(")[1]) then
1504
+ marc2bfutils:clean-string(fn:normalize-space(fn:tokenize($isbn-set/marcxml:subfield[1],"\(")[2]))
1505
+ else ()
1506
+
1507
+ let $physicalForm:=
1508
+ if (fn:matches($physform,"(pbk|softcover)","i")) then
1509
+ "paperback"
1510
+ else if (fn:matches($physform,"(hbk|hdbk|hardcover|hc|hard)","i") ) then
1511
+ "hardback"
1512
+ else if (fn:matches($physform,"(ebook|eresource|e-isbn|ebk)","i") ) then
1513
+ "electronic resource"
1514
+ else if (fn:contains($physform,"lib. bdg.") ) then
1515
+ "library binding"
1516
+
1517
+ else
1518
+ ()
1519
+
1520
+ (:9781555631185 (v. 4. print):)
1521
+ let $i-title := (:this already exists in the output?:)
1522
+ if ($d/marcxml:datafield[@tag = "245"]) then
1523
+ mbshared:get-title($d/marcxml:datafield[@tag = "245"], "instance")
1524
+ else
1525
+ ()
1526
+
1527
+
1528
+ let $extent-title :=
1529
+ if ($volume ne "") then
1530
+ for $t in $i-title
1531
+ return
1532
+ element bf:title {
1533
+ $t/@*,
1534
+ fn:normalize-space(fn:concat(xs:string($t), " (", $volume, ")"))
1535
+
1536
+ }
1537
+ else if ($physicalForm) then
1538
+ for $t in $i-title
1539
+ return
1540
+ element bf:title {
1541
+ $t/@*,
1542
+ fn:normalize-space(fn:concat(xs:string($t), " (", $physicalForm, ")"))
1543
+ }
1544
+ else if ($physform ne "") then
1545
+ for $t in $i-title
1546
+ return
1547
+ element bf:title {
1548
+ $t/@*,
1549
+ fn:normalize-space(fn:concat(xs:string($t), " (", $physform, ")"))
1550
+ }
1551
+ else
1552
+ ()
1553
+
1554
+
1555
+ let $clean-isbn:=
1556
+ for $item in $isbn-set/bf:isbn
1557
+ return marc2bfutils:clean-string(fn:normalize-space(fn:tokenize( fn:string($item),"\(")[1]))
1558
+
1559
+
1560
+ let $isbn :=
1561
+ for $i in $clean-isbn
1562
+ let $element-name :=
1563
+ if (fn:string-length($i) gt 11 ) then
1564
+ "bf:isbn13"
1565
+ else
1566
+ "bf:isbn10"
1567
+ return (
1568
+ element {$element-name} {
1569
+ attribute rdf:resource {fn:concat("http://isbn.example.org/",fn:normalize-space($i))}
1570
+ },
1571
+
1572
+ if ($element-name ="bf:isbn10" and $physicalForm!=() ) then
1573
+ element bf:isbn10 {
1574
+ element bf:Identifier {
1575
+ element bf:identifierValue {fn:normalize-space($i)},
1576
+ element bf:identifierScheme { attribute rdf:resource {"http://id.loc.gov/vocabulary/identifiers/isbn"} },
1577
+ element bf:identifierQualifier {fn:normalize-space($physicalForm)}
1578
+ }
1579
+ }
1580
+ else ()
1581
+
1582
+ )
1583
+
1584
+ let $instanceOf :=
1585
+ element bf:instanceOf {
1586
+ attribute rdf:resource {$workID}
1587
+ }
1588
+
1589
+ return
1590
+ element bf:Instance {
1591
+
1592
+ (: See extent-title above :)
1593
+ (: if ($volume) then element bf:title{ $volume} else (), :)
1594
+ $extent-title,
1595
+ $isbn,
1596
+ (:for $t in $extent-title
1597
+ return
1598
+ element bf:label {
1599
+ $t/@*,
1600
+ xs:string($t)
1601
+ },:)
1602
+ if ($physicalForm) then element bf:format {$physicalForm} else (),
1603
+ $volume-info,
1604
+
1605
+ (:not done yet: 2013-05-21 :)
1606
+ (: element bf:testvtest{$v-test},
1607
+ element bf:testvolume{$volume},
1608
+ element bf:testvolumetest{ $volume-test},:)
1609
+
1610
+ if ( fn:exists($instance) ) then
1611
+ (
1612
+ $instance/@*,
1613
+ if ($volume or $volume-info) then
1614
+ $instance/*[fn:not(fn:local-name()="title") and fn:not(fn:local-name()="extent")]
1615
+ else
1616
+ $instance/*
1617
+ )
1618
+ else
1619
+ $instanceOf
1620
+ }
1621
+
1622
+ };
1623
+ (:~
1624
+ : This is the function generates edition instance resources.
1625
+ : Makes a duplicate? I don't see anything different from the 260
1626
+ : @param $d element is each 250 after the first
1627
+ : @return bf:* as element()
1628
+ :)
1629
+ declare function mbshared:generate-instance-from250(
1630
+ $d as element(marcxml:datafield),
1631
+ $workID as xs:string
1632
+ ) as element ()*
1633
+ {
1634
+
1635
+ (:get the physical details:)
1636
+ (: We only ask for the first 260 :)
1637
+ let $instance := mbshared:generate-instance-from260($d/../marcxml:datafield[fn:matches(@tag, "(260|261|262|264|300)")][1], $workID)
1638
+
1639
+ let $instanceOf :=
1640
+ element bf:instanceOf {
1641
+ attribute rdf:resource {$workID}
1642
+ }
1643
+
1644
+ return
1645
+ element bf:Instance {
1646
+ (if ( fn:exists($instance) ) then
1647
+ (
1648
+ $instance/@*,
1649
+ $instance/*
1650
+ )
1651
+ else
1652
+ $instanceOf)
1653
+
1654
+ }
1655
+
1656
+ };
1657
+
1658
+ (:~
1659
+ : This is the function generates 856-based instance resources or annotations
1660
+ : 856 to resource is an instance, else annotation. Contributor link annotates 1xx uri
1661
+ :
1662
+ : @param $marcxml element is the whole record
1663
+ : @return bf:* as element()
1664
+ : contributor ex:13546156
1665
+
1666
+ :)
1667
+ declare function mbshared:generate-instance-from856(
1668
+ $d as element(marcxml:datafield),
1669
+ $workID as xs:string
1670
+ ) as element ()*
1671
+ {
1672
+ (:let $bibid:=$d/../marcxml:controlfield[@tag="001"]:)
1673
+ let $category:=
1674
+ if ( fn:contains(
1675
+ fn:string-join($d/marcxml:subfield[@code="u"],""),"hdl.") and(:u is repeatable:)
1676
+ fn:not(fn:matches(fn:string($d/marcxml:subfield[@code="3"]),"finding aid","i") )
1677
+ ) then
1678
+ "instance"
1679
+ else if (fn:matches(fn:string($d/marcxml:subfield[@code="3"]) ,"(pdf|page view) ","i")) then
1680
+ "instance"
1681
+ else if ($d/@ind1="4" and $d/@ind2="0" ) then
1682
+ "instance"
1683
+ else if ($d/@ind1="4" and $d/@ind2="1" and fn:not(fn:string($d/marcxml:subfield[@code="3"]) ) ) then
1684
+ "instance"
1685
+ else if (fn:matches(fn:string($d/marcxml:subfield[@code="3"]),"finding aid","i") ) then
1686
+ "findaid"
1687
+ else
1688
+ "annotation"
1689
+ let $annotates:= if ($workID!="person" and $category="annotation") then
1690
+ element bf:annotates {
1691
+ attribute rdf:resource {$workID}
1692
+ }
1693
+ else ()
1694
+
1695
+ let $type:=
1696
+ if (fn:matches(fn:string-join($d/marcxml:subfield[@code="u"],""),"catdir","i")) then
1697
+ if (fn:matches(fn:string($d/marcxml:subfield[@code="3"]),"contents","i")) then "table of contents"
1698
+ else if (fn:matches(fn:string($d/marcxml:subfield[@code="3"]),"sample","i")) then "sample text"
1699
+ else if (fn:matches(fn:string($d/marcxml:subfield[@code="3"]),"contributor","i")) then "contributor biography"
1700
+ else if (fn:matches(fn:string($d/marcxml:subfield[@code="3"]),"publisher","i")) then "publisher summary"
1701
+ else ()
1702
+ else ()
1703
+
1704
+ return
1705
+ if ( $category="instance" ) then
1706
+ element bf:hasInstance {
1707
+ element bf:Instance {
1708
+ element rdf:type {attribute rdf:resource {"http://bibframe.org/vocab/Electronic"}},
1709
+ element bf:label {
1710
+ if ($d/marcxml:subfield[@code="3"]) then fn:normalize-space(fn:string($d/marcxml:subfield[@code="3"]))
1711
+ else "Electronic Resource"
1712
+ },
1713
+ mbshared:handle-856u($d) ,
1714
+ element bf:instanceOf {
1715
+ attribute rdf:resource {$workID}
1716
+ },
1717
+ $annotates
1718
+ }
1719
+ }
1720
+ else
1721
+ let $property-name:= if ($type="table of contents") then "bf:TableOfContents"
1722
+ else if ($type="publisher summary") then "bf:Summary"
1723
+ else "bf:Annotation"
1724
+ return element bf:hasAnnotation {
1725
+
1726
+ element {$property-name}{
1727
+
1728
+ if (fn:string($d/marcxml:subfield[@code="3"]) ne "" or $type) then
1729
+ element bf:label {
1730
+ if (fn:string($d/marcxml:subfield[@code="3"]) ne "") then
1731
+ fn:string($d/marcxml:subfield[@code="3"])
1732
+ else if ($type) then
1733
+ $type
1734
+ else ()
1735
+ }
1736
+ else (),
1737
+
1738
+ for $u in $d/marcxml:subfield[@code="u"]
1739
+ let $property-name:= if ($type="table of contents") then "bf:tableOfContents"
1740
+ else if ($type="publisher summary") then "bf:review"
1741
+ else "bf:annotationBody"
1742
+ return element {$property-name} {
1743
+ attribute rdf:resource {
1744
+ fn:normalize-space(fn:string($u))
1745
+ }
1746
+ },
1747
+
1748
+ for $s in $d/marcxml:subfield[@code="z"]
1749
+ return element bf:copyNote {fn:string($s)},
1750
+ $annotates
1751
+ }
1752
+ }
1753
+
1754
+ };
1755
+ (:~
1756
+ : This is the function generates dissertation on Work from 502.
1757
+ : (dissertation is no longer a subclass of Work
1758
+ : @param $marcxml element is the 502 datafield
1759
+ : @return bf:* as element()
1760
+ :)
1761
+ declare function mbshared:generate-dissertation(
1762
+ $d as element(marcxml:datafield)
1763
+ ) as element ()*
1764
+ {
1765
+
1766
+ (
1767
+
1768
+ if ($d/marcxml:subfield[@code="c"] ) then
1769
+ element bf:dissertationInstitution {element bf:Organization {
1770
+ element bf:label {fn:string($d/marcxml:subfield[@code="c"])}}
1771
+ }
1772
+
1773
+ else (),
1774
+
1775
+ if ($d/marcxml:subfield[@code="o"]) then
1776
+ element bf:dissertationIdentifier { element bf:Identifier {
1777
+ element bf:identifierValue{fn:string($d/marcxml:subfield[@code="o"])}
1778
+ }
1779
+ }
1780
+
1781
+ else ()
1782
+
1783
+ )
1784
+ };
1785
+
1786
+ (:~
1787
+ : This is the function generates holdings properties from hld:holdings.
1788
+ :
1789
+ : @param $marcxml element is the MARCXML
1790
+ : may also contain hld:holdings
1791
+ : @return bf:* as element()
1792
+ :)
1793
+ declare function mbshared:generate-holdings-from-hld(
1794
+ $marcxml as element(marcxml:record)?,
1795
+
1796
+ $workId as xs:string
1797
+
1798
+ ) as element ()*
1799
+ {
1800
+ let $holdings:=$marcxml//hld:holdings
1801
+ let $heldBy:= if ($marcxml/marcxml:datafield[@tag="852"]/marcxml:subfield[@code="a"]) then
1802
+ fn:string($marcxml/marcxml:datafield[@tag="852"][1]/marcxml:subfield[@code="a"])
1803
+ else ""
1804
+ let $custodialHistory:=mbshared:generate-simple-property($marcxml/marcxml:datafield[@tag="561"], "helditem")
1805
+ for $hold in $holdings/hld:holding
1806
+ let $elm :=
1807
+ if ( $hold/hld:volumes/hld:volume[2]) then "HeldMaterial" else "HeldItem"
1808
+ let $summary-set :=
1809
+ for $property in $hold/*
1810
+ return
1811
+ if ( fn:matches(fn:local-name($property), "callNumber")) then
1812
+ (element bf:label {fn:string($property)},
1813
+ element bf:shelfMark {fn:string($property)})
1814
+ else if ( fn:matches(fn:local-name($property), "localLocation")) then
1815
+ element bf:subLocation {fn:string($property)}
1816
+ else if ( fn:matches(fn:local-name($property), "(enumeration|enumAndChron)")) then
1817
+ element bf:enumerationAndChronology {fn:string($property)}
1818
+
1819
+ else if ( fn:matches( fn:local-name($property), "(publicNote|copyNumber)")) then
1820
+ element {fn:concat("bf:", fn:local-name($property))} {fn:string($property)}
1821
+ else ()
1822
+
1823
+ let $item-set :=
1824
+ if ($hold/hld:volumes ) then
1825
+ for $vol in $hold/hld:volumes/hld:volume
1826
+ let $enum:=fn:normalize-space(fn:string($vol/hld:enumAndChron))
1827
+ let $circs:= $vol/ancestor::hld:holding/hld:circulations
1828
+ let $circ :=
1829
+ for $circulation in $circs/hld:circulation[fn:normalize-space(fn:string(hld:enumAndChron ))=$enum]
1830
+ let $status:= if ($circulation/hld:availableNow/@value="1") then "available" else "not available"
1831
+ return element circ {element bf:circulationStatus {$status},
1832
+ if ($circulation/hld:itemId) then element bf:itemId {fn:string($circulation/hld:itemId )} else ()
1833
+ }
1834
+
1835
+
1836
+ return
1837
+ element bf:heldItem {
1838
+ element bf:HeldItem {
1839
+ if ($circ/bf:itemId!='') then
1840
+ attribute rdf:about {fn:concat($workId,"/item",fn:string($circ/bf:itemId))}
1841
+ else (),
1842
+ element bf:label {fn:string($vol/hld:enumAndChron)},
1843
+ element bf:enumerationAndChronology {$enum },
1844
+ element bf:enumerationAndChronology {fn:string($vol/hld:enumeration)},
1845
+ $circ/*
1846
+ }
1847
+ }
1848
+ else (: no volumes, just add circ to the summary heldmaterial:)
1849
+ let $status:= if ($hold/hld:circulations/hld:circulation/hld:availableNow/@value="1") then "available" else "not available"
1850
+ return element bf:heldItem {
1851
+ element bf:HeldItem {
1852
+ if ($hold/hld:circulations/hld:circulation/hld:itemId) then
1853
+ attribute rdf:about {fn:concat($workId,"/item",fn:string($hold/hld:circulations/hld:circulation/hld:itemId))}
1854
+ else (),
1855
+ element bf:circulationStatus {$status},
1856
+ element bf:itemId {fn:string($hold/hld:circulations/hld:circulation/hld:itemId )}
1857
+ }
1858
+ }
1859
+
1860
+
1861
+ return (
1862
+ if ($elm = "HeldItem" ) then
1863
+ element bf:heldItem {
1864
+ element bf:HeldItem {
1865
+ $item-set/bf:HeldItem/@rdf:about,
1866
+ $summary-set, $item-set//bf:HeldItem/*[fn:not(fn:local-name()='label')],
1867
+ $custodialHistory,
1868
+ if ($heldBy!="") then element bf:heldBy {element bf:Organization {element bf:label {$heldBy}}} else ()
1869
+ }
1870
+ }
1871
+
1872
+ else
1873
+ element bf:heldMaterial{
1874
+ element bf:HeldMaterial {
1875
+ $summary-set,
1876
+ $item-set,
1877
+ if ($heldBy!="") then element bf:heldBy {element bf:Organization {element bf:label {$heldBy}}} else ()
1878
+ }
1879
+ }
1880
+ )
1881
+
1882
+ };
1883
+ (:~
1884
+ : This is the function generates holdings properties from hld:holdings.
1885
+ :
1886
+ : @param $marcxml element is the MARCXML
1887
+ : may also contain hld:holdings
1888
+ : @return bf:* as element()
1889
+ :)
1890
+ declare function mbshared:generate-holdings-from-hrecords(
1891
+ $collection as element(marcxml:collection)?,
1892
+
1893
+ $workId as xs:string
1894
+
1895
+ ) as element ()*
1896
+ {
1897
+
1898
+
1899
+ for $r in $collection/marcxml:record[2](:[fn:string(@type)="Holdings"]:)
1900
+ return element bf:heldItem { element bf:HeldItem {
1901
+
1902
+ mbshared:generate-simple-property($r/marcxml:datafield,"holdings")
1903
+ }
1904
+ }
1905
+
1906
+ };
1907
+ (:~
1908
+ : This is the function generates holdings resources.
1909
+ :
1910
+ : @param $marcxml element is the MARCXML
1911
+ : may also contain hld:holdings
1912
+ : @return bf:* as element()
1913
+ :)
1914
+ declare function mbshared:generate-holdings(
1915
+ $marcxml as element(marcxml:record),
1916
+ $workID as xs:string
1917
+ ) as element ()*
1918
+ {
1919
+ (:options: marcxml:records contains opacxml in hld:holdings, or marcxml:record/ancestor:collection contains
1920
+ marcxml:record[@type="Holdings"]:)
1921
+ let $hld:= if ($marcxml//hld:holdings) then
1922
+ mbshared:generate-holdings-from-hld($marcxml, $workID)
1923
+ else if ($marcxml/ancestor::marcxml:collection/marcxml:record[@type='Holdings']) then
1924
+ mbshared:generate-holdings-from-hrecords($marcxml/ancestor::marcxml:collection, $workID)
1925
+ else ()
1926
+
1927
+ (:udc is subfields a,b,c; the rest are ab:)
1928
+ (:call numbers: if a is a class and b exists:)
1929
+ let $shelfmark:= (: regex for call# "^[a-zA-Z]{1,3}[1-9].*$" :)
1930
+ for $tag in $marcxml/marcxml:datafield[fn:matches(@tag,"(050|051|055|060|070|080|082|083|084)")]
1931
+ (: multiple $a is possible: 2017290 use $i to handle :)
1932
+ for $class at $i in $tag[marcxml:subfield[@code="b"]]/marcxml:subfield[@code="a"]
1933
+ let $element:=
1934
+ if (fn:matches($class/../@tag,"(050|051|055|070)")) then "bf:shelfMarkLcc"
1935
+ else if (fn:matches($class/../@tag,"060")) then "bf:shelfMarkNlm"
1936
+ else if (fn:matches($class/../@tag,"080") ) then "bf:shelfMarkUdc"
1937
+ else if (fn:matches($class/../@tag,"082") ) then "bf:shelfMarkDdc"
1938
+ else if (fn:matches($class/../@tag,"083") ) then "bf:shelfMarkDdc"
1939
+ else if (fn:matches($class/../@tag,"084") ) then "bf:shelfMark"
1940
+ else ()
1941
+ let $value:=
1942
+ if ($i=1) then
1943
+ fn:concat(fn:normalize-space(fn:string($class))," ",fn:normalize-space(fn:string($class/../marcxml:subfield[fn:matches(@code,"b")])))
1944
+ else
1945
+ fn:normalize-space(fn:string($class))
1946
+ (:080 doesnt' have $c, so took this out::)
1947
+ return (: if ($element!="bf:callno-udc") then:)
1948
+ element {$element } {$value}
1949
+ (:else
1950
+ element {$element } {fn:normalize-space(fn:string-join($class/../marcxml:subfield[fn:matches(@code, "(a|b|c)")]," "))}:)
1951
+ let $custodialHistory:=mbshared:generate-simple-property($marcxml/marcxml:datafield[@tag="561"], "helditem")
1952
+
1953
+ let $d852:=
1954
+ if ($marcxml/marcxml:datafield[@tag="852"]) then
1955
+ for $d in $marcxml/marcxml:datafield[@tag="852"]
1956
+ return
1957
+ (
1958
+ for $s in $d/marcxml:subfield[@code="a"] return element bf:heldBy{fn:string($s)},
1959
+ for $s in $d/marcxml:subfield[@code="b"] return element bf:subLocation{fn:string($s)},
1960
+
1961
+ if ($d/marcxml:subfield[fn:matches(@code,"(k|h|l|i|m|t)")]) then
1962
+ element bf:shelfMark{fn:string-join($d/marcxml:subfield[fn:matches(@code,"(k|h|i|l|m|t)")]," ")}
1963
+ else (),
1964
+ mbshared:handle-856u($d) ,
1965
+
1966
+ for $s in $d/marcxml:subfield[@code="z"] return element bf:copyNote{fn:string($s)},
1967
+ for $s in $d/../marcxml:datafield[fn:matches(@tag,"(051|061|071)")]
1968
+ return element bf:copyNote {fn:string($s/marcxml:subfield[@code="c"]) }
1969
+ )
1970
+ else
1971
+ ()
1972
+
1973
+ return
1974
+ if (fn:not($hld) and ($shelfmark or $d852 )) then
1975
+ element bf:heldItem{
1976
+ element bf:HeldItem {
1977
+ (:this is for matching later:)
1978
+ element bf:label{fn:string($shelfmark[1])},
1979
+ $shelfmark,
1980
+ $custodialHistory,
1981
+ $d852
1982
+ }
1983
+ }
1984
+
1985
+ else if ($hld) then $hld else ()
1986
+
1987
+ };
1988
+ (:~
1989
+ : This is the function generates bf:uri or bf:doi or bf:hdl from856u
1990
+ :
1991
+ : @param $marcxml element is the MARCXML datafield 856
1992
+ : @return bf:* as element()
1993
+ :)
1994
+ declare function mbshared:handle-856u(
1995
+ $marcxml as element(marcxml:datafield)
1996
+
1997
+ ) as element ()*
1998
+ {
1999
+ for $s in $marcxml/marcxml:subfield[@code="u"] return
2000
+ let $elm:=if (fn:contains(fn:string($s) ,"doi")) then "bf:doi"
2001
+ else if (fn:contains(fn:string($s),"hdl")) then "bf:hdl" else "bf:uri"
2002
+ return element {$elm} {
2003
+ attribute rdf:resource{fn:string($s)}
2004
+ }
2005
+ };
2006
+ (:~
2007
+ : This is the function generates instance resources.
2008
+ :
2009
+ : @param $marcxml element is the MARCXML
2010
+ : @return bf:* as element()
2011
+ :)
2012
+ declare function mbshared:generate-instances(
2013
+ $marcxml as element(marcxml:record),
2014
+ $typeOf008 as xs:string,
2015
+ $workID as xs:string
2016
+ ) as element ()*
2017
+ {
2018
+ let $isbn-sets:=
2019
+ if ($marcxml/marcxml:datafield[@tag eq "020"]/marcxml:subfield[@code eq "a"]) then
2020
+ mbshared:process-isbns($marcxml)
2021
+ else ()
2022
+
2023
+ return
2024
+ (
2025
+ if ( $isbn-sets//bf:set) then
2026
+ (:use the first 260 to set up a book instance... what else is an instance in other formats?:)
2027
+ let $instance:=
2028
+ for $i in $marcxml/marcxml:datafield[fn:matches(@tag, "(260|261|262|264|300)")][1]
2029
+ return mbshared:generate-instance-from260($i, $workID)
2030
+
2031
+ for $set in $isbn-sets/bf:set
2032
+ return mbshared:generate-instance-fromISBN($marcxml,$set, $instance, $workID)
2033
+
2034
+ else (: $isbn-sets//bf:set is false use the first edition, etc:)
2035
+ (:for $i in $marcxml/marcxml:datafield[@tag eq "260"]|$marcxml/marcxml:datafield[@tag eq "264"]:)
2036
+ for $i in $marcxml/marcxml:datafield[fn:matches(@tag, "(260|261|262|264|300)")][1]
2037
+ return mbshared:generate-instance-from260($i, $workID)
2038
+ ,
2039
+ if ($typeOf008!="SE") then
2040
+ for $i at $x in $marcxml/marcxml:datafield[@tag="260"][fn:position() != 1]
2041
+ return mbshared:generate-additional-instance($i, $workID , $x)
2042
+ else (),
2043
+ for $i at $x in $marcxml/marcxml:datafield[@tag="300"][fn:position() != 1]
2044
+ return mbshared:generate-addl-physical($i, $workID , $x)
2045
+ )
2046
+ };
2047
+ (:~
2048
+ : This is the function generates general notes for all marc notes not in vocabulary
2049
+ :
2050
+ : @param $marcxml element is the MARCXML
2051
+ : @param $domain work or instance; allows suppression based on domain
2052
+ : @return bf:note as element()?
2053
+ :)
2054
+ declare function mbshared:generate-500notes(
2055
+ $marcxml as element(marcxml:record),
2056
+ $domain as xs:string
2057
+
2058
+ ) as element ()*
2059
+ {
2060
+
2061
+ for $marc-note in $marcxml/marcxml:datafield[fn:starts-with(@tag, "5") and fn:not(fn:matches(@tag,$mbshared:named-notes))][marcxml:subfield[@code="3" or @code="a"]]
2062
+ return if ($marc-note[@tag ='504']) then
2063
+ ()
2064
+ else if ( $domain="work") then
2065
+ ()
2066
+ else
2067
+ let $note-text:= fn:string-join($marc-note/marcxml:subfield[@code="3" or @code="a"]," ")
2068
+ return (element bf:note {$note-text},
2069
+ mbshared:generate-880-label($marc-note,"note")
2070
+ )
2071
+ };
2072
+ (:~
2073
+ : This is the function generates a nonsort version of titles using private language tags
2074
+ : accepts element, property label
2075
+ :
2076
+ :: @param $d element is the marcxml datafield
2077
+ : @param $title string is the title as merged subfields
2078
+ : @param $property string is the title property name
2079
+ : @return {$property} as element()
2080
+ :)
2081
+ declare function mbshared:generate-titleNonsort(
2082
+ $d as element(marcxml:datafield),
2083
+ $title as xs:string,
2084
+ $property as xs:string
2085
+ ) as element ()*
2086
+ {
2087
+ if (fn:matches($d/@tag,"(222|242|243|245|440|240)" ) and fn:number($d/@ind2) gt 0 ) then
2088
+ (:need to sniff for begin and end nonsort codes also:)
2089
+ element bf:title {attribute xml:lang {"x-bf-sort"},
2090
+ fn:substring($title, fn:number($d/@ind2)+1)
2091
+ }
2092
+ else if (fn:matches($d/@tag,"(130|630)" ) and fn:number($d/@ind1) gt 0 ) then
2093
+ (:need to sniff for begin and end nonsort codes also:)
2094
+ element bf:title {attribute xml:lang {"x-bf-sort"},
2095
+ fn:substring($title, fn:number($d/@ind1)+1)
2096
+ }
2097
+
2098
+ else ()
2099
+
2100
+ };
2101
+ (:776, 777 related instances
2102
+ ex bib:12821255
2103
+ :)
2104
+ declare function mbshared:generate-related-instance
2105
+ (
2106
+ $d as element(marcxml:datafield) ,
2107
+ $property as xs:string
2108
+ ) as element()*
2109
+ {
2110
+ let $title:=if ($d/marcxml:subfield[@code="t"]) then
2111
+ fn:string($d/marcxml:subfield[@code="t"])
2112
+ else if ($d/marcxml:subfield[@code="a"]) then
2113
+ fn:string($d/marcxml:subfield[@code="a"])
2114
+ else if ($d/marcxml:subfield[@code="c"] and $d/../marcxml:datafield[@tag="245"]/marcxml:subfield[@code="a"]) then
2115
+ fn:concat(fn:string($d/../marcxml:datafield[@tag="245"]/marcxml:subfield[@code="a"]),fn:string($d/marcxml:subfield[@code="c"]))
2116
+ else fn:string($d/marcxml:subfield[@code="c"])
2117
+ let $uri:=mbshared:handle-856u($d)
2118
+ (:fn:string($d/marcxml:subfield[@code="u"]):)
2119
+ let $ids:=mbshared:generate-simple-property($d,"7xx")
2120
+ (:let $id:=if ($d/marcxml:subfield[@code="w"]) then
2121
+ mbshared:handle-system-number( $d/marcxml:subfield[@code="w"])
2122
+ else ():)
2123
+
2124
+ return
2125
+ element {fn:concat("bf:",$property)} {
2126
+ element bf:Instance{
2127
+ element bf:title {$title},
2128
+ $uri,
2129
+ $ids
2130
+ }
2131
+ }
2132
+
2133
+ };
2134
+ (:533 to reproduction
2135
+ sample bib 723007
2136
+ :)
2137
+ declare function mbshared:generate-related-reproduction
2138
+ (
2139
+ $d as element(marcxml:datafield) ,
2140
+ $type
2141
+ )
2142
+ {
2143
+ let $title:=fn:string($d/../marcxml:datafield[@tag="245"]/marcxml:subfield[@code="a"])
2144
+ let $carrier:=
2145
+ if ($d/marcxml:subfield[@code="a"]) then
2146
+ fn:string($d/marcxml:subfield[@code="a"])
2147
+ else if ($d/marcxml:subfield[@code="3"]) then
2148
+ $d/marcxml:subfield[@code="3"]
2149
+ else ()
2150
+ let $pubPlace:= for $pl in $d/marcxml:subfield[@code="b"]
2151
+ return element bf:providerPlace{
2152
+ element bf:Place {
2153
+ element bf:label {fn:string($pl)}
2154
+ }}
2155
+ let $agent:= for $aa in $d/marcxml:subfield[@code="c"]
2156
+ return element bf:providerName {
2157
+ element bf:Organization {
2158
+ element bf:label {fn:string($aa)}
2159
+ }
2160
+ }
2161
+ let $pubDate:= if ($d/marcxml:subfield[@code="d"]) then element bf:providerDate{ marc2bfutils:chopPunctuation($d/marcxml:subfield[@code="d"],".")} else ()
2162
+ let $extent:= fn:string($d/marcxml:subfield[@code="e"])
2163
+ let $coverage:= fn:string($d/marcxml:subfield[@code="m"])
2164
+ (:gwu has multiple 533$n:)
2165
+ let $note:= for $n in $d/marcxml:subfield[@code="n"]
2166
+ return element bf:note { fn:string($n)}
2167
+ return
2168
+ element {fn:concat("bf:",fn:string($type/@property))} {
2169
+ element bf:Work{
2170
+ element bf:authorizedAccessPoint {$title},
2171
+ element bf:title {$title},
2172
+ if ($pubDate or $pubPlace or $agent or $extent or $coverage or $note) then
2173
+ element bf:hasInstance {
2174
+ element bf:Instance {
2175
+ element bf:instanceTitle {element bf:Title {element bf:label{$title}}},
2176
+ element bf:publication {
2177
+ element bf:Provider {
2178
+ $pubPlace,
2179
+ $pubDate,
2180
+ $agent
2181
+ }
2182
+ },
2183
+
2184
+ if ($extent) then element bf:extent {$extent} else (),
2185
+ if ($coverage) then element bf:temporalCoverageNote {$coverage} else (),
2186
+ if ($carrier!="" ) then element bf:carrierCategory {element bf:Category {element bf:categoryValue {marc2bfutils:chopPunctuation($carrier,".")}}} else (),
2187
+
2188
+ if ($note) then $note else ()
2189
+
2190
+ }
2191
+ }
2192
+ else ()
2193
+ }
2194
+ }
2195
+ };
2196
+ (:033 events
2197
+ @since 2014-05-16
2198
+ example bib 11785748
2199
+ @param $d as datafield 033
2200
+ :)
2201
+ declare function mbshared:generate-event
2202
+ (
2203
+ $d as element(marcxml:datafield)
2204
+ )
2205
+ {
2206
+ let $dates:= element bf:eventDate {
2207
+ if ($d/@ind1="2") then (:range:)
2208
+ fn:string-join($d/marcxml:subfield[@code="a"]," - ")
2209
+ else if ($d/@ind1="1") then (:multiple consecutive dates:)
2210
+ fn:string-join($d/marcxml:subfield[@code="a"],", ")
2211
+ else (attribute rdf:datatype {"xsd:dateTime"},fn:string($d/marcxml:subfield[@code="a"]))
2212
+ }
2213
+
2214
+
2215
+ let $placesCodes:=
2216
+ for $s in $d/marcxml:subfield[@code="b"]
2217
+ let $subcode:=if ($s/following-sibling::marcxml:subfield[@code="c"]) then
2218
+ fn:normalize-space(fn:string($s/following-sibling::marcxml:subfield[@code="c"][1]))
2219
+ else ()
2220
+ let $base:=fn:concat("http://id.loc.gov/authorities/classification/G", fn:normalize-space(fn:string($s)))
2221
+ let $uri:= if ($subcode) then
2222
+ fn:concat($base,".", $subcode)
2223
+ else $base
2224
+
2225
+ return (: this in not really right; the g class is not a place :)
2226
+ element bf:eventPlace { attribute rdf:resource {$uri}
2227
+ }
2228
+ let $placesStrings:=
2229
+ for $s in $d/marcxml:subfield[@code="p"]
2230
+ return (: this in not really right; the g class is not a place :)
2231
+ element bf:eventPlace { element bf:Place{
2232
+ element bf:label {fn:string($d/marcxml:subfield[@code="p"]) },
2233
+ for $sys-num in $d/marcxml:subfield[@code="0"]
2234
+ return mbshared:handle-system-number($sys-num)
2235
+ }
2236
+ }
2237
+ return element bf:event { element bf:Event {
2238
+ $dates,
2239
+ $placesCodes,
2240
+ $placesStrings
2241
+ }
2242
+ }
2243
+ };
2244
+ (:555 finding aids note may be related work link or a simple property
2245
+ sample bib 14923309
2246
+ consider linking 555 w/856 on $u!
2247
+ @param $d as datafield 555
2248
+ :)
2249
+ declare function mbshared:generate-finding-aid-work
2250
+ (
2251
+ $d as element(marcxml:datafield)
2252
+ )
2253
+ {
2254
+ let $property-name := if ($d/@ind1="0") then "bf:findingAid"
2255
+ else "bf:index"
2256
+ return element {$property-name}
2257
+ {
2258
+ element bf:Work{
2259
+ element bf:authorizedAccessPoint {fn:string($d/marcxml:subfield[@code="a"])},
2260
+ element bf:title {fn:string($d/marcxml:subfield[@code="a"])},
2261
+ if ($d/marcxml:subfield[@code="u"]) then
2262
+ element bf:hasInstance {
2263
+ element bf:Instance {
2264
+ mbshared:handle-856u($d)
2265
+ }
2266
+ }
2267
+ else ()
2268
+ }
2269
+ }
2270
+
2271
+ };
2272
+ (:
2273
+ For RDA: 040$e = rda
2274
+ For AACR2: Leader/18 = a
2275
+
2276
+ Under AACR2, when two works were published together the first work in the compilation was given the 1XX/240, and the second work was given a 700 analytic (name/title). This essentially resulted in identifying the aggregate work by only the first work in the compilation.
2277
+ Under RDA, we identify the aggregate work in the 240 (not just one of the works), and provide analytical added entries (name/title) for the works in the compilation.
2278
+ (245 would be the instance title, 240 the UT)
2279
+ @param $d as the datafield iwth the related work
2280
+ @param $type as the crosswalk node with instructions on what to match, output
2281
+ @param $workID as the main Work resource ID
2282
+ :)
2283
+ declare function mbshared:generate-related-work
2284
+ (
2285
+ $d as element(marcxml:datafield),
2286
+ $type as element(),
2287
+ $workID as xs:string
2288
+ )
2289
+ {
2290
+
2291
+ let $titleFields :=
2292
+ if (fn:matches($d/@tag,"(630|730|740)")) then
2293
+ "(a|n|p)"
2294
+ else if (fn:matches($d/@tag,"(440|490|830)")) then
2295
+ "(a|n|p|v)"
2296
+ else if (fn:matches($d/@tag,"(534)")) then
2297
+ "(t|b|f|k)"
2298
+ else
2299
+ "(t|f|k|m|n|o|p|s)"
2300
+ let $title :=
2301
+ marc2bfutils:clean-title-string(fn:string-join($d/marcxml:subfield[fn:matches(@code,$titleFields)] , " "))
2302
+ let $name :=
2303
+ if (
2304
+ $d/marcxml:subfield[@code="a"] and
2305
+ $d/@tag="740" and
2306
+ $d/@ind2="2" and
2307
+ $d/ancestor::marcxml:record/marcxml:datafield[fn:matches(@tag, "(100|110|111)")][1]
2308
+ ) then
2309
+ mbshared:get-name($d/ancestor::marcxml:record/marcxml:datafield[fn:matches(@tag, "(100|110|111)")][1])
2310
+ else if ( $d/marcxml:subfield[@code="a"] and fn:not(fn:matches($d/@tag,"(400|410|411|440|490|800|810|811|630|730|740|830)")) ) then
2311
+ mbshared:get-name($d)
2312
+ else ()
2313
+ let $related-props:=mbshared:generate-simple-property($d,"related")
2314
+ let $language:= marc2bfutils:process-language(fn:string($d/marcxml:subfield[@code="l"]))
2315
+ (:if ($d/marcxml:subfield[@code="l"]) then
2316
+ let $lang:= (\:some have 2 codes german = deu, ger :\)
2317
+ $marc2bfutils:lang-xwalk/language[@language-name=marc2bfutils:chopPunctuation(fn:string($d/marcxml:subfield[@code="l"]),".")]/iso6392[1]
2318
+ return if ($lang!="") then
2319
+ element bf:language {
2320
+ attribute rdf:resource { fn:concat("http://id.loc.gov/vocabulary/languages/",$lang)}
2321
+ }
2322
+ else element bf:languageNote {marc2bfutils:clean-string(fn:string($d/marcxml:subfield[@code="l"]))}
2323
+ else ():)
2324
+ let $aLabel :=
2325
+ fn:concat(
2326
+ fn:string(($name//bf:label)[1]),
2327
+ " ",
2328
+ $title
2329
+ )
2330
+ let $aLabel := fn:normalize-space($aLabel)
2331
+
2332
+ let $aLabelWork880 := mbshared:generate-880-label($d,"title")
2333
+ let $aLabelWork880 :=
2334
+ if ($aLabelWork880/@xml:lang) then
2335
+ let $lang := $aLabelWork880/@xml:lang
2336
+ let $n := $name//bf:authorizedAccessPoint[@xml:lang=$lang][1]
2337
+ let $combinedLabel := fn:normalize-space(fn:concat(fn:string($n), " ", fn:string($aLabelWork880)))
2338
+ return
2339
+ element bf:authorizedAccessPoint {
2340
+ $aLabelWork880/@xml:lang,
2341
+ $combinedLabel
2342
+ }
2343
+ else
2344
+ $aLabelWork880
2345
+
2346
+ let $inverse:= if (fn:string($d/@tag)="774" ) then
2347
+ element bf:partOf { attribute rdf:resource {$workID}
2348
+ }
2349
+ else ()
2350
+ return
2351
+ element {fn:concat("bf:",fn:string($type/@property))} {
2352
+ element bf:Work {
2353
+ element bf:title {$title},
2354
+ element bf:authorizedAccessPoint {$aLabel},
2355
+ $aLabelWork880,
2356
+ if ($d/marcxml:subfield[@code="w" or @code="x"] and fn:not($d/@tag="630")) then (:(identifiers):)
2357
+ for $s in $d/marcxml:subfield[@code="w" or @code="x" ]
2358
+ let $iStr := marc2bfutils:clean-string(fn:replace($s, "\(OCoLC\)", ""))
2359
+ return
2360
+ if ( fn:contains(fn:string($s), "(OCoLC)" ) ) then
2361
+ element bf:systemNumber { attribute rdf:resource {fn:concat("http://www.worldcat.org/oclc/",fn:replace($iStr,"(^ocm|^ocn)","")) }}
2362
+ else if ( fn:contains(fn:string($s), "(DLC)" ) ) then
2363
+ element bf:lccn { attribute rdf:resource {fn:concat("http://id.loc.gov/authorities/test/identifiers/lccn/",fn:replace( fn:replace($iStr, "\(DLC\)", "")," ",""))} }
2364
+ else if ($s/@code="x") then element bf:issn {attribute rdf:resource {fn:concat("urn:issn:", fn:replace(marc2bfutils:clean-string($iStr)," ","")) } }
2365
+ (:too much nesting for "nested to flat" right now, but issn belongs in instance: :)
2366
+ (: element bf:hasInstance{
2367
+ element bf:Instance{
2368
+ element bf:label {$title},
2369
+
2370
+ element bf:issn {attribute rdf:resource {fn:concat("urn:issn:", fn:replace(marc2bfutils:clean-string($iStr)," ","")) } }
2371
+ }
2372
+ }
2373
+ :)
2374
+ else ()
2375
+ else
2376
+ (),
2377
+ mbshared:generate-titleNonsort($d,$title, "bf:title"),
2378
+ $name,
2379
+ $related-props,
2380
+ $language,
2381
+ $inverse
2382
+ }
2383
+ }
2384
+ };
2385
+
2386
+ (:~
2387
+ : This is the function that finds and dedups isbns, delivering a complete set for generate-instancefrom isbn
2388
+ : If the 020$a has a 10 or 13, they are matched in a set, if the opposite of a pair doesn't exist, it is calculated
2389
+ : @param $marcxml element is the MARCXML record
2390
+ : @return wrap as as wrapper for bf:set* as element() containing both marcxml:subfield [code=a] and bf:isbn calculated nodes
2391
+ :
2392
+ :)
2393
+ declare function mbshared:process-isbns (
2394
+ $marcxml as element (marcxml:record)
2395
+ ) as element() {
2396
+
2397
+ (:for books with isbns, generate all isbn10 and 13s from the data, list each pair on individual instances:)
2398
+ let $isbns:=$marcxml/marcxml:datafield[@tag eq "020"]/marcxml:subfield[@code eq "a"]
2399
+ let $isbn-sets:=
2400
+ for $str in $isbns
2401
+ let $isbn-str:=fn:normalize-space(fn:tokenize(fn:string($str),"\(")[1])
2402
+ return
2403
+ element bf:isbn-pair {
2404
+ mbshared:get-isbn( marc2bfutils:clean-string( $isbn-str ) )/*
2405
+ }
2406
+
2407
+ let $unique-13s := fn:distinct-values($isbn-sets/bf:isbn13)
2408
+ let $unique-pairs:=
2409
+ for $isbn13 in $unique-13s
2410
+ let $isbn-set := $isbn-sets[bf:isbn13=$isbn13][1]
2411
+ (: for $isbn-set in $isbn-sets :)
2412
+ return
2413
+ element set {
2414
+ (:
2415
+ $isbn-set/bf:isbn[1],
2416
+ $isbn-set/bf:isbn[2],
2417
+ :)
2418
+ element bf:isbn { fn:string($isbn-set/bf:isbn10) },
2419
+ element bf:isbn { fn:string($isbn-set/bf:isbn13) },
2420
+ for $sfa in $marcxml/marcxml:datafield[@tag eq "020"]/marcxml:subfield[@code eq "a"]
2421
+ where fn:contains(fn:string($sfa),fn:string($isbn-set/bf:isbn10)) or fn:contains(fn:string($sfa),fn:string($isbn-set/bf:isbn13))
2422
+ return $sfa
2423
+ }
2424
+ return
2425
+ element wrap {
2426
+ for $set in $unique-pairs
2427
+ return element bf:set { $set/* }
2428
+ }
2429
+ };
2430
+ (:~
2431
+ : This is the function generates related item works.
2432
+ : ex 710 constituent title with 880 : 15015234
2433
+ : @param $marcxml element is the MARCXML
2434
+ : @param $workID element is the main Work resource ID
2435
+ : @param $resource string is the "work" or "instance"
2436
+ : @return bf:* as element()
2437
+ :)
2438
+ declare function mbshared:related-works
2439
+ (
2440
+ $marcxml as element(marcxml:record),
2441
+ $workID as xs:string,
2442
+ $resource as xs:string
2443
+ ) as element ()*
2444
+ {
2445
+
2446
+ let $relateds:=
2447
+ if ($resource="instance") then
2448
+ $mbshared:relationships/instance-relateds
2449
+ else
2450
+ $mbshared:relationships/work-relateds
2451
+
2452
+ let $relationship-source-tags:=$marcxml/marcxml:datafield[fn:matches(@tag,$relateds/@all-tags)]
2453
+
2454
+ let $relateds :=
2455
+ (:for $tagnum in $relationship-source-tags:)
2456
+ (:for $type in $relateds/type[@tag=$d/@tag]:)
2457
+ (:return:)
2458
+ if ($resource="instance" ) then
2459
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,$relateds/@all-tags)]
2460
+ let $property:=$relateds/type[@tag=$d/@tag]/@property
2461
+ return mbshared:generate-related-instance($d,$property)
2462
+ else
2463
+ (: title is in $a , @ind2 needs attention:)
2464
+ (
2465
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(730|740|780|785)")]
2466
+ return (
2467
+ for $type in $relateds/type[fn:matches($d/@tag,@tag)][fn:matches(@ind2,$d/@ind2)]
2468
+ return mbshared:generate-related-work($d,$type, $workID) )
2469
+ ,
2470
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(533)")]
2471
+ for $type in $relateds/type[@tag=$d/@tag]
2472
+ return mbshared:generate-related-reproduction($d,$type)
2473
+ ,
2474
+ for $d in $marcxml/marcxml:datafield[@tag="787"][marcxml:subfield[@code="t"]]
2475
+ for $type in $relateds/type[fn:matches($d/@tag,@tag)]
2476
+ return mbshared:generate-related-work($d,$type, $workID)
2477
+ ,
2478
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(700|710|711)")][marcxml:subfield[@code="t"]]
2479
+ for $type in $relateds/type[fn:matches($d/@tag,@tag)][fn:matches($d/@ind2,@ind2)]
2480
+ return mbshared:generate-related-work($d,$type, $workID)
2481
+ ,
2482
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(490)")][marcxml:subfield[@code="a"]]
2483
+ for $type in $relateds/type[fn:matches($d/@tag,@tag)]
2484
+ return mbshared:generate-related-work($d,$type, $workID)
2485
+ ,
2486
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(400|410|411|430|440|534|774|775|800|810|811|830)")][marcxml:subfield[@code="t"]]
2487
+ for $type in $relateds/type[fn:matches($d/@tag,@tag)]
2488
+ return mbshared:generate-related-work($d,$type, $workID)
2489
+ ,
2490
+
2491
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(760|762|765|767|770|772|773|774)")]
2492
+ for $type in $relateds/type[fn:matches(@tag,$d/@tag)]
2493
+ return
2494
+ mbshared:generate-related-work($d,$type, $workID)
2495
+ )
2496
+ return
2497
+ $relateds
2498
+ };
2499
+ (:~
2500
+ : This is the function that generates an xml:lang attribute from the script and language
2501
+ :
2502
+ : @param $scr string is from the subfield $6
2503
+ : @param $lang string is the from the 008 (or 040?)
2504
+ : @return bf:* as element()
2505
+ :)
2506
+ declare function mbshared:generate-xml-lang(
2507
+ $scr as xs:string?,
2508
+ $lang as xs:string
2509
+ ) as xs:string
2510
+ {
2511
+ let $xml-lang:=
2512
+ $marc2bfutils:lang-xwalk/language[iso6392=$lang]/@xmllang
2513
+
2514
+ let $script:=
2515
+ if ($scr="(3" ) then "arab"
2516
+ else if ($scr="(B" ) then "latn"
2517
+ else if ($scr="$1" and $lang="kor" ) then "hang"
2518
+ else if ($scr="$1" and $lang="chi" ) then "hani"
2519
+ else if ($scr="$1" and $lang="jpn" ) then "jpan"
2520
+ else if ($scr="(N" ) then "cyrl"
2521
+ else if ($scr="(S" ) then "grek"
2522
+ else if ($scr="(2" ) then "hebr"
2523
+ else ""
2524
+ return
2525
+ if ($script) then fn:concat($xml-lang,"-",$script) else $xml-lang
2526
+ };
2527
+ (:~
2528
+ : This is the function that generates a work resource.
2529
+ :
2530
+ : @param $collection element is the MARCXML (one bib, zero or more holdings in <collection/>
2531
+ : @return bf:* as element()
2532
+ :)
2533
+ declare function mbshared:generate-work(
2534
+ $collection as element(marcxml:collection),
2535
+ $workID as xs:string
2536
+ ) as element ()
2537
+ { (:2013-05-01 ntra moved instances inside work; :)
2538
+ for $marcxml in $collection/marcxml:record[fn:not(@type) or @type="Bibliographic"]
2539
+
2540
+ let $cf008 := fn:string($marcxml/marcxml:controlfield[@tag='008'])
2541
+ let $leader:=fn:string($marcxml/marcxml:leader)
2542
+ let $leader6:=fn:substring($leader,7,1)
2543
+ let $leader7:=fn:substring($leader,8,1)
2544
+ let $leader19:=fn:substring($leader,20,1)
2545
+
2546
+ let $typeOf008:=
2547
+ if ($leader6="a") then
2548
+ if (fn:matches($leader7,"(a|c|d|m)")) then
2549
+ "BK"
2550
+ else if (fn:matches($leader7,"(b|i|s)")) then
2551
+ "SE"
2552
+ else ""
2553
+
2554
+ else
2555
+ if ($leader6="t") then "BK"
2556
+ else if ($leader6="p") then "MM"
2557
+ else if ($leader6="m") then "CF"
2558
+ else if (fn:matches($leader6,"(e|f|s)")) then "MP"
2559
+ else if (fn:matches($leader6,"(g|k|o|r)")) then "VM"
2560
+ else if (fn:matches($leader6,"(c|d|i|j)")) then "MU"
2561
+ else ""
2562
+
2563
+ let $instances := mbshared:generate-instances($marcxml, $typeOf008, $workID)
2564
+ let $instancesfrom856:=
2565
+ (:set up instances/annotations for each non-contributor bio link:)
2566
+ (:first 856 wi/ind2=0 is the existing Instance:)
2567
+ for $d at $x in $marcxml/marcxml:datafield[fn:matches(@tag,"(856|859)")]
2568
+ return if ( ($d/@ind2 = "0" and $x ne 1 ) or
2569
+ fn:not(fn:matches(fn:string($d/marcxml:subfield[@code="3"]),"contributor","i"))) then
2570
+ mbshared:generate-instance-from856($d, $workID)
2571
+ else ()
2572
+
2573
+ let $types := mbshared:get-resourceTypes($marcxml)
2574
+
2575
+ let $mainType := "Work"
2576
+
2577
+ let $uniformTitle := (:work title can be from 245 if no 240/130:)
2578
+ for $d in ($marcxml/marcxml:datafield[@tag eq "130"]|$marcxml/marcxml:datafield[@tag eq "240"])[1]
2579
+ return mbshared:get-uniformTitle($d)
2580
+ let $names :=
2581
+ (for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(100|110|111)")]
2582
+ return mbshared:get-name($d),
2583
+ (:joined addl-names to names so we can get at least the first 700 if htere are no 1xx's into aap:)
2584
+ (:let $addl-names:= :)
2585
+ for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"(700|710|711|720)")][fn:not(marcxml:subfield[@code="t"])]
2586
+ return mbshared:get-name($d)
2587
+ )
2588
+
2589
+ let $titles :=
2590
+ <titles>{
2591
+ for $t in $marcxml/marcxml:datafield[fn:matches(@tag,"(243|245|247)")]
2592
+ return mbshared:get-title($t, "work")
2593
+ }</titles>
2594
+ let $hashable := mbshared:generate-hashable($marcxml, $mainType, $types)
2595
+
2596
+ (: Let's create an authoritativeLabel for this :)
2597
+ let $aLabel :=
2598
+ if ($uniformTitle[bf:workTitle]) then
2599
+ fn:concat( fn:string($names[1]/bf:*[1]/bf:label), " ", fn:string($uniformTitle/bf:workTitle) )
2600
+ else if ($titles) then
2601
+ fn:concat( fn:string($names[1]/bf:*[1]/bf:label), " ", fn:string($titles/bf:workTitle[1]) )
2602
+ else
2603
+ ""
2604
+
2605
+ let $aLabel :=
2606
+ if (fn:ends-with($aLabel, ".")) then
2607
+ fn:substring($aLabel, 1, fn:string-length($aLabel) - 1 )
2608
+ else
2609
+ $aLabel
2610
+
2611
+ let $aLabel :=
2612
+ if ($aLabel ne "") then
2613
+ element bf:authorizedAccessPoint { fn:normalize-space($aLabel) }
2614
+ else
2615
+ ()
2616
+
2617
+ let $aLabelsWork880 := $titles/bf:authorizedAccessPoint
2618
+ let $aLabelsWork880 :=
2619
+ for $al in $aLabelsWork880
2620
+ let $lang := $al/@xml:lang
2621
+ let $n := $names//bf:authorizedAccessPoint[@xml:lang=$lang][1]
2622
+ let $combinedLabel := fn:normalize-space(fn:concat(fn:string($n), " ", fn:string($al)))
2623
+ where $al/@xml:lang
2624
+ return
2625
+ element bf:authorizedAccessPoint {
2626
+ $al/@xml:lang,
2627
+ $combinedLabel
2628
+ }
2629
+
2630
+ let $events:= for $d in $marcxml/marcxml:datafield[@tag="033"]
2631
+ return mbshared:generate-event($d)
2632
+
2633
+ (:
2634
+ Here's a thought. If this Work *isn't* English *and* it does
2635
+ have a uniform title (240), we should probably figure out the
2636
+ lexical value of the language code and append it to the
2637
+ authoritativeLabel, thereby creating a type of expression.
2638
+ :)
2639
+
2640
+ let $langs := mbshared:get-languages ($marcxml)
2641
+ let $dissertation:=
2642
+ for $diss in $marcxml/marcxml:datafield[@tag="502"]
2643
+ return mbshared:generate-dissertation($diss)
2644
+ let $audience := fn:substring($cf008, 23, 1)
2645
+ let $audience := (: untorture this! :)
2646
+ if ($audience ne "" and fn:matches($typeOf008, "(BK|CF|MU|V)")) then
2647
+ let $aud := fn:string($marc2bfutils:targetAudiences/type[@cf008-22 eq $audience])
2648
+ return
2649
+ if (
2650
+ $aud ne ""
2651
+ (: What others would have audience? :)
2652
+ (:?? ntra: I think audience s.b. there regardless of the subclass of work and anyway, mainType is Work
2653
+ and
2654
+ (
2655
+ $mainType eq "Text" or
2656
+ $mainType eq "SoftwareOrMultimedia" or
2657
+ $mainType eq "StillImage" or
2658
+ $mainType eq "NotatedMusic" or
2659
+ $mainType eq "MusicRecording"
2660
+
2661
+ ):)
2662
+ ) then
2663
+ element bf:intendedAudience {
2664
+ attribute rdf:resource { fn:concat("http://id.loc.gov/vocabulary/targetAudiences/" , $aud) }
2665
+ }
2666
+ else ()
2667
+ else
2668
+ ()
2669
+
2670
+ let $aud521:=
2671
+ for $tag in $marcxml/marcxml:datafield[@tag eq "521"]
2672
+ return mbshared:get-521audience($tag)
2673
+
2674
+
2675
+ (: Don't be surprised when genre turns into "form" :)
2676
+ let $genre := fn:substring($cf008, 24, 1)
2677
+ (:$genre isn't working because $mainType=Work:)
2678
+ let $genre :=
2679
+ if ($genre ne "") then
2680
+ let $gen := fn:string($marc2bfutils:formsOfItems/type[@cf008-23 eq $genre and fn:contains(fn:string(@rType), $mainType)])
2681
+ return
2682
+ if ($gen ne "") then
2683
+ element bf:genre {$gen}
2684
+ else ()
2685
+ else
2686
+ ()
2687
+
2688
+ let $contentCategory := mbshared:generate-physdesc($marcxml,"work") (:336:)
2689
+ let $cartography:=
2690
+ for $d in $marcxml/marcxml:datafield[@tag="255"]
2691
+ return mbshared:generate-simple-property($d,"cartography")
2692
+
2693
+
2694
+ let $abstract:= (:contentsNote:)
2695
+ for $d in $marcxml/marcxml:datafield[@tag="520"][fn:not(marcxml:subfield[@code="c"]) and fn:not(marcxml:subfield[@code="u"])]
2696
+ return mbshared:generate-simple-property($d,"work")
2697
+
2698
+ let $abstract-annotation:=
2699
+ (:if ($marcxml/marcxml:datafield[@tag="520"][marcxml:subfield[fn:matches(@code,"(c|u)")]] ) then:)
2700
+ if ($marcxml/marcxml:datafield[@tag="520"][marcxml:subfield[fn:matches(@code,"(a|c|u)")]] ) then
2701
+ mbshared:generate-abstract-annotation($marcxml,$workID)
2702
+ else ()
2703
+
2704
+ let $work-identifiers := mbshared:generate-identifiers($marcxml,"work")
2705
+ let $general-notes := mbshared:generate-500notes($marcxml, "work")
2706
+ let $work-classes := mbshared:generate-classification($marcxml,"work")
2707
+
2708
+ let $subjects:=
2709
+ for $d in $marcxml/marcxml:datafield[fn:matches(fn:string-join($marc2bfutils:subject-types//@tag," "),fn:string(@tag))]
2710
+ return mbshared:get-subject($d)
2711
+
2712
+ let $findaids:= for $d in $marcxml/marcxml:datafield[fn:matches(@tag,"555")]
2713
+ return if ($d/marcxml:subfield[@code="u"]) then
2714
+ mbshared:generate-finding-aid-work($d)
2715
+ else
2716
+ mbshared:generate-simple-property($d,"findingaid")
2717
+ let $work-relateds := mbshared:related-works($marcxml,$workID,"work")
2718
+
2719
+ let $complex-notes:=
2720
+ for $d in $marcxml/marcxml:datafield[@tag eq "505"][@ind2="0"]
2721
+ return (mbshared:generate-complex-notes($d),
2722
+ element bf:contentsNote{ fn:string-join($d/marcxml:subfield," ")}
2723
+ )
2724
+ let $standalone-880s:=mbshared:generate-standalone-880( $marcxml ,"work")
2725
+
2726
+ let $gacs:=
2727
+ for $d in $marcxml/marcxml:datafield[@tag = "043"]/marcxml:subfield[@code="a"]
2728
+ (:filter out trailing hyphens:)
2729
+ let $gac := fn:replace(fn:normalize-space(fn:string($d)),"-+$","")
2730
+ return
2731
+ element bf:subject {
2732
+ attribute rdf:resource { fn:concat("http://id.loc.gov/vocabulary/geographicAreas/", $gac) }
2733
+ }
2734
+
2735
+ let $derivedFrom:=
2736
+ element bf:derivedFrom {
2737
+ attribute rdf:resource{fn:concat($workID,".marcxml.xml")}
2738
+ }
2739
+
2740
+ let $work-simples:=
2741
+ for $d in $marcxml/marcxml:datafield
2742
+ return mbshared:generate-simple-property($d,"work")
2743
+
2744
+ let $admin:=mbshared:generate-admin-metadata($marcxml, $workID)
2745
+ return
2746
+ element {fn:concat("bf:" , $mainType)} {
2747
+ attribute rdf:about {$workID},
2748
+
2749
+ for $t in fn:distinct-values($types)
2750
+ return
2751
+ element rdf:type {
2752
+ attribute rdf:resource {fn:concat("http://bibframe.org/vocab/", $t)}
2753
+ },
2754
+ $aLabel,
2755
+ $aLabelsWork880,
2756
+ $dissertation,
2757
+
2758
+ if ($uniformTitle/bf:workTitle) then
2759
+ $uniformTitle/*
2760
+ else
2761
+ $titles/* ,
2762
+
2763
+ $names,
2764
+ (:$addl-names,:)
2765
+ $events,
2766
+ $work-simples,
2767
+ $contentCategory,
2768
+ $aud521,
2769
+ $langs,
2770
+ $findaids,
2771
+ $abstract,
2772
+ $abstract-annotation,
2773
+ $audience,
2774
+ $genre,
2775
+ $general-notes,
2776
+ $cartography,
2777
+ $subjects,
2778
+ $gacs,
2779
+ $work-classes,
2780
+ $work-identifiers,
2781
+ $complex-notes,
2782
+ $standalone-880s,
2783
+ $work-relateds,
2784
+ $derivedFrom,
2785
+ $hashable,
2786
+ $admin,
2787
+
2788
+ for $i in $instances
2789
+ return element bf:hasInstance{$i},
2790
+ $instancesfrom856
2791
+
2792
+ }
2793
+
2794
+ };
2795
+ (:~
2796
+ : This function generates constituent (hasPart) works from 505
2797
+ :
2798
+ : LC often uses only $a, but stanford has $g$t, and dave reser says he's seen [$g]$t[$r][$u] and $u is always last.
2799
+ : @param $d element is the marcxml:datafield 505
2800
+ : @return bf:hasPart*
2801
+ :)
2802
+ declare function mbshared:generate-complex-notes(
2803
+ $d as element(marcxml:datafield)
2804
+ ) as element()*
2805
+ {
2806
+ let $vernacular:= $d/ancestor::marcxml:record/marcxml:datafield[@tag="880"][fn:matches(marcxml:subfield[@code="6"],"^505-")]
2807
+
2808
+ let $sub-codes:= fn:distinct-values($d/marcxml:subfield[@code!="t"]/@code)
2809
+ let $return-codes := "gru"
2810
+ let $set:=
2811
+ for $title at $x in $d/marcxml:subfield[@code="t"]
2812
+ let $t := fn:replace(fn:string($title), " /", "")
2813
+ let $vernacular-title:=
2814
+ if ($vernacular) then
2815
+ let $lang := fn:substring(fn:string($d/ancestor::marcxml:record/marcxml:controlfield[@tag="008"]), 36, 3)
2816
+ let $scr := fn:tokenize($vernacular/marcxml:subfield[@code="6"],"/")[2]
2817
+ let $xmllang:= mbshared:generate-xml-lang($scr, $lang)
2818
+
2819
+ return element bf:title {if ($xmllang) then attribute xml:lang{$lang} else (),
2820
+ fn:string($vernacular/marcxml:subfield[@code="t"][fn:position()=$x])
2821
+ }
2822
+ else ()
2823
+ let $details :=
2824
+ element details {
2825
+ (://for the set of subfields after this $t, up until there's a new $t
2826
+ problem is, $g precedes $t?
2827
+ for each title t, get the immediate preceding $gs, if there, and the following $rs if it's there, and $u ??.
2828
+ :)
2829
+ for $subfield in ($title/preceding-sibling::marcxml:subfield[@code="g"][following-sibling::marcxml:subfield[@code="t"][1]=fn:string($title)]
2830
+ | $title/following-sibling::marcxml:subfield[@code="r" or @code="u"][preceding-sibling::marcxml:subfield[@code="t"][1]=fn:string($title)])
2831
+ (: the following is wrong, I think: assumes $t is first:
2832
+ for $subfield in $title/following-sibling::marcxml:subfield[@code!="t"][preceding-sibling::marcxml:subfield[@code="t"][1]=fn:string($title)]
2833
+ :)
2834
+ let $elname:=
2835
+ if ($subfield/@code="g") then "bf:note"
2836
+ else if ($subfield/@code="r") then "bf:creator"
2837
+ else if ($subfield/@code="u") then "rdf:resource"
2838
+ else "bf:note"
2839
+ let $sfdata := fn:replace(fn:string($subfield), " --", "")
2840
+ return
2841
+ if ($elname eq "rdf:resource") then
2842
+ element {$elname} { attribute rdf:resource {$sfdata} }
2843
+ else if ($elname eq "bf:creator") then
2844
+ if ( fn:contains($sfdata, ";") ) then
2845
+ (: we have multiples :)
2846
+ for $c in fn:tokenize($sfdata, ";")
2847
+ return mbshared:get-name-fromSOR($c,"bf:creator")
2848
+ else
2849
+ mbshared:get-name-fromSOR($sfdata,"bf:creator")
2850
+ else
2851
+ element {$elname} {$sfdata}
2852
+ }
2853
+
2854
+ return
2855
+ element part {
2856
+ $details/* ,
2857
+ element bf:title {$t},
2858
+
2859
+ $vernacular-title
2860
+
2861
+ }
2862
+ return
2863
+ for $item in $set
2864
+ return
2865
+ element bf:hasPart {
2866
+ element bf:Work {
2867
+ $item/*
2868
+ }
2869
+ }
2870
+ };
2871
+ (:~
2872
+ : This function generates a hashable version of the work, using title, name etc.
2873
+ :
2874
+ : It generates a bf:authorizedAccessPoint xml:lang="x-bf-hash" private language.
2875
+ :
2876
+ : The "hashable" string is an attempt to create an identifier of sorts to help
2877
+ : establish "sameness" between works (this may be extended to instances in the future).
2878
+ : While there are other ways to do this (load the data into a search system and do
2879
+ : specific field-based queries), this is meant as a way to test out "matching" ideas without
2880
+ : the overhead of loading into a special system.
2881
+ :
2882
+ : The algorithm is as follows:
2883
+ : 1) Look for a title - take the 130 or 240 if it exists, otherwise use the 245.
2884
+ : 2) Use only select subfields from 130, 240, or 245. For example, only subfields a and b
2885
+ : used when evaluating the 245.
2886
+ : 3) Grab all the names from the 1XX field and the 7XX fields. Only use a given 7XX field if
2887
+ : it represents a name (name/title 7XX fields, therefore, are not included)
2888
+ : 4) Sort all the names alphabetically to help control for variation in how the data were
2889
+ : originally entered.
2890
+ : 5) Include the langauge from the 008.
2891
+ : 6) Include the type of MARC resource (Text, Audio, etc)
2892
+ : 7) Concatenate and normalize. Normalization includes forcing the string to be all lower
2893
+ : case, removing spaces, and removing all special characters.
2894
+ :
2895
+
2896
+ : @param $marcxml element is the marcxml:datafield
2897
+ : @return bf:authorizedAccessPoint
2898
+ :)
2899
+ declare function mbshared:generate-hashable(
2900
+ $marcxml as element(marcxml:record),
2901
+ $mainType as xs:string,
2902
+ $types as item()*
2903
+ ) as element( bf:authorizedAccessPoint)
2904
+ {
2905
+ let $hashableTitle :=
2906
+ let $uniform := ($marcxml/marcxml:datafield[@tag eq "130"]|$marcxml/marcxml:datafield[@tag eq "240"])[1]
2907
+ let $primary := $marcxml/marcxml:datafield[@tag eq "245"]
2908
+ let $t :=
2909
+ if ($uniform/marcxml:subfield[fn:not(fn:matches(@code,"(g|h|k|l|m|n|o|p|r|s|0|6|8)"))]) then
2910
+ (: We have a uniform title that contains /only/ a title and a date of work. :)
2911
+ fn:string-join($uniform/marcxml:subfield, " ")
2912
+ else
2913
+ (: Otherwise, let's just use the 245 for now. For example,
2914
+ we cannot create an uber work for Leaves of Grass. Selections.
2915
+ :)
2916
+ let $tstr := fn:string-join($primary/marcxml:subfield[fn:matches(@code, "a|b")], " ")
2917
+ let $tstr :=
2918
+ if (fn:number($primary/@ind2) gt 0 ) then
2919
+ (: Yep, there's a nonfiling marker. :)
2920
+ fn:substring($tstr, fn:number($primary/@ind2)+1)
2921
+ else
2922
+ $tstr
2923
+ return $tstr
2924
+ let $t := marc2bfutils:clean-title-string($t)
2925
+ return $t
2926
+ let $hashableNames :=
2927
+ (
2928
+ let $n := (:fn:string-join($marcxml/marcxml:datafield[fn:matches(@tag,"(100|110|111)") and marcxml:subfield[fn:not(fn:matches(@code,"(e|0|4|6|8)"))]][1]/marcxml:subfield, " "):)
2929
+ fn:string-join($marcxml/marcxml:datafield[fn:matches(@tag,"(100|110|111)")]/marcxml:subfield[fn:not(fn:matches(@code,"(e|0|4|6|8)"))] , " ")
2930
+ return marc2bfutils:clean-name-string($n),
2931
+
2932
+ let $n :=(: fn:string-join($marcxml/marcxml:datafield[fn:matches(@tag,"(700|710|711)") and marcxml:subfield[fn:not(fn:matches(@code,"(e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|x|0|3|4|5|6|8)"))]]/marcxml:subfield, " "):)
2933
+ fn:string-join($marcxml/marcxml:datafield[fn:matches(@tag,"(700|710|711)")]/marcxml:subfield[fn:not(fn:matches(@code,"(e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|x|0|3|4|5|6|8)"))], " ")
2934
+ return marc2bfutils:clean-name-string($n)
2935
+ )
2936
+ let $hashableNames :=
2937
+ for $n in $hashableNames
2938
+ order by $n
2939
+ return $n
2940
+ let $hashableNames := fn:string-join($hashableNames, " ")
2941
+ let $hashableLang := fn:normalize-space(fn:substring(fn:string($marcxml/marcxml:controlfield[@tag='008']), 36, 3))
2942
+ (:let $hashableTypes := fn:concat($mainType, fn:string-join($types, "")):)
2943
+ let $hashableTypes := fn:concat($mainType, $types[1])
2944
+
2945
+ let $hashableStr := fn:concat($hashableNames, " / ", $hashableTitle, " / ", $hashableLang, " / ", $hashableTypes)
2946
+ let $hashableStr := fn:replace($hashableStr, "!|\||@|#|\$|%|\^|\*|\(|\)|\{|\}|\[|\]|:|;|'|&amp;quot;|&amp;|<|>|,|\.|\?|~|`|\+|=|_|\-|/|\\| ", "")
2947
+ let $hashableStr := fn:replace($hashableStr, '"','')
2948
+ let $hashableStr := fn:lower-case($hashableStr)
2949
+ return
2950
+ element bf:authorizedAccessPoint {
2951
+ attribute xml:lang { "x-bf-hash"},
2952
+ $hashableStr
2953
+ }
2954
+ };
2955
+ (:~
2956
+ : This function generates a subject.
2957
+ : It takes a specific 6xx as input.
2958
+ : It generates a bf:subject as output.
2959
+ :
2960
+ ,
2961
+
2962
+ -:29 '600': ('subject', {'bibframeType': 'Person'}),
2963
+ -:30 '610': ('subject', {'bibframeType': 'Organization'}),
2964
+ -:31 '611': ('subject', {'bibframeType': 'Meeting'}),
2965
+ -:33 '630': ('uniformTitle', {'bibframeType': 'Title'}),
2966
+ -:34 '650': ('subject', {'bibframeType': 'Topic'}),
2967
+ -:35 '651': ('subject', {'bibframeType': 'Geographic'}),
2968
+
2969
+ : need to add madsscheme:
2970
+ : - Thesaurus specified in 600-651, 655 Ind2. If Ind2=7, then thesaurus in subfield $2 using MARC code.
2971
+ : - Thesaurus specified only in subfield $2 using MARC code in 654, 656, 657, 658, 662
2972
+ : lcsh: <madsrdf:isMemberOfMADSScheme rdf:resource="id.loc.gov/authorities/subjects"/>
2973
+ : mesh: nlm.gov/mesh ?
2974
+
2975
+ : @param $d element is the marcxml:datafield
2976
+ : @return bf:subject
2977
+ :)
2978
+ declare function mbshared:get-subject(
2979
+ $d as element(marcxml:datafield)
2980
+ ) as element()
2981
+ {
2982
+ let $subjectType := fn:string($marc2bfutils:subject-types/subject[@tag=$d/@tag])
2983
+ let $subjectType:= if ($d[@tag="600"][marcxml:subfield[@code="t"]]) then "Work" else $subjectType
2984
+ let $subjectScheme:= if ($d/marcxml:subfield[@code="2"]) then
2985
+ fn:concat("http://id.loc.gov/vocabulary/subjectSchemes/",fn:normalize-space(fn:string($d/marcxml:subfield[@code="2"])))
2986
+ else if($d[@ind2="0"]) then "http://id.loc.gov/authorities/subjects"
2987
+ else if($d[@ind2="1"]) then "http://id.loc.gov/authorities/childrensSubjects"
2988
+ else if($d[@ind2="2"]) then "http://id.loc.gov/vocabulary/subjectSchemes/mesh"
2989
+ else if($d[@ind2="3"]) then "http://id.loc.gov/vocabulary/subjectSchemes/nal"
2990
+ else if($d[@ind2="5"]) then "http://www.collectionscanada.gc.ca/obj/900/f11/040004/canadian-subject-headings"
2991
+ else if($d[@ind2="6"]) then "http://rvm.example.org/rvm"
2992
+ else ()
2993
+ let $details :=
2994
+
2995
+ if (fn:matches(fn:string($d/@tag),"(600|610|611|648|650|655|751)")) then
2996
+ let $last2Tag := fn:substring(fn:string($d/@tag), 2)
2997
+ (:
2998
+ The controlfields and the leader are bogus,
2999
+ designed purely to ensure it runs without error.
3000
+ :)
3001
+ let $marcAuthXML :=
3002
+ <marcxml:record>
3003
+ <marcxml:leader>01243cz a2200253n 4500</marcxml:leader>
3004
+ <marcxml:controlfield tag="001">sh0000000</marcxml:controlfield>
3005
+ <marcxml:controlfield tag="003">DLC</marcxml:controlfield>
3006
+ <marcxml:controlfield tag="005">20110524062830.0</marcxml:controlfield>
3007
+ <marcxml:controlfield tag="008">840503n| acannaabn |a aaa </marcxml:controlfield>
3008
+ {
3009
+ element marcxml:datafield {
3010
+ attribute tag { fn:concat("1" , $last2Tag) },
3011
+ attribute ind1 { " " },
3012
+ attribute ind2 { "0" },
3013
+ $d/*[@code ne "2"][@code ne "0"][@code ne "8"]
3014
+ }
3015
+ }
3016
+ </marcxml:record>
3017
+ let $madsrdf := marcxml2madsrdf:marcxml2madsrdf($marcAuthXML)
3018
+ let $madsrdf := $madsrdf/madsrdf:*[1]
3019
+ let $details :=
3020
+ (
3021
+ element bf:authorizedAccessPoint {fn:string($madsrdf/madsrdf:authoritativeLabel)},
3022
+ element bf:label { fn:string($madsrdf/madsrdf:authoritativeLabel) },
3023
+ if ( fn:not(fn:matches(fn:string-join($d/marcxml:subfield[@code="0"]," "),"(http://|\(uri\)|\(DE-588\))" ) ) ) then
3024
+ ( element bf:hasAuthority {
3025
+ element madsrdf:Authority {
3026
+ element rdf:type {
3027
+ attribute rdf:resource {
3028
+ fn:concat("http://www.loc.gov/mads/rdf/v1#" , fn:local-name($madsrdf))
3029
+ }
3030
+ },
3031
+ $madsrdf/madsrdf:authoritativeLabel,
3032
+ element madsrdf:isMemberOfMADSScheme {attribute rdf:resource {$subjectScheme}}
3033
+ }
3034
+ },
3035
+ if ($d/marcxml:subfield[@code="2"]) then element bf:authoritySource {$subjectScheme} else ()
3036
+ )
3037
+ else ()
3038
+
3039
+ )
3040
+ return $details
3041
+
3042
+
3043
+ else if ($d/@tag="752") then
3044
+ (:no longer includes 662:)
3045
+ let $aLabel := fn:string-join($d/marcxml:subfield[fn:matches(fn:string(@code),"(a|b|c|d|f|g|h)")], ". ")
3046
+ let $components :=
3047
+ for $c in $d/marcxml:subfield[fn:matches(fn:string(@code),"(a|b|c|d|f|g|h)")]
3048
+ return
3049
+ if ( fn:string($c/@code) eq "a" ) then
3050
+ element madsrdf:Country {
3051
+ element madsrdf:authoritativeLabel { fn:string($c) }
3052
+ }
3053
+ else if ( fn:string($c/@code) eq "b" ) then
3054
+ element madsrdf:State {
3055
+ element madsrdf:authoritativeLabel { fn:string($c) }
3056
+ }
3057
+ else if ( fn:string($c/@code) eq "c" ) then
3058
+ element madsrdf:County {
3059
+ element madsrdf:authoritativeLabel { fn:string($c) }
3060
+ }
3061
+ else if ( fn:string($c/@code) eq "d" ) then
3062
+ element madsrdf:City {
3063
+ element madsrdf:authoritativeLabel { fn:string($c) }
3064
+ }
3065
+ else if ( fn:string($c/@code) eq "f" ) then
3066
+ element madsrdf:CitySection {
3067
+ element madsrdf:authoritativeLabel { fn:string($c) }
3068
+ }
3069
+ else if ( fn:string($c/@code) eq "g" ) then
3070
+ element madsrdf:Geographic {
3071
+ element madsrdf:authoritativeLabel { fn:string($c) }
3072
+ }
3073
+ else if ( fn:string($c/@code) eq "h" ) then
3074
+ element madsrdf:ExtraterrestrialArea {
3075
+ element madsrdf:authoritativeLabel { fn:string($c) }
3076
+ }
3077
+ else
3078
+ ()
3079
+ let $details :=
3080
+ (
3081
+ element rdf:type {
3082
+ attribute rdf:resource { "http://www.loc.gov/mads/rdf/v1#HierarchicalGeographic"}
3083
+ },
3084
+ element bf:authorizedAccessPoint { fn:string($aLabel) },
3085
+ (: element bf:label { fn:string($aLabel) },:)
3086
+ if ( fn:not(fn:matches(fn:string-join($d/marcxml:subfield[@code="0"]," "),"(http://|\(uri\)|\(DE-588\))" ) ) ) then
3087
+ element bf:hasAuthority {
3088
+ element madsrdf:Authority {
3089
+ element madsrdf:authoritativeLabel{fn:string($aLabel)},
3090
+ element madsrdf:componentList {
3091
+ attribute rdf:parseType {"Collection"},
3092
+ $components
3093
+ }
3094
+ }
3095
+ }
3096
+ else ()
3097
+ )
3098
+ return $details
3099
+ (:656 occupation itoamc in $2? :)
3100
+ else
3101
+ (
3102
+ element bf:label {fn:string-join($d/marcxml:subfield[fn:not(@code="6")], " ")
3103
+
3104
+ }
3105
+ )
3106
+ let $system-number:=
3107
+ for $sys-num in $d/marcxml:subfield[@code="0"]
3108
+ return mbshared:handle-system-number($sys-num)
3109
+ return
3110
+ element bf:subject {
3111
+ element {fn:concat("bf:",$subjectType)} {
3112
+ $details,
3113
+ mbshared:generate-880-label($d,"subject"),
3114
+ $system-number
3115
+ }
3116
+ }
3117
+
3118
+ };
3119
+ (:~
3120
+ : This function generates all languages .
3121
+ : It takes 041 and generates a wrapper
3122
+ : It generates a bf:Language's as output.
3123
+ :
3124
+ : $2 - Source of code (NR)
3125
+ also 546?
3126
+
3127
+
3128
+ : @param $marcxml element is the marcxml:record
3129
+ : @return wrap/bf:language* or wrap/bf:Language*
3130
+
3131
+ :)
3132
+
3133
+ declare function mbshared:get-languages(
3134
+ $marcxml as element(marcxml:record)
3135
+ ) as element()*
3136
+ {
3137
+ let $cf008 := fn:string($marcxml/marcxml:controlfield[@tag='008'])
3138
+ let $parts:=
3139
+ <languageObjectParts>
3140
+ <sf code="a">text</sf>
3141
+ <sf code="b">summary or abstract</sf>
3142
+ <sf code="d">sung or spoken text</sf>
3143
+ <sf code="e">librettos</sf>
3144
+ <sf code="f">table of contents</sf>
3145
+ <sf code="g">accompanying material other than librettos</sf>
3146
+ <sf code="h">original</sf>
3147
+ <sf code="j">subtitles or captions</sf>
3148
+ <sf code="k">intermediate translations</sf>
3149
+ <sf code="m">original accompanying materials other than librettos</sf>
3150
+ <sf code="n">original libretto</sf>
3151
+ </languageObjectParts>
3152
+
3153
+ let $simple-a:=
3154
+ for $sfa in $marcxml/marcxml:datafield[@tag="041"]/marcxml:subfield[@code="a"]
3155
+ for $i in 0 to (fn:string-length($sfa) idiv 3)-1
3156
+ let $pos := $i * 3 + 1
3157
+ return
3158
+ element bf:language{
3159
+ attribute rdf:resource { fn:concat("http://id.loc.gov/vocabulary/languages/" , fn:substring($sfa, $pos, 3))}
3160
+ }
3161
+ let $first-041a:= fn:string($simple-a[1]/@rdf:resource)
3162
+
3163
+ let $lang008 := fn:normalize-space(fn:substring($cf008, 36, 3))
3164
+ let $lang008 :=
3165
+ if ($lang008 ne "" and $lang008 ne "|||" and $lang008 ne fn:substring-after($first-041a,"/languages/")) then
3166
+ element bf:language {
3167
+ attribute rdf:resource { fn:concat("http://id.loc.gov/vocabulary/languages/" , $lang008) }
3168
+ }
3169
+ else
3170
+ ()
3171
+ let $parts:=
3172
+ for $sf in $marcxml/marcxml:datafield[@tag="041"]/marcxml:subfield[fn:matches(@code,"(b|d|e|f|g|h|j|k|m|n)")]
3173
+ return element bf:language {
3174
+ element bf:Language {
3175
+ element bf:resourcePart{
3176
+ fn:string($parts//sf[@code=$sf/@code])
3177
+ },
3178
+ for $i in 0 to (fn:string-length($sf) idiv 3)-1
3179
+ let $pos := $i * 3 + 1
3180
+ return
3181
+ element bf:languageOfPartUri{
3182
+ attribute rdf:resource { fn:concat("http://id.loc.gov/vocabulary/languages/" , fn:substring($sf, $pos, 3))}
3183
+ },
3184
+ if ($sf/../marcxml:subfield[@code="2"]) then
3185
+ element bf:languageSource {fn:string($sf/../marcxml:subfield[@code="2"])}
3186
+ else ()
3187
+ }
3188
+ }
3189
+ return
3190
+ ($lang008,
3191
+ $simple-a,
3192
+ $parts
3193
+
3194
+ )
3195
+
3196
+ };
3197
+
3198
+ (:~
3199
+ : This function generates a name.
3200
+ : It takes a specific datafield as input.
3201
+ : It generates a bf:creator or other name link as output.
3202
+ :
3203
+ : @param $d element is the marcxml:datafield
3204
+ :
3205
+ : @return bf:creator element OR a more specific relators:* one.
3206
+ :)
3207
+ declare function mbshared:get-name(
3208
+ $d as element(marcxml:datafield)
3209
+ ) as element()*
3210
+ {
3211
+ (:let $relatorCode :=
3212
+ if ($d/marcxml:subfield[@code = "4"]!="") then
3213
+ marc2bfutils:chopPunctuation(marc2bfutils:clean-string(fn:string($d/marcxml:subfield[@code = "4"][1])),".")
3214
+ else
3215
+ marc2bfutils:generate-role-code(fn:string($d/marcxml:subfield[@code = "e"][1]))
3216
+ :)
3217
+ let $relatorCodes :=
3218
+ for $role in $d/marcxml:subfield[@code = "4" or @code = "e"]
3219
+ return
3220
+ if (fn:string($role/@code) = "4" and fn:string($role)!="") then
3221
+ marc2bfutils:chopPunctuation(marc2bfutils:clean-string(fn:string($role)),".")
3222
+ else
3223
+ marc2bfutils:generate-role-code(marc2bfutils:clean-string(fn:string($role)))
3224
+
3225
+ let $label := if ($d/@tag!='534') then
3226
+ fn:string-join($d/marcxml:subfield[@code='a' or @code='b' or @code='c' or @code='d' or @code='q' or @code='n'] , " ")
3227
+ else
3228
+ fn:string($d/marcxml:subfield[@code='a' ])
3229
+
3230
+ let $aLabel := marc2bfutils:clean-name-string($label)
3231
+
3232
+ let $elementList := if ($d/@tag!='534'
3233
+ and
3234
+ fn:not(fn:matches(fn:string-join($d/marcxml:subfield[@code="0"]," "),"(http://|\(uri\)|\(DE-588\))" ) ) ) then
3235
+ (:if there's a $0 uri, then we don't need the madsrdf:)
3236
+ element bf:hasAuthority{
3237
+ element madsrdf:Authority {
3238
+ element madsrdf:authoritativeLabel {$aLabel}
3239
+ }
3240
+ }
3241
+ else () (: 534 $a is not parsed:)
3242
+
3243
+ let $class :=
3244
+ if ( fn:ends-with(fn:string($d/@tag), "00") and fn:string($d/@ind1)="3") then
3245
+ "bf:Family"
3246
+ else if ( fn:ends-with(fn:string($d/@tag), "00") ) then
3247
+ "bf:Person"
3248
+ else if ( fn:ends-with(fn:string($d/@tag), "10") ) then
3249
+ "bf:Organization"
3250
+ else if ( fn:ends-with(fn:string($d/@tag), "11") ) then
3251
+ "bf:Meeting"
3252
+ else if ( fn:string($d/@tag)= "720" and fn:string($d/@ind1)="1") then
3253
+ "bf:Person" (:????:)
3254
+ else if ( fn:string($d/@tag)= "720" and fn:string($d/@ind1)="2") then
3255
+ "bf:Organization" (:may be a meeting:)
3256
+ else
3257
+ "bf:Agent"
3258
+
3259
+ let $tag := fn:string($d/@tag)
3260
+ let $desc-role:=if (fn:starts-with($tag , "10") or fn:starts-with($tag , "11")) then "primary" else ()
3261
+ let $resourceRoles :=
3262
+ (:if ($relatorCode ne "") then:)
3263
+ ( if (fn:string-join($relatorCodes,"") = "") then
3264
+ (:
3265
+ k-note, added substring call because of cruddy data.
3266
+ record 16963854 had "aut 146781635" in it
3267
+ Actually, I'm going to undo this because this is a cataloging error
3268
+ and we want those caught. was fn:substring($relatorCode, 1, 3))
3269
+ :)
3270
+ (: fn:concat("relators:" , $relatorCode):)
3271
+ if ( fn:starts-with($tag, "1") and fn:not($d/marcxml:subfield[@code="4"])) then
3272
+ "bf:creator"
3273
+ else if ( fn:starts-with($tag, "7") and $d/marcxml:subfield[@code="t"] and fn:not($d/marcxml:subfield[@code="4"]) ) then
3274
+ "bf:contributor"
3275
+ else
3276
+ "bf:contributor"
3277
+ else
3278
+ for $role in $relatorCodes[fn:string(.) !=""]
3279
+ return fn:concat("relators:" , $role)
3280
+ )
3281
+
3282
+ (: resourceRole inside the authority makes it un-re-useable; removed 2013-12-03
3283
+ let $resourceRoleTerms :=
3284
+ for $r in $d/marcxml:subfield[@code="e"]
3285
+ return element bf:resourceRole {fn:string($r)}
3286
+ :)
3287
+ let $bio-links:=
3288
+ if ( $d/../marcxml:datafield[fn:matches(@tag,"(856|859)")][fn:matches(fn:string(marcxml:subfield[@code="3"]),"contributor","i")]) then
3289
+ (:set up annotations for each contributor bio link:)
3290
+ for $link in $d/../marcxml:datafield[fn:matches(@tag,"(856|859)")][fn:matches(fn:string(marcxml:subfield[@code="3"]),"contributor","i")]
3291
+ return mbshared:generate-instance-from856($link, "person")
3292
+ else
3293
+ ()
3294
+ let $system-number:=
3295
+ for $sys-num in $d/marcxml:subfield[@code="0"]
3296
+ return mbshared:handle-system-number($sys-num)
3297
+ return
3298
+
3299
+ for $role in $resourceRoles
3300
+ return element {fn:string($role)} {
3301
+ element {$class} {
3302
+ element bf:label { marc2bfutils:clean-name-string($label)},
3303
+ if ($d/@tag!='534') then element bf:authorizedAccessPoint {$aLabel} else (),
3304
+ mbshared:generate-880-label($d,"name"),
3305
+ $elementList,
3306
+ $system-number,
3307
+ $bio-links
3308
+ }
3309
+ }
3310
+
3311
+ };
3312
+
3313
+ (:~
3314
+ : This function generates a name from a Statement of
3315
+ : Responsibility of string. It's going to take work.
3316
+ :
3317
+ : @param $c is the string to parse
3318
+ : @param $prop is the name of the prop to create
3319
+ : @return element
3320
+ :)
3321
+ declare function mbshared:get-name-fromSOR(
3322
+ $c as xs:string,
3323
+ $prop as xs:string)
3324
+ {
3325
+ let $role :=
3326
+ if ( fn:contains($c, " by") ) then
3327
+ if ( fn:normalize-space(fn:replace($c, " by", "")) eq "" ) then
3328
+ ""
3329
+ else
3330
+ fn:concat(fn:substring-before($c, " by"), " by")
3331
+ else
3332
+ ""
3333
+ let $role := fn:normalize-space($role)
3334
+
3335
+ let $name :=
3336
+ if ( fn:contains($c, " by") ) then
3337
+ fn:substring-after($c, " by")
3338
+ else
3339
+ $c
3340
+ let $name := fn:normalize-space($name)
3341
+ return
3342
+ element {$prop} {
3343
+ element bf:Agent {
3344
+ element bf:label {$name}
3345
+ }
3346
+ }
3347
+
3348
+ };
3349
+ (:~
3350
+ : This is the function gets the intendedaudience entity from 521.
3351
+ :
3352
+ : @param $tag element is the datafield 521
3353
+ : @return bf:* as element()
3354
+ :)
3355
+ declare function mbshared:get-521audience(
3356
+ $tag as element(marcxml:datafield)
3357
+ ) as item()*
3358
+ {
3359
+ element bf:intendedAudience {
3360
+ element bf:IntendedAudience {
3361
+ element bf:audience {fn:string($tag/marcxml:subfield[@code="a"])},
3362
+ if ($tag/marcxml:subfield[@code="b"]) then element bf:audienceAssigner{fn:string($tag/marcxml:subfield[@code="b"])} else ()
3363
+ }
3364
+ }
3365
+ (:
3366
+ let $type:= if ($tag/@ind1=" ") then "Audience: " else if ($tag/@ind1=" 0") then "Reading grade level" else if ($tag/@ind1="1") then "Interest age level" else if ($tag/@ind1="2") then "Interest grade level" else if ($tag/@ind1="3") then "Special audience characteristics" else if ($tag/@ind1="4") then "Motivation/interest level" else ()
3367
+
3368
+ return if ($type= "Audience: ") then
3369
+ if ( fn:not($tag/marcxml:subfield[@code="b"]) ) then
3370
+ element bf:intendedAudience {fn:concat($type,": ",$tag/marcxml:subfield[@code="a"])}
3371
+ else element bf:intendedAudience {
3372
+ element bf:IntendedAudience {
3373
+ element bf:audience {fn:concat($type,": ",$tag/marcxml:subfield[@code="a"])},
3374
+ element bf:audienceAssigner{fn:string($tag/marcxml:subfield[@code="b"])}
3375
+ }}
3376
+ else if ($type) then
3377
+ element bf:intendedAudience {
3378
+ element bf:IntendedAudience {
3379
+ if ($tag/marcxml:subfield[@code="a"]) then
3380
+ element bf:audience {fn:string($tag/marcxml:subfield[@code="a"])}
3381
+ else (),
3382
+ element bf:audienceType {$type},
3383
+ if ($tag/marcxml:subfield[@code="b"]) then
3384
+ element bf:audienceAssigner{fn:string($tag/marcxml:subfield[@code="b"])}
3385
+ else ()
3386
+ }
3387
+ }
3388
+ else if ($tag/marcxml:subfield[@code="b"]) then
3389
+ element bf:intendedAudience {
3390
+ element bf:IntendedAudience {
3391
+ element bf:audienceType {$type},
3392
+ if ($tag/marcxml:subfield[@code="a"]) then
3393
+ element bf:audience {fn:string($tag/marcxml:subfield[@code="a"])}
3394
+ else (),
3395
+ element bf:audienceAssigner{fn:string($tag/marcxml:subfield[@code="b"])}
3396
+ }}
3397
+ else if ($tag/marcxml:subfield[@code="a"]) then
3398
+ element bf:intendedAudience {fn:concat($type,": ",$tag/marcxml:subfield[@code="a"])}
3399
+ else ()
3400
+ :)
3401
+ };
3402
+ (:~
3403
+ : This is the function generates an Instance subclass.
3404
+ :
3405
+ : @param $marcxml element is the MARCXML
3406
+ : @return bf:* as element()
3407
+ :)
3408
+ declare function mbshared:get-instanceTypes(
3409
+ $record as element(marcxml:record)
3410
+ ) as item()*
3411
+ {
3412
+ let $leader:=fn:string($record/marcxml:leader)
3413
+ let $leader06:=fn:substring($leader,7,1)
3414
+ let $leader07:=fn:substring($leader,8,1)
3415
+ let $leader08:=fn:substring($leader,9,1)
3416
+ let $leader19:=fn:substring($leader,20,1)
3417
+
3418
+ let $types:=
3419
+ ( for $cf in $record/marcxml:controlfield[@tag="007"]/fn:substring(text(),1,1)
3420
+ for $t in $marc2bfutils:instanceTypes/type[@cf007]
3421
+ where fn:matches($cf,$t/@cf007)
3422
+ return fn:string($t),
3423
+
3424
+ for $field in $record/marcxml:datafield[@tag="336"]/marcxml:subfield[@code="a"]
3425
+ for $t in $marc2bfutils:instanceTypes/type[@sf336a]
3426
+ where fn:matches(fn:string($field),$t/@sf336a)
3427
+ return fn:string($t),
3428
+
3429
+ for $field in $record/marcxml:datafield[@tag="336"]/marcxml:subfield[@code="b"]
3430
+ for $t in $marc2bfutils:instanceTypes/type[@sf336b]
3431
+ where fn:matches(fn:string($field),$t/@sf336b)
3432
+ return fn:string($t),
3433
+
3434
+ for $t in $marc2bfutils:instanceTypes/type
3435
+ where $t/@leader6 eq $leader06
3436
+ return fn:string($t),
3437
+ for $t in $marc2bfutils:instanceTypes/type
3438
+ where $t/@leader8 eq $leader08
3439
+ return fn:string($t),
3440
+ if (fn:matches($leader07,"(a|m)") and fn:not($leader19="a")) then "Monograph"
3441
+ else if (fn:matches($leader07,"(a|m)") and $leader19="a") then "Multipart monograph"
3442
+ else (),
3443
+ if ($leader07='s') then "Serial"
3444
+ else if ($leader07='i') then "Integrating"
3445
+ else (),
3446
+ if (fn:matches($leader07,"(c|d)")) then "Collection" else (),
3447
+ if (fn:matches($leader06,"(d|f|t)")) then "Manuscript" else (),
3448
+ if ($leader08="a") then "Archival" else (),
3449
+ if ($record/marcxml:datafield[@tag="856"][@ind2="0"][marcxml:subfield[@code="u"]]) then "Electronic" else ()
3450
+ )
3451
+ return $types
3452
+
3453
+ };
3454
+ (:~
3455
+ : This is the function generates a work subclass.
3456
+ : test on this bib id : 11510969
3457
+ : @param $marcxml element is the MARCXML
3458
+ : @return bf:* as element()
3459
+ :)
3460
+ declare function mbshared:get-resourceTypes(
3461
+ $record as element(marcxml:record)
3462
+ ) as item()*
3463
+ {
3464
+
3465
+ let $leader06 := fn:substring(fn:string($record/marcxml:leader), 7, 1)
3466
+ let $types:=
3467
+ ( for $cf in $record/marcxml:controlfield[@tag="007"]/fn:substring(text(),1,1)
3468
+ (:00 - Category of material :)
3469
+ for $t in $marc2bfutils:resourceTypes/type[@cf007]
3470
+ where fn:matches($cf,$t/@cf007)
3471
+ return fn:string($t) ,
3472
+
3473
+ for $field in $record/marcxml:datafield[@tag="336"]/marcxml:subfield[@code="a"]
3474
+ for $t in $marc2bfutils:resourceTypes/type[@sf336a]
3475
+ where fn:matches(fn:string($field),$t/@sf336a)
3476
+ return fn:string($t),
3477
+
3478
+ for $field in $record/marcxml:datafield[@tag="336"]/marcxml:subfield[@code="b"]
3479
+ for $t in $marc2bfutils:resourceTypes/type[@sf336b]
3480
+ where fn:matches(fn:string($field),$t/@sf336b)
3481
+ return fn:string($t),
3482
+
3483
+
3484
+ for $field in $record/marcxml:datafield[@tag="337"]/marcxml:subfield[@code="a"]
3485
+ for $t in $marc2bfutils:resourceTypes/type[@sf337a]
3486
+ where fn:matches(fn:string($field),$t/@sf337a)
3487
+ return fn:string($t) ,
3488
+
3489
+ for $field in $record/marcxml:datafield[@tag="337"]/marcxml:subfield[@code="b"]
3490
+ for $t in $marc2bfutils:resourceTypes/type[@sf337b]
3491
+ where fn:matches(fn:string($field),$t/@sf337b)
3492
+ return fn:string($t) ,
3493
+ for $t in $marc2bfutils:resourceTypes/type
3494
+ where $t/@leader6 eq $leader06
3495
+ return fn:string($t)
3496
+ )
3497
+ return $types
3498
+
3499
+ };
3500
+
3501
+ (:~
3502
+ : This returns a basic title from 245.
3503
+ : actually 243|245|246|247|222|242|210
3504
+ :
3505
+ : @param $d element is the marcxml:datafield
3506
+ : @param $domain "work" or "instance" to name the property
3507
+ :
3508
+ : @return sequence of bf:title, workTitle, instanceTitle, nonsort, sysnum etc.
3509
+ : drop the $h from the work title????
3510
+ :)
3511
+ declare function mbshared:get-title(
3512
+ $d as element(marcxml:datafield),
3513
+ $domain as xs:string
3514
+ )
3515
+ {
3516
+
3517
+ let $title := fn:replace(fn:string($d/marcxml:subfield[@code="a"]),"^(.+)/$","$1")
3518
+
3519
+ let $title :=
3520
+ if (fn:ends-with($title, ".")) then
3521
+ fn:substring($title, 1, fn:string-length($title) - 1 )
3522
+ else
3523
+ $title
3524
+
3525
+
3526
+ let $title := if (fn:contains($title,"=")) then
3527
+ fn:substring-before($title, "=")
3528
+ else
3529
+ fn:normalize-space($title)
3530
+ let $element-name :=
3531
+ if (fn:matches(fn:string($d/@tag),"(246|247|242)" )) then
3532
+ "bf:titleVariation"
3533
+ else if ($d/@tag = "222" ) then
3534
+ "bf:keyTitle"
3535
+ else if ($d/@tag ="210" ) then
3536
+ "bf:abbreviatedTitle"
3537
+ else if ($domain="work") then
3538
+ "bf:workTitle"
3539
+ else (:245:)
3540
+ "bf:instanceTitle"
3541
+
3542
+ let $lang-attribute := if ($d/@tag = "242" and $d/marcxml:subfield[@code = "y"] ne "" ) then
3543
+ attribute xml:lang {fn:string($d/marcxml:subfield[@code = "y"][1])}
3544
+ else
3545
+ ()
3546
+ let $title-type:=
3547
+ if (fn:matches($d/@tag , "(242|246|247)")) then
3548
+ if ($d/@tag="242") then "Translated title"
3549
+ else if ($d/@tag="247") then "Former title"
3550
+ else (:246 :)
3551
+ if ($d/@ind2=" " and $d/marcxml:subfield[@code = "i"]) then
3552
+ fn:string($d/marcxml:subfield[@code = "i"])
3553
+ else if ($d/@ind2="0") then "portion"
3554
+ else if ($d/@ind2="1") then "parallel"
3555
+ else if ($d/@ind2="2") then "distinctive"
3556
+ else if ($d/@ind2="4") then "cover"
3557
+ else if ($d/@ind2="6") then "caption"
3558
+ else if ($d/@ind2="7") then "running"
3559
+ else if ($d/@ind2="8") then "spine"
3560
+ else ()
3561
+ else
3562
+ ""
3563
+ let $parallel:=
3564
+ if (fn:contains(fn:string($d/marcxml:subfield[@code="a"]),"=")) then
3565
+ element {$element-name} { element bf:Title {
3566
+ element bf:titleValue {marc2bfutils:clean-title-string($d/marcxml:subfield[@code="b"])},
3567
+ element bf:titleType {"parallel"}
3568
+ }
3569
+ }
3570
+ else if (fn:contains(fn:string($d/marcxml:subfield[@code="b"][1]),"=")) then
3571
+ (:$b: parallel title is the part after the = :)
3572
+ element {$element-name} { element bf:Title {
3573
+ element bf:titleValue {marc2bfutils:clean-title-string(fn:substring-after($d/marcxml:subfield[@code="b"][1],"="))},
3574
+ element bf:titleType {"parallel"}
3575
+ }
3576
+ }
3577
+ else if (fn:contains(fn:string($d/marcxml:subfield[@code="c"]),"=")) then
3578
+ (:$c eng stmt resp = foreign title / foreign resp . so the parallel title is after the =, before the / (resp stmt handled elsewhere) :)
3579
+ element {$element-name} { element bf:Title {
3580
+ element bf:titleValue {
3581
+ if (fn:contains(fn:string($d/marcxml:subfield[@code="c"]),"/")) then
3582
+ marc2bfutils:clean-title-string(fn:replace($d/marcxml:subfield[@code="c"],"^.+=(.+)/","$1"))
3583
+ else
3584
+ marc2bfutils:clean-title-string(fn:substring-after($d/marcxml:subfield[@code="c"],"="))
3585
+ },
3586
+ element bf:titleType {"parallel"}
3587
+ }
3588
+ }
3589
+
3590
+ else ()
3591
+
3592
+
3593
+ let $constructed-title:=
3594
+ element {$element-name} {
3595
+ element bf:Title {
3596
+ if ($title-type ne "") then
3597
+ element bf:titleType {$title-type}
3598
+ else (),
3599
+
3600
+ if ($d/@tag="245") then element bf:titleValue {$title} else (),
3601
+ if ($d/@tag!="210" and $d/@tag!="222" and fn:not(fn:contains($title,"=")) and $d/marcxml:subfield[@code="b"]) then
3602
+ (:$b isn't repeatable but gwu had some!:)
3603
+ for $sub in $d/marcxml:subfield[@code="b"]
3604
+ return if (fn:not(fn:contains($sub,"="))) then
3605
+ element bf:subtitle { marc2bfutils:clean-title-string($sub)}
3606
+ else
3607
+ element bf:subtitle { fn:substring-after(marc2bfutils:clean-title-string($sub),"=")}
3608
+ else (),
3609
+ mbshared:generate-simple-property($d,"title"),
3610
+ mbshared:generate-880-label($d,"title")
3611
+ }
3612
+ } (:end Title:)
3613
+
3614
+ return
3615
+ ( (:element bf:title { $lang-attribute, $title }, :)
3616
+ (:this is wasteful if there's only an $a, but there is no simple string property for keytitle etc.:)
3617
+ $constructed-title,
3618
+ mbshared:generate-titleNonsort($d,$title, $element-name),
3619
+ $parallel,
3620
+ for $sys-num in $d/marcxml:subfield[@code="0"]
3621
+ return mbshared:handle-system-number($sys-num)
3622
+ )
3623
+ };
3624
+ (:~
3625
+ : This function generates a related work (rda expression?), as translation of from the 100, 240.
3626
+ : It takes a 130 or 240 element.
3627
+ : It generates a bf:translationOf/bf:Work
3628
+ :
3629
+ : @param $d element is the marcxml:datafield
3630
+ : @return bf:translationOf
3631
+ :)
3632
+ declare function mbshared:generate-translationOf ( $d as element(marcxml:datafield)
3633
+ ) as element( bf:translationOf)
3634
+
3635
+ {
3636
+
3637
+ let $aLabel := marc2bfutils:clean-title-string(fn:string-join($d/marcxml:subfield[fn:matches(@code,"(a|d|f|g|h|k)") ]," "))
3638
+ return element bf:translationOf {
3639
+ element bf:Work {
3640
+
3641
+ element bf:title {$aLabel},
3642
+ mbshared:generate-titleNonsort($d,$aLabel,"bf:title") ,
3643
+ element madsrdf:authoritativeLabel{$aLabel},
3644
+ element bf:authorizedAccessPoint {$aLabel},
3645
+
3646
+ if ($d/../marcxml:datafield[@tag="100"]) then
3647
+ element bf:creator{
3648
+ element bf:Agent {
3649
+ element bf:label {fn:string($d/../marcxml:datafield[@tag="100"]/marcxml:subfield[@code="a"])}
3650
+ }
3651
+ }
3652
+ else ()
3653
+ }
3654
+ }
3655
+
3656
+
3657
+ };
3658
+
3659
+ (:~
3660
+ : This is the function generates a literal property or simple uri from a marc tag
3661
+ : Options in this function are a prefix, (@startwith), indicator2, and concatenation of multiple @sfcodes.
3662
+ : If @ind2 is absent on the node, there is no test, otherwise it must match the datafield @ind2
3663
+ : <node domain="work" tag ="500" property="note" ind2=" " sfcodes="ab" >Note</note>
3664
+ :
3665
+ : if there's only one subfield code in sfcodes, it looks for all those subfields (repeatables)
3666
+ : if there's a string of subfields, it does a stringjoin of all, but still creates a sequence in $text
3667
+ : @stringjoin could be on node; else " "
3668
+ : @param $d element is the MARCXML tag
3669
+ : @param $domain element is the domain for this element to sit in. is this needed?
3670
+ : maybe needed for building related works??
3671
+ : @return bf:* as element()
3672
+ :
3673
+ :)
3674
+ declare function mbshared:generate-simple-property(
3675
+ $d as element(marcxml:datafield)*,
3676
+ $domain as xs:string
3677
+ )
3678
+ {
3679
+ (:all the nodes in this domain with this datafield's tag, where there's no @ind1 or it matches the datafield's, and no ind2 or it matches the datafields:)
3680
+ for $node in $mbshared:simple-properties//node[fn:string(@domain)=$domain][@tag=$d/@tag][ fn:not(@ind1) or @ind1=$d/@ind1][ fn:not(@ind2) or @ind2=$d/@ind2]
3681
+ let $return-codes:= if ($node/@sfcodes) then fn:string($node/@sfcodes) else "a"
3682
+ let $startwith:=
3683
+ if ($d/@tag="511" and $d/@ind1="0") then
3684
+ ""
3685
+ else
3686
+ fn:string($node/@startwith)
3687
+
3688
+ return
3689
+ if ( $d/marcxml:subfield[fn:contains($return-codes,@code)] ) then
3690
+ let $text:= if (fn:string-length($return-codes) > 1) then
3691
+ let $stringjoin:= if ($node/@stringjoin) then fn:string($node/@stringjoin) else " "
3692
+ return element wrap{ marc2bfutils:clean-string(fn:string-join($d/marcxml:subfield[fn:contains($return-codes,@code)],$stringjoin))}
3693
+ else
3694
+ for $s in $d/marcxml:subfield[fn:contains($return-codes,@code)]
3695
+ return element wrap{ if (fn:matches($s/parent::datafield/@tag,"^5.+$"))then
3696
+ fn:string($s)
3697
+ else
3698
+ marc2bfutils:clean-string(fn:string($s))
3699
+ }
3700
+
3701
+ return
3702
+ for $i in $text
3703
+ return
3704
+ element {fn:concat("bf:",fn:string($node/@property))} {
3705
+ (:for identifiers, if it's oclc and there's an oclc id (035a) return attribute/uri, else return bf:Id:)
3706
+ if (fn:string($node/@group)="identifiers") then
3707
+ if (fn:starts-with($i,"(OCoLC)") and fn:contains($node/@uri,"worldcat") ) then
3708
+ let $s := marc2bfutils:clean-string(fn:replace($i, "\(OCoLC\)", ""))
3709
+ return attribute rdf:resource{fn:concat(fn:string($node/@uri),fn:replace($s,"(^ocm|^ocn)","")) }
3710
+ else if (fn:contains($node/@uri,"id.loc.gov/vocabulary/organizations") ) then
3711
+ let $s := marc2bfutils:clean-string(fn:lower-case($i))
3712
+ return attribute rdf:resource{fn:concat(fn:string($node/@uri),$s) }
3713
+ else
3714
+ element bf:Identifier {
3715
+ element bf:identifierValue {
3716
+ if (fn:starts-with($i, "(DLC)" )) then
3717
+ fn:normalize-space(fn:replace($i,"(\(DLC\))(.+)$","$2" ))
3718
+ else
3719
+ fn:normalize-space(fn:concat($startwith, $i) )
3720
+ },
3721
+ element bf:identifierScheme {
3722
+ if (fn:starts-with($i, "(DLC)" )) then
3723
+ attribute rdf:resource {"http://id.loc.gov/vocabulary/identifiers/lccn"}
3724
+ else
3725
+ attribute rdf:resource {fn:concat("http://id.loc.gov/vocabulary/identifiers/",fn:string($node/@property) ) }}
3726
+ }
3727
+
3728
+
3729
+ (:non-identifiers:)
3730
+ else if (fn:not($node/@uri)) then
3731
+ fn:normalize-space(fn:concat($startwith, $i) )
3732
+ (:nodes with uris: :)
3733
+ else if (fn:contains(fn:string($node/@uri),"loc.gov/vocabulary/organizations")) then
3734
+ let $s:=fn:lower-case(fn:normalize-space($i))
3735
+ return
3736
+ if (fn:string-length($s) lt 10 and fn:not(fn:contains($s, " "))) then
3737
+
3738
+ (:if (fn:string-length($s) lt 10 and fn:not(fn:contains($s, " ")) or fn:not(fn:starts-with($i,"Ca") ) ) then:)
3739
+ attribute rdf:resource{fn:concat(fn:string($node/@uri),fn:replace($s,"-",""))}
3740
+ else
3741
+ element bf:Organization {element bf:label {$s}}
3742
+ else if (fn:contains(fn:string($node/@property),"lccn")) then
3743
+ attribute rdf:resource{fn:concat(fn:string($node/@uri),fn:replace($i," ","")) }
3744
+ else
3745
+ attribute rdf:resource{fn:concat(fn:string($node/@uri),$i)}
3746
+ }
3747
+
3748
+ else (:no matching nodes for this datafield:)
3749
+ ()
3750
+
3751
+ };
3752
+ (:~
3753
+ : This is the function generates a literal property or simple uri from a string, using the nodes xml
3754
+ : Example of usage: you need to convert the content of a subfield before treating it like it's supposed to be treated.
3755
+ : 338 $a is the literal string, but you need the code, so you have to look it up.
3756
+ : let $code :=marc2bfutils:generate-carrier-code("volume")
3757
+ : mbshared:generate-property-from-text("338","a",$code,"work")
3758
+ : I don't have this in use. 338 is handled elsewhere
3759
+
3760
+ : Options in this function are a prefix, (@startwith), indicator2, and concatenation of multiple @sfcodes.
3761
+ : If @ind2 is absent on the node, there is no test, otherwise it must match the datafield @ind2
3762
+ : <node domain="work" tag ="505" property="contents" ind2=" " sfcodes="agrtu" >Formatted Contents Note</note>
3763
+ :
3764
+ : @param $d element is the MARCXML tag
3765
+ : @param $sfcodes element is the marcxml subfield set that are included
3766
+ : @param $domain element is the domain for this element.
3767
+ :
3768
+ : @return bf:* as element()
3769
+ :
3770
+ :)
3771
+ declare function mbshared:generate-property-from-text(
3772
+ $tag as xs:string,
3773
+ $sfcodes as xs:string,
3774
+ $text as xs:string,
3775
+ $domain as xs:string
3776
+ ) as element ()*
3777
+ {
3778
+ for $node in $mbshared:simple-properties//node[fn:string(@domain)=$domain][@tag=$tag][fn:contains(fn:string(@sfcodes),$sfcodes) or @sfcodes="" or $sfcodes=""]
3779
+ let $return-codes:=
3780
+ if ($node/@sfcodes) then fn:string($node/@sfcodes) else "a"
3781
+ let $startwith:=fn:string($node/@startwith)
3782
+
3783
+ return
3784
+ element {fn:concat("bf:",fn:string($node/@property))} {
3785
+ if (fn:not($node/@uri)) then
3786
+ fn:normalize-space(fn:concat($startwith, $text) )
3787
+ else if (fn:contains(fn:string($node/@uri),"loc.gov/vocabulary/organizations")) then
3788
+ let $text:=fn:lower-case(fn:normalize-space($text))
3789
+ return attribute rdf:resource{fn:concat(fn:string($node/@uri),fn:replace($text,"-",""))}
3790
+ else if (fn:contains(fn:string($node/@property),"lccn")) then
3791
+ attribute rdf:resource{fn:concat(fn:string($node/@uri),fn:replace($text," ",""))
3792
+ }
3793
+ else
3794
+ attribute rdf:resource{fn:concat(fn:string($node/@uri),$text)}
3795
+ }
3796
+ };
3797
+ (:~
3798
+ : This function generates a Work based on the uniformTitle.
3799
+ : It takes a specific datafield (130 or 240) as input.
3800
+ : It generates a bf:Work as output.
3801
+ :
3802
+ : @param $d element is the marcxml:datafield
3803
+ : @return bf:Work
3804
+ :)
3805
+ declare function mbshared:get-uniformTitle(
3806
+ $d as element(marcxml:datafield)
3807
+ )
3808
+ (:as element(bf:Work):)
3809
+ {
3810
+ (:let $label := fn:string($d/marcxml:subfield["a"][1]):)
3811
+ (:??? filter out nonsorting chars??? 880s?:)
3812
+
3813
+ let $aLabel := marc2bfutils:clean-title-string(fn:string-join($d/marcxml:subfield[@code ne '0' and @code!='6' and @code!='8'] , " "))
3814
+ let $translationOf :=
3815
+ if ($d/marcxml:subfield[@code="l"]) then
3816
+ (for $s in $d/marcxml:subfield[@code="l"]
3817
+ return marc2bfutils:process-language($s),
3818
+ (:let $lang:=
3819
+ $marc2bfutils:lang-xwalk/language[@language-name=marc2bfutils:chopPunctuation($s,".")]/iso6392[1]
3820
+ return if ($lang!="")
3821
+ then
3822
+ element bf:language {
3823
+ attribute rdf:resource { fn:concat("http://id.loc.gov/vocabulary/languages/",$lang)}
3824
+ }
3825
+ else element bf:languageNote {marc2bfutils:clean-string($s)},
3826
+ :)
3827
+ mbshared:generate-880-label($d,"title"),
3828
+ mbshared:generate-translationOf($d)
3829
+ )
3830
+ else ()
3831
+
3832
+ let $title-nonsort:=mbshared:generate-titleNonsort($d,$aLabel,"bf:title")
3833
+ let $ut-local-id:=if ($d/marcxml:subfield[@code = '0' ]) then
3834
+ element bf:identifier {
3835
+ element bf:Identifier {
3836
+ element bf:identifierValue {fn:string($d/marcxml:subfield[@code = '0' ])},
3837
+ element bf:identifierScheme { attribute rdf:resource {"http://id.loc.gov/vocabulary/identifiers/local"} }
3838
+ }
3839
+ }
3840
+
3841
+ else ()
3842
+
3843
+ return
3844
+
3845
+ element bf:Work {
3846
+ (:element bf:label {$aLabel},:)
3847
+ element madsrdf:authoritativeLabel{ fn:string($aLabel)},
3848
+ $title-nonsort,
3849
+ element bf:workTitle {element bf:Title{ mbshared:generate-simple-property($d,"title"),
3850
+ mbshared:generate-880-label($d,"title")
3851
+ }
3852
+ },
3853
+ $ut-local-id,
3854
+ $translationOf
3855
+ }
3856
+ };
3857
+
3858
+ (:~
3859
+ : This function takes an ISBN string and
3860
+ : determines if it's 10 or 13, and returns both the 10 and 13 for this one.
3861
+ :
3862
+ : @param $s is fn:string
3863
+ : @return wrap/bf:isbn element()
3864
+ :)
3865
+
3866
+ declare function mbshared:get-isbn($isbn as xs:string ) as element() {
3867
+ (:
3868
+ let $isbn1:="9780792312307" (:produces 0792312309 ok:)
3869
+ let $isbn1:="0792312309" (:produces 9780792312307 ok:)
3870
+ let $isbn1:="0-571-08989-5" (:produces 9780571089895 ok:)
3871
+ let $isbn1:="0 571 08989 5" (:produces 9780571089895 ok:)
3872
+ verify here:http://www.isbn.org/converterpub.asp
3873
+ let $isbn:="paperback" (:produces "error" ok:)
3874
+ :)
3875
+
3876
+ let $clean-isbn:=fn:replace($isbn,"[- ]+","")
3877
+ (:let $isbn-num:=replace($clean-isbn,"^[^0-9]*(\d+)[^0-9]*$","$1" ):)
3878
+ (: test on isbn 10, 13, hyphens, empty, strings only :)
3879
+
3880
+ let $isbn-num1:= fn:replace($clean-isbn,"^[^0-9]*(\d+)[^0-9]*$","$1" )
3881
+ let $isbn-num:= if (fn:string-length($isbn-num1)=9) then fn:concat($isbn-num1,'X') else $isbn-num1
3882
+
3883
+ (: test on isbn 10, 13, hyphens, empty, strings only :)
3884
+
3885
+ return
3886
+ if (fn:number($isbn-num) or fn:number($isbn-num1) ) then
3887
+
3888
+ if ( fn:string-length($isbn-num) = 10 ) then
3889
+ let $isbn12:= fn:concat("978",fn:substring($isbn-num,1,9))
3890
+ let $odds:= fn:number(fn:substring($isbn12,1,1)) + fn:number(fn:substring($isbn12,3,1)) +fn:number(fn:substring($isbn12,5,1)) + fn:number(fn:substring($isbn12,7,1)) +fn:number(fn:substring($isbn12,9,1)) +fn:number(fn:substring($isbn12,11,1))
3891
+ let $evens:= (fn:number(fn:substring($isbn12,2,1)) + fn:number(fn:substring($isbn12,4,1)) +fn:number(fn:substring($isbn12,6,1)) + fn:number(fn:substring($isbn12,8,1)) +fn:number(fn:substring($isbn12,10,1)) +fn:number(fn:substring($isbn12,12,1)) ) * 3
3892
+ let $chk:=
3893
+ if ( (($odds + $evens) mod 10) = 0) then
3894
+ 0
3895
+ else
3896
+ 10 - (($odds + $evens) mod 10)
3897
+ return
3898
+ element wrap {
3899
+ element bf:isbn10 {$isbn-num},
3900
+ element bf:isbn13 { fn:concat($isbn12,$chk)}
3901
+ }
3902
+
3903
+ else (: isbn13 to 10 :)
3904
+ let $isbn9:=fn:substring($isbn-num,4,9)
3905
+ let $sum:= (fn:number(fn:substring($isbn9,1,1)) * 1)
3906
+ + (fn:number(fn:substring($isbn9,2,1)) * 2)
3907
+ + (fn:number(fn:substring($isbn9,3,1)) * 3)
3908
+ + (fn:number(fn:substring($isbn9,4,1)) * 4)
3909
+ + (fn:number(fn:substring($isbn9,5,1)) * 5)
3910
+ + (fn:number(fn:substring($isbn9,6,1)) * 6)
3911
+ + (fn:number(fn:substring($isbn9,7,1)) * 7)
3912
+ + (fn:number(fn:substring($isbn9,8,1)) * 8)
3913
+ + (fn:number(fn:substring($isbn9,9,1)) * 9)
3914
+ let $check_dig:=
3915
+ if ( ($sum mod 11) = 10 ) then
3916
+ 'X'
3917
+ else
3918
+ ($sum mod 11)
3919
+ return
3920
+ element wrap {
3921
+ element bf:isbn10 {fn:concat($isbn9,$check_dig) },
3922
+ element bf:isbn13 {$isbn-num}
3923
+ }
3924
+
3925
+ else
3926
+ element wrap {
3927
+ }
3928
+
3929
+ };
3930
+ (:~
3931
+ : This function validates lc class content
3932
+ :
3933
+ : $string is the string content of the 050a as stripped to be compared
3934
+ : @return xs:string content or null
3935
+ :)
3936
+ declare function mbshared:validate-lcc(
3937
+ $string as xs:string
3938
+ ) as xs:boolean
3939
+ {
3940
+ let $validLCCs:=("DAW","DJK","KBM","KBP","KBR","KBU","KDC","KDE","KDG","KDK","KDZ","KEA","KEB","KEM","KEN","KEO","KEP","KEQ","KES","KEY","KEZ","KFA","KFC","KFD","KFF","KFG","KFH","KFI","KFK","KFL","KFM","KFN","KFO","KFP","KFR","KFS","KFT","KFU","KFV","KFW","KFX","KFZ","KGA","KGB","KGC","KGD","KGE","KGF","KGG","KGH","KGJ","KGK","KGL","KGM","KGN","KGP","KGQ","KGR","KGS","KGT","KGU","KGV","KGW","KGX","KGY","KGZ","KHA","KHC","KHD","KHF","KHH","KHK","KHL","KHM","KHN","KHP","KHQ","KHS","KHU","KHW","KJA","KJC","KJE","KJG","KJH","KJJ","KJK","KJM","KJN","KJP","KJR","KJS","KJT","KJV","KJW","KKA","KKB","KKC","KKE","KKF","KKG","KKH","KKI","KKJ","KKK","KKL","KKM","KKN","KKP","KKQ","KKR","KKS","KKT","KKV","KKW","KKX","KKY","KKZ","KLA","KLB","KLD","KLE","KLF","KLH","KLM","KLN","KLP","KLQ","KLR","KLS","KLT","KLV","KLW","KMC","KME","KMF","KMG","KMH","KMJ","KMK","KML","KMM","KMN","KMP","KMQ","KMS","KMT","KMU","KMV","KMX","KMY","KNC","KNE","KNF","KNG","KNH","KNK","KNL","KNM","KNN","KNP","KNQ","KNR","KNS","KNT","KNU","KNV","KNW","KNX","KNY","KPA","KPC","KPE","KPF","KPG","KPH","KPJ","KPK","KPL","KPM","KPP","KPS","KPT","KPV","KPW","KQC","KQE","KQG","KQH","KQJ","KQK","KQM","KQP","KQT","KQV","KQW","KQX","KRB","KRC","KRE","KRG","KRK","KRL","KRM","KRN","KRP","KRR","KRS","KRU","KRV","KRW","KRX","KRY","KSA","KSC","KSE","KSG","KSH","KSK","KSL","KSN","KSP","KSR","KSS","KST","KSU","KSV","KSW","KSX","KSY","KSZ","KTA","KTC","KTD","KTE","KTF","KTG","KTH","KTJ","KTK","KTL","KTN","KTQ","KTR","KTT","KTU","KTV","KTW","KTX","KTY","KTZ","KUA","KUB","KUC","KUD","KUE","KUF","KUG","KUH","KUN","KUQ","KVB","KVC","KVE","KVH","KVL","KVM","KVN","KVP","KVQ","KVR","KVS","KVU","KVW","KWA","KWC","KWE","KWG","KWH","KWL","KWP","KWQ","KWR","KWT","KWW","KWX","KZA","KZD","AC","AE","AG","AI","AM","AN","AP","AS","AY","AZ","BC","BD","BF","BH","BJ","BL","BM","BP","BQ","BR","BS","BT","BV","BX","CB","CC", "CD","CE","CJ","CN","CR","CS","CT","DA","DB","DC","DD","DE","DF","DG","DH","DJ","DK","DL","DP","DQ","DR","DS","DT","DU","DX","GA","GB","GC","GE","GF","GN","GR","GT","GV","HA","HB","HC","HD","HE","HF","HG","HJ","HM","HN","HQ","HS","HT","HV","HX","JA","JC","JF","JJ","JK","JL","JN","JQ","JS","JV","JX","JZ","KB","KD","KE","KF","KG","KH","KJ","KK","KL","KM","KN","KP","KQ","KR","KS","KT","KU","KV","KW","KZ","LA","LB","LC","LD","LE", "LF","LG","LH","LJ","LT","ML","MT","NA","NB","NC","ND","NE","NK","NX","PA","PB","PC","PD","PE","PF","PG","PH","PJ","PK","PL","PM","PN","PQ","PR","PS","PT","PZ","QA","QB","QC","QD","QE","QH","QK","QL","QM","QP","QR","RA","RB","RC","RD","RE","RF","RG", "RJ","RK","RL","RM","RS","RT","RV","RX","RZ","SB","SD","SF","SH","SK","TA","TC","TD","TE","TF","TG","TH","TJ","TK","TL","TN","TP","TR","TS","TT","TX","UA","UB","UC","UD","UE","UF","UG","UH","VA","VB","VC","VD","VE","VF","VG","VK","VM","ZA","A","B","C","D","E","F","G","H","J","K","L","M","N","P","Q","R","S","T","U","V","Z")
3941
+ return
3942
+ if ($string = $validLCCs) then
3943
+ fn:true()
3944
+ else (:invalid content in sfa:)
3945
+ fn:false()
3946
+ };
3947
+ (:~
3948
+ : This function generates uris to ddc, nlm,lcc classifications or a Classification node
3949
+ : classificationItem is retained, even though it looks like holdings data.
3950
+ : $marcxml is marcxml:record
3951
+ : $resource is work or instance
3952
+ : @return ??
3953
+ :)
3954
+ declare function mbshared:generate-classification(
3955
+ $marcxml as element(marcxml:record),
3956
+ $resource as xs:string
3957
+ ) as element ()*
3958
+ {(: interesting: try this first?
3959
+ and move this to the function for classif...
3960
+ For the Classify service at OCLC, when it is LCC we use a regular
3961
+ expression: "^[a-zA-Z]{1,3}[1-9].*$". For DDC we filter out the truncation symbols, spaces, quotes, etc.
3962
+
3963
+ -Steve Meyer
3964
+ :)
3965
+
3966
+ let $classes:=
3967
+ if ($resource="instance") then (:no classes currently defined for instance ; this should never happen:)
3968
+ $marc2bfutils:classes//property[@domain="Instance"]
3969
+ else
3970
+ $marc2bfutils:classes//property[@domain="Work"]
3971
+
3972
+ return
3973
+ ( for $this-tag in $marcxml/marcxml:datafield[fn:matches(@tag,"(060|061)")]
3974
+ for $cl in $this-tag/marcxml:subfield[@code="a"]
3975
+ let $class:= fn:tokenize(fn:string($cl),' ')[1]
3976
+ return
3977
+ element bf:classificationNlm{
3978
+ attribute rdf:resource {fn:concat( "http://nlm.example.org/classification/",fn:normalize-space($class))
3979
+ }
3980
+ },
3981
+ for $this-tag in $marcxml/marcxml:datafield[@tag="052"] return mbshared:generate-simple-property($this-tag ,"classification") ,
3982
+ for $this-tag in $marcxml/marcxml:datafield[fn:matches(@tag,"086")][marcxml:subfield[@code="z"]]
3983
+ let $scheme:=
3984
+ if ($this-tag[@ind1=" "] and $this-tag/marcxml:subfield[@code="2"] ) then
3985
+ element bf:classificationScheme {fn:string($this-tag/marcxml:subfield[@code="2"])}
3986
+ else if ($this-tag[@ind1="0"] ) then
3987
+ element bf:classificationScheme {attribute rdf:resource{ "http://id.loc.gov/authorities/classSchemes/sudocs"}}
3988
+ else if ($this-tag[@ind1="1"] ) then
3989
+ element bf:classificationScheme {attribute rdf:resource{ "http://id.loc.gov/authorities/classSchemes/cacodoc"}}
3990
+ else ()
3991
+ let $status:=element bf:classificationStatus {"canceled/invalid"}
3992
+ return for $cancel in $this-tag/marcxml:subfield[@code="z"]
3993
+ return
3994
+ element bf:classification {
3995
+ element bf:Classification {
3996
+ $scheme,
3997
+ $status,
3998
+ element bf:classificationNumber { fn:string($cancel)}
3999
+ }
4000
+ }
4001
+ ,
4002
+
4003
+
4004
+ for $this-tag in $marcxml/marcxml:datafield[fn:matches(@tag,"(050|055|070|080|082|083|084|086|090)")]
4005
+ for $cl in $this-tag/marcxml:subfield[@code="a"]
4006
+ let $valid:=
4007
+ if (fn:not(fn:matches($this-tag/@tag,"(050|055)"))) then
4008
+ fn:string($cl)
4009
+ else (:050 has non-class stuff in it: :)
4010
+ let $strip := fn:replace(fn:string($cl), "(\s+|\.).+$", "")
4011
+ let $subclassCode := fn:replace($strip, "\d", "")
4012
+ return
4013
+
4014
+ if ( mbshared:validate-lcc($subclassCode))
4015
+ then
4016
+ fn:string($strip)
4017
+ else (:invalid content in sfa:)
4018
+ ()
4019
+ return
4020
+ if ( $valid and
4021
+ fn:count($this-tag/marcxml:subfield)=1 and
4022
+ $this-tag/marcxml:subfield[@code="a"] or
4023
+ (fn:count($this-tag/marcxml:subfield)=2 and $this-tag/marcxml:subfield[@code="b"] )
4024
+ ) then
4025
+ let $property:=
4026
+ if (fn:exists($classes[@level="property"][fn:contains(@tag,$this-tag/@tag)])) then
4027
+ fn:string( $classes[@level="property"][fn:contains(@tag,$this-tag/@tag)]/@name)
4028
+ else
4029
+ "classification"
4030
+ return
4031
+ element {fn:concat("bf:",$property)} {
4032
+ if ($property="classificationLcc" ) then
4033
+ attribute rdf:resource {fn:concat( "http://id.loc.gov/authorities/classification/",fn:string($cl ))}
4034
+ else if ($property="classificationDdc" ) then
4035
+ let $ddc:=fn:normalize-space($this-tag/marcxml:subfield[@code="a"])
4036
+ let $ddc:=fn:replace($ddc,"^(.+) (.+)$", "$1")
4037
+ return
4038
+ (:attribute rdf:resource {fn:concat("http://dewey.info/class/",fn:normalize-space(fn:encode-for-uri($this-tag/marcxml:subfield[@code="a"])),"/about")}:)
4039
+ attribute rdf:resource {fn:concat("http://dewey.info/class/",fn:encode-for-uri($ddc),"/about")}
4040
+ else element bf:Classification {
4041
+ element bf:classificationNumber {fn:string($cl)},
4042
+ if ($this-tag[@tag="086"] and $this-tag[@ind1=" "] and $this-tag/marcxml:subfield[@code="2"] ) then
4043
+ element bf:classificationScheme {fn:string($this-tag/marcxml:subfield[@code="2"])}
4044
+ else if ($this-tag[@tag="086"] and $this-tag[@ind1="0"] ) then
4045
+ element bf:classificationScheme {"SUDOC"}
4046
+ else if ($this-tag[@tag="086"] and $this-tag[@ind1="1"] ) then
4047
+ element bf:classificationScheme {"Government of Canada classification"}
4048
+ else
4049
+ element bf:classificationScheme {fn:string($classes[@level="property"][fn:contains(@tag,$this-tag/@tag)]/@name)}
4050
+ }
4051
+ }
4052
+ else if ($valid ) then
4053
+ let $assigner:=
4054
+ if ($this-tag/@tag="050" and $this-tag/@ind2="0") then "dlc"
4055
+ else if (fn:matches($this-tag/@tag,"(060|061)")) then "dnlm"
4056
+ else if (fn:matches($this-tag/@tag,"(070|071)")) then "dnal"
4057
+ else if (fn:matches($this-tag/@tag,"(082|083|084)") and $this-tag/marcxml:subfield[@code="q"]) then fn:string($this-tag/marcxml:subfield[@code="q"])
4058
+ else ()
4059
+
4060
+ return
4061
+ element bf:classification {
4062
+ element bf:Classification {
4063
+ if (fn:matches($this-tag/@tag,"(050|090)")) then element bf:classificationScheme {attribute rdf:resource{ "http://id.loc.gov/authorities/classSchemes/lcc"} }
4064
+ else if (fn:matches($this-tag/@tag,"080")) then element bf:classificationScheme {attribute rdf:resource{ "http://id.loc.gov/authorities/classSchemes/nlm"}}
4065
+ else if (fn:matches($this-tag/@tag,"080")) then element bf:classificationScheme {attribute rdf:resource{ "http://id.loc.gov/authorities/classSchemes/udc"}}
4066
+ else if (fn:matches($this-tag/@tag,"082")) then element bf:classificationScheme {attribute rdf:resource{ "http://id.loc.gov/authorities/classSchemes/ddc"}}
4067
+ (:nal??:)
4068
+ else if (fn:matches($this-tag/@tag,"(084|086)") and $this-tag/marcxml:subfield[@code="2"] ) then element bf:classificationScheme {fn:string($this-tag/marcxml:subfield[@code="2"])}
4069
+ else ()
4070
+ ,
4071
+ if (fn:matches($this-tag/@tag,"(082|083)") and $this-tag/marcxml:subfield[@code="m"] ) then
4072
+ element bf:classificationDesignation {
4073
+ if ($this-tag/marcxml:subfield[@code="m"] ="a") then "standard"
4074
+ else if ($this-tag/marcxml:subfield[@code="m"] ="b") then "optional"
4075
+ else ()
4076
+ }
4077
+ else (),
4078
+ element bf:classificationNumber {fn:string($cl)},
4079
+ element bf:label {fn:string($cl)},
4080
+ if ( $assigner) then
4081
+ (:assigner is string, not uri:)
4082
+ (element bf:classificationAssigner {$assigner}
4083
+ )
4084
+ else (),
4085
+
4086
+ if (
4087
+ fn:matches($this-tag/@tag,"(080|082|083)") and fn:matches($this-tag/@ind1,"(0|1)")
4088
+ ) then
4089
+ let $this-edition:=
4090
+ if (fn:matches($this-tag/@tag,"(080|082|083)") and $this-tag/@ind1="1") then
4091
+ "abridged"
4092
+ else if (fn:matches($this-tag/@tag,"(080|082|083)") and $this-tag/@ind1="0") then
4093
+ "full"
4094
+ else if (fn:matches($this-tag/@tag,"(082|083)") and $this-tag/marcxml:subfield[@code="2"] ) then
4095
+ fn:string($this-tag/marcxml:subfield[@code="2"] )
4096
+ else ()
4097
+ return if ($this-edition ) then
4098
+ element bf:classificationEdition {$this-edition}
4099
+ (:mbshared:generate-property-from-text(fn:string($this-tag/@tag),"",$this-edition,"classification"):)
4100
+ else ()
4101
+
4102
+ else (),
4103
+ if (fn:matches($this-tag/@tag,"(082|083)") and $this-tag/marcxml:subfield[@code="2"] ) then
4104
+ element bf:classificationEdition {fn:string($this-tag/marcxml:subfield[@code="2"] )}
4105
+ else (),
4106
+ for $d in $this-tag[@tag="083"] return mbshared:generate-simple-property($d,"classification")
4107
+ }
4108
+ }
4109
+ else ()
4110
+
4111
+ )
4112
+ };