Skip to content

Commit fb0f584

Browse files
committed
Add XML tutorial
1 parent 80702e5 commit fb0f584

File tree

13 files changed

+184
-45
lines changed

13 files changed

+184
-45
lines changed

cloudapp/src/app/app-routing.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ThemingComponent } from './theming/theming.component';
66
import { SettingsComponent } from './settings/settings.component';
77
import { ParallelComponent } from './parallel/parallel.component';
88
import { ExternalComponent } from './external/external.component';
9+
import { XmlComponent } from './xml/xml.component';
910

1011
const routes: Routes = [
1112
{ path: '', component: MainComponent },
@@ -14,6 +15,7 @@ const routes: Routes = [
1415
{ path: 'settings', component: SettingsComponent },
1516
{ path: 'parallel', component: ParallelComponent },
1617
{ path: 'external', component: ExternalComponent },
18+
{ path: 'xml', component: XmlComponent },
1719
];
1820

1921
@NgModule({

cloudapp/src/app/app.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { ThemingComponent } from './theming/theming.component';
1515
import { SettingsComponent } from './settings/settings.component';
1616
import { ParallelComponent } from './parallel/parallel.component';
1717
import { ExternalComponent } from './external/external.component';
18+
import { XmlComponent } from './xml/xml.component';
1819

1920
export function getToastrModule() {
2021
return ToastrModule.forRoot({
@@ -32,7 +33,8 @@ export function getToastrModule() {
3233
ThemingComponent,
3334
SettingsComponent,
3435
ParallelComponent,
35-
ExternalComponent
36+
ExternalComponent,
37+
XmlComponent
3638
],
3739
imports: [
3840
MaterialModule,

cloudapp/src/app/external/external.component.scss

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
.commands-container {
2-
margin: 20px 0;
3-
width: fit-content;
4-
}
5-
6-
.spinner {
7-
float: right;
8-
}
9-
10-
.commands-container button {
11-
margin-right: 10px;
12-
}
13-
141
.settings-section {
152
display: flex;
163
align-content: center;

cloudapp/src/app/main/main.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ <h1>
99
<li><a [routerLink]="['settings']">Using the Settings Service</a></li>
1010
<li><a [routerLink]="['parallel']">Making parallel API requests</a></li>
1111
<li><a [routerLink]="['external']">Reaching outside your app</a></li>
12+
<li><a [routerLink]="['xml']">Working with bibliographic records in XML</a></li>
1213
</ul>
1314
</section>

cloudapp/src/app/settings/settings.component.scss

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
.commands-container {
2-
margin: 20px 0;
3-
width: fit-content;
4-
}
5-
6-
.spinner {
7-
float: right;
8-
}
9-
10-
.commands-container button {
11-
margin-right: 10px;
12-
}
13-
141
.settings-section {
152
display: flex;
163
align-content: center;

cloudapp/src/app/xml/bib-utils.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { CloudAppRestService, HttpMethod } from "@exlibris/exl-cloudapp-angular-lib";
2+
import { Observable } from "rxjs";
3+
import { map } from "rxjs/operators";
4+
5+
export interface Bib {
6+
link: string,
7+
mms_id: string;
8+
title: string;
9+
record_format: string;
10+
anies: any;
11+
}
12+
13+
export class BibUtils {
14+
private _restService: CloudAppRestService;
15+
16+
constructor(restService: CloudAppRestService) {
17+
this._restService = restService;
18+
}
19+
20+
/** Retrieve a single BIB record */
21+
getBib (mmsId: string): Observable<Bib> {
22+
return this._restService.call(`/bibs/${mmsId}`);
23+
}
24+
25+
/** Update a BIB record with the specified MARCXML */
26+
updateBib( bib: Bib ): Observable<Bib> {
27+
return this._restService.call( {
28+
url: `/bibs/${bib.mms_id}`,
29+
headers: {
30+
"Content-Type": "application/xml",
31+
Accept: "application/json" },
32+
requestBody: `<bib>${bib.anies}</bib>`,
33+
method: HttpMethod.PUT
34+
});
35+
}
36+
37+
/** Adds a 500 note field to a MARC21 Bibliographic Record */
38+
addNoteToBib(bib: Bib) {
39+
const doc = new DOMParser().parseFromString(bib.anies, "application/xml");
40+
const datafield = dom("datafield", {
41+
parent: doc.documentElement,
42+
attributes: [ ["tag", "500"], ["ind1", " "], ["ind2", " "] ]
43+
});
44+
dom("subfield", {
45+
parent: datafield,
46+
text: `Record processed at ${(new Date()).toLocaleString()}`,
47+
attributes: [ ["code", "a"] ]
48+
});
49+
bib.anies = new XMLSerializer().serializeToString(doc.documentElement);
50+
return bib;
51+
}
52+
}
53+
54+
/** Adds Element to dom and returns it */
55+
const dom = (name: string, options: {parent?: Element | Node, text?:
56+
string, className?: string, id?: string, attributes?: string[][]} = {}
57+
): Element => {
58+
59+
let ns = options.parent ? options.parent.namespaceURI : '';
60+
let element = document.createElementNS(ns, name);
61+
62+
if (options.parent) options.parent.appendChild(element);
63+
if (options.text) element.innerHTML = options.text;
64+
if (options.className) element.className = options.className;
65+
if (options.id) element.id = options.id;
66+
if (options.attributes) options.attributes.forEach(([att, val]) => element.setAttribute(att, val));
67+
68+
return element;
69+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<div>
2+
<div *ngIf="bib; else nobib">
3+
<p>Bibliographic record:</p>
4+
<ul>
5+
<li><strong>MMS ID: </strong>{{ bib.mms_id }}</li>
6+
<li><strong>Title: </strong>{{ bib.title }}</li>
7+
<li><strong>Author: </strong>{{ bib.author }}</li>
8+
</ul>
9+
<div class="commands-container">
10+
<button mat-stroked-button (click)="addNote()" color="primary">Add Note</button>
11+
<mat-spinner diameter="30" class="spinner" *ngIf="running"></mat-spinner>
12+
</div>
13+
</div>
14+
<ng-template #nobib>
15+
Please navigate to a bibliographic record.
16+
</ng-template>
17+
</div>

cloudapp/src/app/xml/xml.component.scss

Whitespace-only changes.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Component, OnInit, OnDestroy } from '@angular/core';
2+
import { AppService } from '../app.service';
3+
import { Subscription } from 'rxjs';
4+
import { finalize } from 'rxjs/operators';
5+
import { CloudAppEventsService, PageInfo, EntityType, CloudAppRestService } from '@exlibris/exl-cloudapp-angular-lib';
6+
import { ToastrService } from 'ngx-toastr';
7+
import { Bib, BibUtils } from './bib-utils';
8+
9+
@Component({
10+
selector: 'app-xml',
11+
templateUrl: './xml.component.html',
12+
styleUrls: ['./xml.component.scss']
13+
})
14+
export class XmlComponent implements OnInit, OnDestroy {
15+
16+
private pageLoad$: Subscription;
17+
private bibUtils: BibUtils;
18+
bib: Bib;
19+
running = false;
20+
21+
constructor(
22+
private appService: AppService,
23+
private eventsService: CloudAppEventsService,
24+
private restService: CloudAppRestService,
25+
private toastr: ToastrService
26+
) { }
27+
28+
ngOnInit() {
29+
this.appService.setTitle('Working with XML');
30+
this.bibUtils = new BibUtils(this.restService);
31+
this.pageLoad$ = this.eventsService.onPageLoad((pageInfo: PageInfo) => {
32+
const entities = (pageInfo.entities||[]).filter(e=>[EntityType.BIB_MMS, 'IEP', 'BIB'].includes(e.type));
33+
if (entities.length > 0) {
34+
this.bibUtils.getBib(entities[0].id).subscribe(bib=>
35+
this.bib = (bib.record_format=='marc21') ? bib : null
36+
)
37+
} else {
38+
this.bib = null;
39+
}
40+
});
41+
}
42+
43+
ngOnDestroy(): void {
44+
this.pageLoad$.unsubscribe();
45+
}
46+
47+
addNote() {
48+
if (!confirm(`Add a note to ${this.bib.mms_id}?`)) return;
49+
this.running = true;
50+
this.bib = this.bibUtils.addNoteToBib(this.bib);
51+
this.bibUtils.updateBib(this.bib).pipe(finalize(()=>this.running=false))
52+
.subscribe(
53+
bib=>this.eventsService.refreshPage().subscribe(
54+
()=>this.toastr.success("Note added to Bib")
55+
),
56+
(e) => this.toastr.error(e.message)
57+
)
58+
}
59+
}

cloudapp/src/main.scss

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,16 @@
99
}
1010

1111
@mixin global-styles {
12-
/* Add global styles here */
12+
.commands-container {
13+
margin: 20px 0;
14+
width: fit-content;
15+
}
16+
17+
.spinner {
18+
float: right;
19+
}
20+
21+
.commands-container button {
22+
margin-right: 10px;
23+
}
1324
}

0 commit comments

Comments
 (0)