evt-model.service.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import { Injectable } from '@angular/core';
  2. import { combineLatest, Observable } from 'rxjs';
  3. import { map, shareReplay, switchMap } from 'rxjs/operators';
  4. import { NamedEntities, NamedEntityOccurrence, OriginalEncodingNodeType, Page, ZoneHotSpot, ZoneLine, LemmatizedEntities, LemmatizedEntityOccurrence } from '../models/evt-models';
  5. import { Map } from '../utils/js-utils';
  6. import { EditionDataService } from './edition-data.service';
  7. import { ApparatusEntriesParserService } from './xml-parsers/apparatus-entries-parser.service';
  8. import { CharacterDeclarationsParserService } from './xml-parsers/character-declarations-parser.service';
  9. import { FacsimileParserService } from './xml-parsers/facsimile-parser.service';
  10. import { LinesVersesParserService } from './xml-parsers/lines-verses-parser.service';
  11. import { MsDescParserService } from './xml-parsers/ms-desc-parser.service';
  12. import { NamedEntitiesParserService } from './xml-parsers/named-entities-parser.service';
  13. import { PrefatoryMatterParserService } from './xml-parsers/prefatory-matter-parser.service';
  14. import { StructureXmlParserService } from './xml-parsers/structure-xml-parser.service';
  15. import { WitnessesParserService } from './xml-parsers/witnesses-parser.service';
  16. // add by FS
  17. import { LemmatizedEntitiesParserService } from './xml-parsers/lemmatized-entities-parser.service';
  18. @Injectable({
  19. providedIn: 'root',
  20. })
  21. export class EVTModelService {
  22. public readonly editionSource$: Observable<OriginalEncodingNodeType> = this.editionDataService.parsedEditionSource$
  23. .pipe(
  24. shareReplay(1),
  25. );
  26. public readonly title$ = this.editionSource$.pipe(
  27. map((source) => this.prefatoryMatterParser.parseEditionTitle(source)),
  28. shareReplay(1),
  29. );
  30. public readonly projectInfo$ = this.prefatoryMatterParser.projectInfo$.pipe(
  31. shareReplay(1),
  32. );
  33. public readonly pages$: Observable<Page[]> = this.editionSource$.pipe(
  34. map((source) => this.editionStructureParser.parsePages(source).pages),
  35. shareReplay(1),
  36. );
  37. // NAMED ENTITIES
  38. public readonly parsedLists$ = this.editionSource$.pipe(
  39. map((source) => this.namedEntitiesParser.parseLists(source)),
  40. shareReplay(1),
  41. );
  42. public readonly persons$ = this.parsedLists$.pipe(
  43. map(({ lists, entities }) => (this.namedEntitiesParser.getResultsByType(lists, entities, ['person', 'personGrp']))),
  44. );
  45. public readonly places$ = this.parsedLists$.pipe(
  46. map(({ lists, entities }) => this.namedEntitiesParser.getResultsByType(lists, entities, ['place'])),
  47. );
  48. public readonly organizations$ = this.parsedLists$.pipe(
  49. map(({ lists, entities }) => this.namedEntitiesParser.getResultsByType(lists, entities, ['org'])),
  50. );
  51. public readonly relations$ = this.parsedLists$.pipe(
  52. map(({ relations }) => relations),
  53. );
  54. public readonly events$ = this.parsedLists$.pipe(
  55. map(({ lists, entities }) => this.namedEntitiesParser.getResultsByType(lists, entities, ['event'])),
  56. );
  57. public readonly verses$ = this.editionSource$.pipe(
  58. map((source) => this.linesVersesParser.parseVerses(source)),
  59. shareReplay(1),
  60. );
  61. public readonly lines$ = this.editionSource$.pipe(
  62. map((source) => this.linesVersesParser.parseLines(source)),
  63. shareReplay(1),
  64. );
  65. public readonly namedEntities$: Observable<NamedEntities> = combineLatest([
  66. this.persons$,
  67. this.places$,
  68. this.organizations$,
  69. this.relations$,
  70. this.events$,
  71. ]).pipe(
  72. map(([persons, places, organizations, relations, events]) => ({
  73. all: {
  74. lists: [...persons.lists, ...places.lists, ...organizations.lists, ...events.lists],
  75. entities: [...persons.entities, ...places.entities, ...organizations.entities, ...events.entities],
  76. },
  77. persons,
  78. places,
  79. organizations,
  80. relations,
  81. events,
  82. })),
  83. shareReplay(1),
  84. );
  85. public entitiesOccurrences$: Observable<Map<NamedEntityOccurrence[]>> = this.pages$.pipe(
  86. map((pages) => this.namedEntitiesParser.parseNamedEntitiesOccurrences(pages)),
  87. shareReplay(1),
  88. );
  89. // WITNESSES
  90. public readonly witnessesData$ = this.editionSource$.pipe(
  91. map((source) => this.witnessesParser.parseWitnessesData(source)),
  92. shareReplay(1),
  93. );
  94. public readonly witnesses$ = this.witnessesData$.pipe(
  95. map(({ witnesses }) => witnesses),
  96. shareReplay(1),
  97. );
  98. public readonly groups$ = this.witnessesData$.pipe(
  99. map(({ groups }) => groups),
  100. shareReplay(1),
  101. );
  102. // APPARATUS ENTRIES
  103. public readonly appEntries$ = this.editionSource$.pipe(
  104. map((source) => this.apparatusParser.parseAppEntries(source)),
  105. shareReplay(1),
  106. );
  107. public readonly significantReadings$ = this.appEntries$.pipe(
  108. map((appEntries) => this.apparatusParser.getSignificantReadings(appEntries)),
  109. shareReplay(1),
  110. );
  111. public readonly significantReadingsNumber$ = this.significantReadings$.pipe(
  112. map((signRdgs) => this.apparatusParser.getSignificantReadingsNumber(signRdgs)),
  113. shareReplay(1),
  114. );
  115. public readonly appVariance$ = this.witnesses$.pipe(
  116. switchMap((witList) => {
  117. return this.significantReadingsNumber$.pipe(
  118. map((signRdgsNum) => this.apparatusParser.getAppVariance(signRdgsNum, witList)),
  119. );
  120. }),
  121. shareReplay(1),
  122. );
  123. // FACSIMILE
  124. public readonly surfaces$ = this.editionSource$.pipe(
  125. map((source) => this.facsimileParser.parseSurfaces(source)),
  126. shareReplay(1),
  127. );
  128. public readonly hsLines$ = this.surfaces$.pipe(
  129. map((surfaces) => surfaces.reduce((x: ZoneLine[], y) => x.concat(y.zones.lines), [])),
  130. shareReplay(1),
  131. );
  132. public readonly hotspots$ = this.surfaces$.pipe(
  133. map((surfaces) => surfaces.reduce((x: ZoneHotSpot[], y) => x.concat(y.zones.hotspots), [])),
  134. shareReplay(1),
  135. );
  136. // CHAR DECL
  137. public readonly characters$ = this.editionSource$.pipe(
  138. map((source) => this.characterDeclarationsParser.parseChars(source)),
  139. shareReplay(1),
  140. );
  141. public readonly glyphs$ = this.editionSource$.pipe(
  142. map((source) => this.characterDeclarationsParser.parseGlyphs(source)),
  143. shareReplay(1),
  144. );
  145. public readonly specialChars$ = combineLatest([
  146. this.characters$,
  147. this.glyphs$,
  148. ]).pipe(
  149. map(([chars, glyphs]) => chars.concat(glyphs)),
  150. );
  151. public readonly msDesc$ = this.editionSource$.pipe(
  152. map((source) => this.msDescParser.parseMsDesc(source)),
  153. shareReplay(1),
  154. );
  155. // add by FS
  156. // LEMMA ENTITIES
  157. public readonly parsedLemLists$ = this.editionSource$.pipe(
  158. map((source) => this.lemmatizedEntitiesParser.parseLemLists(source)),
  159. shareReplay(1),
  160. );
  161. public readonly item$ = this.parsedLemLists$.pipe(
  162. map(({ lemlists, entities }) => (this.lemmatizedEntitiesParser.getResultsByType(lemlists, entities, ['item', 'lem', 'w']))),
  163. );
  164. public readonly lemmas$ = this.parsedLemLists$.pipe(
  165. map(({ lemlists, entities }) => (this.lemmatizedEntitiesParser.getResultsByType(lemlists, entities, ['item', 'lem', 'w']))),
  166. );
  167. public readonly lemmatizedEntities$: Observable<LemmatizedEntities> = combineLatest([
  168. this.item$,
  169. this.lemmas$,
  170. this.relations$,
  171. ]).pipe(
  172. map(([item, lemmas, relations]) => ({
  173. all: {
  174. lemlists: [...item.lemlists, ...lemmas.lemlists],
  175. entities: [...item.entities],
  176. },
  177. item,
  178. lemmas,
  179. relations,
  180. })),
  181. shareReplay(1),
  182. );
  183. public entitiesLemOccurrences$: Observable<Map<LemmatizedEntityOccurrence[]>> = this.pages$.pipe(
  184. map((pages) => this.lemmatizedEntitiesParser.parseLemmatizedEntitiesOccurrences(pages)),
  185. shareReplay(1),
  186. );
  187. constructor(
  188. private editionDataService: EditionDataService,
  189. private editionStructureParser: StructureXmlParserService,
  190. private namedEntitiesParser: NamedEntitiesParserService,
  191. private prefatoryMatterParser: PrefatoryMatterParserService,
  192. private witnessesParser: WitnessesParserService,
  193. private apparatusParser: ApparatusEntriesParserService,
  194. private facsimileParser: FacsimileParserService,
  195. private characterDeclarationsParser: CharacterDeclarationsParserService,
  196. private linesVersesParser: LinesVersesParserService,
  197. private msDescParser: MsDescParserService,
  198. // add by FS
  199. private lemmatizedEntitiesParser: LemmatizedEntitiesParserService,
  200. ) {
  201. }
  202. getPage(pageId: string): Observable<Page> {
  203. return this.pages$.pipe(map((pages) => pages.find((page) => page.id === pageId)));
  204. }
  205. }