Skip to content

Commit

Permalink
Merge pull request #8 from HSG-Library/develop
Browse files Browse the repository at this point in the history
Allow to query for "upward hierarchies"
  • Loading branch information
d22 authored Oct 3, 2023
2 parents 5b0c138 + 6f46da1 commit 2ae4afe
Show file tree
Hide file tree
Showing 11 changed files with 1,653 additions and 2,915 deletions.
58 changes: 34 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ An [ExLibris Alma CloudApp](https://developers.exlibrisgroup.com/cloudapps/), wh
## How to use
* Search for any Bib-Record in Alma
* Open the Bib-Hierarchy Cloud App
* Click 'Show hierarchy' on the entry you're intrested in
* Click 'Hierarchy ↓' (or 'Hierarchy ↑') on the entry you're intrested in
* Wait(, wait a bit longer)
* See all related records
* Click 'Expand' in the Cloud App toolbar, to see a nice table, or click export to download the result as Excel file
Expand All @@ -21,43 +21,54 @@ To submit an SRU request, the app needs the Alma URL and the network code. The a
## How does it work
The result data is retrieved via SRU (see [SRU documentation](https://developers.exlibrisgroup.com/alma/integrations/sru/)), this means SRU must be enabled, otherwise this app will not work ([how to enable SRU](https://knowledge.exlibrisgroup.com/Alma/Product_Documentation/010Alma_Online_Help_(English)/090Integrations_with_External_Systems/030Resource_Management/190SRU_SRW_Search#)).

For the 'downward' hierarchy:

1. Find the NZ MMS ID via Alma API
2. Get the record via SRU
3. Parse out `other system numbers` from field `035a`
4. Query SRU for `other_system_number` and `001` with the result from the previous step. `other_system_number` is an index over fields `019a,z;035a,z;774w;773w;775w;777w;786w;800w;810w;811w` (see: [Alma Search Index documentation](https://knowledge.exlibrisgroup.com/Alma/Product_Documentation/010Alma_Online_Help_(English)/Metadata_Management/180Search_Indexes/050MARC_21_Search_Indexes#Search_Index_to_MARC_21_Bibliographic_Tag_Mapping))
5. Parse the result and display as nice table

<br>

For the 'upward' hierarchy:
1. Find the NZ MMS ID via Alma API
2. Get the record via SRU
3. Parse out 'other system numbers' from field 035$a
4. Query SRU for 'other_system_number' and '001' with the result from the previous step. 'other_system_number' is an index over fields `019a,z;035a,z;774w;773w;775w;777w;786w;800w;810w;811w` (see: [Alma Search Index documentation](https://knowledge.exlibrisgroup.com/Alma/Product_Documentation/010Alma_Online_Help_(English)/Metadata_Management/180Search_Indexes/050MARC_21_Search_Indexes#Search_Index_to_MARC_21_Bibliographic_Tag_Mapping))
3. Parse out the system numbers from fields: `773w`, `800w`, `810w`, `811w`, `830w`
4. Query SRU for `other_system_number_active_035` with the result from the previous step. `other_system_number_active_035` is an index over the field `035a` (see: [Alma Search Index documentation](https://knowledge.exlibrisgroup.com/Alma/Product_Documentation/010Alma_Online_Help_(English)/Metadata_Management/180Search_Indexes/050MARC_21_Search_Indexes#Search_Index_to_MARC_21_Bibliographic_Tag_Mapping))
5. Parse the result and display as nice table

## Which fields are used
To display the result table, the following fields are used. If this does not work for you, please open an [issue on Github](https://github.com/HSG-Library/alma-bib-hierarchy/issues).

* Order: `800$v`, `810$v`, `830$v`, `773$q`
* Order: `800v`, `810v`, `830v`, `773q`
* Title: `245`
* Year: `008` (substring 7,11)
* Edition: `250`
* MMS ID: `001` (controllfield)
* Duplicate: records with the same order and edition are marked as duplicates
* Analytical: `LDR 7`(leader position 7)
* Holding: `852$a`
* Holding: `852a`

### Additional data
In addition to the fields mentionen above, there is the possibilty to display additional data. Currently it is possible to add the following fields to the table:
* `040$e`
* `490$a`
* `490$v`
* `773$g`
* `773$t`
* `800$a`
* `800$t`
* `800$v`
* `810$a`
* `810$t`
* `810$v`
* `811$a`
* `811$t`
* `811$v`
* `830$a`
* `830$t`
* `830$v`
* `040e`
* `490a`
* `490v`
* `773g`
* `773t`
* `800a`
* `800t`
* `800v`
* `810a`
* `810t`
* `810v`
* `811a`
* `811t`
* `811v`
* `830a`
* `830t`
* `830v`

The Excel export will contain all active additional fields.

Expand Down Expand Up @@ -329,7 +340,7 @@ Example queries for 'Gesamtausgabe Martin Heidegger, Heidegger, Martin', MMS ID
```
</details>

2. Get 'other system numbers' from field `035$a`.
1. Get 'other system numbers' from field `035a`.
<details>
<summary>result</summary>

Expand Down Expand Up @@ -903,4 +914,3 @@ Example queries for 'Gesamtausgabe Martin Heidegger, Heidegger, Martin', MMS ID
- Running version of the code above https://bibdata.univie.ac.at/bib-hierarchy/
- ExLibris Cloud App documentation: https://developers.exlibrisgroup.com/cloudapps/
- ExLibris SRU documentation: https://developers.exlibrisgroup.com/alma/integrations/sru/
-
9 changes: 8 additions & 1 deletion cloudapp/src/app/main/main.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ <h2 translate>main.noMmsIdMsg</h2>
</mat-list>
</mat-card-content>
<mat-card-actions class="bib-entity-actions" *ngIf="!selectedEntity">
<button mat-flat-button color="primary" (click)="showHierarchy(bibEntity)">{{ 'main.showHierarchyButtonLabel' | translate }}</button>
<button mat-flat-button color="primary" (click)="showHierarchyUp(bibEntity)">
{{ 'main.showHierarchyButtonLabel' | translate }}
<mat-icon>arrow_upward</mat-icon>
</button>
<button mat-flat-button color="primary" (click)="showHierarchyDown(bibEntity)">
{{ 'main.showHierarchyButtonLabel' | translate }}
<mat-icon>arrow_downward</mat-icon>
</button>
</mat-card-actions>
</mat-card>

Expand Down
1 change: 1 addition & 0 deletions cloudapp/src/app/main/main.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
display: flex;
justify-content: flex-end;
margin-bottom: 6px;
gap: 6px;
}

.result-actions {
Expand Down
51 changes: 49 additions & 2 deletions cloudapp/src/app/main/main.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class MainComponent implements OnInit, OnDestroy {
ngOnDestroy(): void {
}

showHierarchy(bibEntity: BibEntity): void {
showHierarchyDown(bibEntity: BibEntity): void {
this.selectedEntity = bibEntity

this.loader.show()
Expand Down Expand Up @@ -117,7 +117,54 @@ export class MainComponent implements OnInit, OnDestroy {
},
(error) => {
this.alert.error(`Could not show hierarchy, please check the Alma URL '${this.almaUrl}'`, { autoClose: false })
console.error('Error in showHierarchy()', error)
console.error('Error in showHierarchyDown()', error)
this.reset()
this.loader.hide()
})
}

showHierarchyUp(bibEntity: BibEntity): void {
this.selectedEntity = bibEntity

this.loader.show()
this.status.set('Collecting infos for ' + bibEntity.entity.description)
let currentNzMmsId: string
bibEntity.nzMmsId
.pipe(
switchMap(nzMmsId => {
currentNzMmsId = nzMmsId
return of(SruQuery.MMS_ID(nzMmsId))
}),
tap(() => this.status.set('Collecting other system numbers')),
switchMap(query => this.sruService.queryNZ(query)),
switchMap(records => {
const upwardSystemNumbers: string[] = this.sruParser.getUpwardSystemNumbers(records)
this.status.set('Found ' + upwardSystemNumbers.length + ' system numbers')
const query035a: SruQuery = SruQuery.OTHER_SYSTEM_NUMBER_ACTIVE_035(upwardSystemNumbers)
const queryMmsId: SruQuery = SruQuery.MMS_IDS(upwardSystemNumbers.filter(systemNumber => !isNaN(+systemNumber)))
const queryHierarchyUpward: SruQuery = query035a.or(queryMmsId)
this.status.set('Querying SRU for related records')
return this.sruService.queryNZ(queryHierarchyUpward)
})
).subscribe(
(records) => {
const bibInfos: BibInfo[] = this.sruParser.getBibInfo(records)
const bibInfosSorted: BibInfo[] = this.sortHoldings(bibInfos)
if (bibInfos.length > 0) {
this.availableAdditionalColums = Array.from(bibInfos[0].additionalInfo.keys())
this.resultTable.setAdditionalColumns(this.availableAdditionalColums)
}
const datasource = new MatTableDataSource(bibInfosSorted)
datasource.sortData = this.tableSortFunction()
const matSort: MatSort = this.resultTable.getMatSort()
matSort.sort(({ id: 'order', start: 'asc' }) as MatSortable)
datasource.sort = matSort
this.bibInfoResult = datasource
this.loader.hide()
},
(error) => {
this.alert.error(`Could not show hierarchy, please check the Alma URL '${this.almaUrl}'`, { autoClose: false })
console.error('Error in showHierarchyDown()', error)
this.reset()
this.loader.hide()
})
Expand Down
24 changes: 24 additions & 0 deletions cloudapp/src/app/services/sru-response-parsers.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ export class SruResponseParserService {
private readonly XPATH_QUERY_250_EDITION: string = "//default:datafield[@tag='250']/default:subfield"
private readonly XPATH_QUERY_852_HOLDINGS: string = "//default:datafield[@tag='852']/default:subfield[@code='a']"
private readonly XPATH_QUERY_LEADER_ANALYTICAL: string = "//default:leader"
// query for upward hierarchy
private readonly XPATH_QUERY_773w: string = "//default:datafield[@tag='773']/default:subfield[@code='w']"
private readonly XPATH_QUERY_800w: string = "//default:datafield[@tag='800']/default:subfield[@code='w']"
private readonly XPATH_QUERY_810w: string = "//default:datafield[@tag='810']/default:subfield[@code='w']"
private readonly XPATH_QUERY_811w: string = "//default:datafield[@tag='811']/default:subfield[@code='w']"
private readonly XPATH_QUERY_830w: string = "//default:datafield[@tag='830']/default:subfield[@code='w']"

private readonly XPATH_QUERY_ADDITIONAL: Map<string, string> = new Map<string, string>([
["040$e", "//default:datafield[@tag='040']/default:subfield[@code='e']"],
["490$a", "//default:datafield[@tag='490']/default:subfield[@code='a']"],
Expand Down Expand Up @@ -62,6 +69,23 @@ export class SruResponseParserService {
}).reduce((acc, curr) => acc.concat(curr))
}

getUpwardSystemNumbers(records: Element[]): string[] {
if (!records || records?.length == 0) {
console.warn('No records - cannot query for upward system numbers')
return []
}
return records.map(record => {
const tempDoc: Document = new Document()
tempDoc.append(record)
const field773w = this.xpathQuery(tempDoc, this.XPATH_QUERY_773w)
const field800w = this.xpathQuery(tempDoc, this.XPATH_QUERY_800w)
const field810w = this.xpathQuery(tempDoc, this.XPATH_QUERY_810w)
const field811w = this.xpathQuery(tempDoc, this.XPATH_QUERY_811w)
const field830w = this.xpathQuery(tempDoc, this.XPATH_QUERY_830w)
return field773w.concat(field800w, field810w, field811w, field830w)
}).reduce((acc, curr) => acc.concat(curr))
}

getBibInfo(records: Element[]): BibInfo[] {
if (!records || records?.length == 0) {
console.warn('No records - cannot query for bib info')
Expand Down
29 changes: 27 additions & 2 deletions cloudapp/src/app/sru/sru-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export class SruQuery {

private static MMS_ID_DEF: QueryDefinition = { index: 'mms_id', operator: '=' }
private static OTHER_SYSTEM_NUMBER_DEF: QueryDefinition = { index: 'other_system_number', operator: '==' }
private static OTHER_SYSTEM_NUMBER_ACTIVE_35a_DEF: QueryDefinition = { index: 'other_system_number_active_035', operator: '==' }

private query: string[]
private _name: string
Expand All @@ -19,6 +20,18 @@ export class SruQuery {
return this.query.join(' ')
}

or(query: SruQuery): SruQuery {
if (query.getQueryParts().length > 0) {
this.query.push(BoolOp.OR)
this.query = this.query.concat(query.getQueryParts())
}
return this
}

private getQueryParts(): string[] {
return this.query
}

private setName(name: string): SruQuery {
this._name = name
return this
Expand All @@ -41,16 +54,28 @@ export class SruQuery {
.setName("query for mmsid")
}

static MMS_IDS(values: string[]): SruQuery {
return SruQuery.orListQuery(values, SruQuery.MMS_ID_DEF, "query for mmsid")
}

static OTHER_SYSTEM_NUMBER(values: string[]): SruQuery {
return SruQuery.orListQuery(values, SruQuery.OTHER_SYSTEM_NUMBER_DEF, "query for 'other_system_number'")
}

static OTHER_SYSTEM_NUMBER_ACTIVE_035(values: string[]): SruQuery {
return SruQuery.orListQuery(values, SruQuery.OTHER_SYSTEM_NUMBER_ACTIVE_35a_DEF, "query for 'other_system_number_active_035'")
}

private static orListQuery(values: string[], queryDef: QueryDefinition, name: string): SruQuery {
const query: SruQuery = new SruQuery()
values.forEach((value, idx, arr) => {
query.addQuery(SruQuery.OTHER_SYSTEM_NUMBER_DEF, value)
query.addQuery(queryDef, value)
// dont add OR to the last element
if (idx + 1 < arr.length) {
query.addBoolOp(BoolOp.OR)
}
})
query.setName("query for 'other_system_number'")
query.setName(name)
return query
}
}
Expand Down
2 changes: 1 addition & 1 deletion cloudapp/src/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"resetButtonLabel": "Zurücksetzen",
"resetSelectionButtonLabel": "Auswahl Zurücksetzen",
"showAdditionalData": "Zusätzliche Daten anzeigen/verstecken",
"showHierarchyButtonLabel": "Hierarchie anzeigen"
"showHierarchyButtonLabel": "Hierarchie"
},
"popup": {
"windowIsOpen": "Der Inhalt wird in einem Popup-Fenster dargestellt. Ein Klick auf 'Popup schliessen' zeigt den Inhalt wieder hier an."
Expand Down
2 changes: 1 addition & 1 deletion cloudapp/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"resetButtonLabel": "Reset",
"resetSelectionButtonLabel": "Reset selection",
"showAdditionalData": "Show/Hide additional data",
"showHierarchyButtonLabel": "Show hierarchy"
"showHierarchyButtonLabel": "Hierarchy"
},
"popup": {
"windowIsOpen": "Content is displayed in a popup window. Click 'Close window' to display it here again."
Expand Down
Loading

0 comments on commit 2ae4afe

Please sign in to comment.