ochre-sdk 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +278 -134
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -54,6 +54,7 @@ const XML_ARRAY_TAGS = [
54
54
  ];
55
55
  const XML_PARSER_OPTIONS = {
56
56
  alwaysCreateTextNode: true,
57
+ captureMetaData: true,
57
58
  ignoreAttributes: false,
58
59
  removeNSPrefix: true,
59
60
  ignorePiTags: true,
@@ -814,6 +815,34 @@ const setItemsParamsSchema = v.object({
814
815
  pageSize: v.optional(positiveNumber("Page size must be positive"), 48)
815
816
  });
816
817
  //#endregion
818
+ //#region src/xml/metadata.ts
819
+ const XML_METADATA_SYMBOL = XMLParser.getMetaDataSymbol();
820
+ function isRecord$4(value) {
821
+ return typeof value === "object" && value != null;
822
+ }
823
+ function getXMLMetadata(value) {
824
+ if (!isRecord$4(value)) return null;
825
+ return value[XML_METADATA_SYMBOL] ?? null;
826
+ }
827
+ function getXMLSourceIndex(value) {
828
+ const startIndex = getXMLMetadata(value)?.startIndex;
829
+ return typeof startIndex === "number" ? startIndex : null;
830
+ }
831
+ function restoreXMLMetadata(output, input) {
832
+ if (!isRecord$4(output) || !isRecord$4(input)) return;
833
+ const metadata = getXMLMetadata(input);
834
+ if (metadata != null) Object.defineProperty(output, XML_METADATA_SYMBOL, {
835
+ value: metadata,
836
+ enumerable: false,
837
+ configurable: true
838
+ });
839
+ if (Array.isArray(output) && Array.isArray(input)) {
840
+ for (const [index, outputValue] of output.entries()) restoreXMLMetadata(outputValue, input[index]);
841
+ return;
842
+ }
843
+ for (const [key, outputValue] of Object.entries(output)) restoreXMLMetadata(outputValue, input[key]);
844
+ }
845
+ //#endregion
817
846
  //#region src/parsers/string.ts
818
847
  const TEXT_ANNOTATION_TOKEN = "text-annotation";
819
848
  const TEXT_STYLING_TOKEN = "text-styling";
@@ -1149,11 +1178,26 @@ function createInternalLinkComponent(properties) {
1149
1178
  }
1150
1179
  function getXMLRichTextLinks(item) {
1151
1180
  const links = [];
1181
+ let fallbackIndex = 0;
1152
1182
  for (const rawLinks of Object.values(item.links ?? {})) {
1153
1183
  if (!Array.isArray(rawLinks)) continue;
1154
- for (const rawLink of rawLinks) if (isXMLRichTextLink(rawLink) && !isTextAnnotationMarkerLink(rawLink)) links.push(rawLink);
1184
+ for (const rawLink of rawLinks) if (isXMLRichTextLink(rawLink) && !isTextAnnotationMarkerLink(rawLink)) {
1185
+ links.push({
1186
+ link: rawLink,
1187
+ fallbackIndex
1188
+ });
1189
+ fallbackIndex += 1;
1190
+ }
1155
1191
  }
1156
- return links;
1192
+ links.sort((left, right) => {
1193
+ const leftIndex = getXMLSourceIndex(left.link);
1194
+ const rightIndex = getXMLSourceIndex(right.link);
1195
+ if (leftIndex != null && rightIndex != null && leftIndex !== rightIndex) return leftIndex - rightIndex;
1196
+ return left.fallbackIndex - right.fallbackIndex;
1197
+ });
1198
+ const sortedLinks = [];
1199
+ for (const { link } of links) sortedLinks.push(link);
1200
+ return sortedLinks;
1157
1201
  }
1158
1202
  function renderRichTextItem(item, linkString, contentItem, options) {
1159
1203
  const { languages, rendering } = options;
@@ -1556,29 +1600,83 @@ function normalizeCategory(category) {
1556
1600
  function isHeadingItemCategory(category) {
1557
1601
  return HEADING_ITEM_CATEGORIES.includes(category);
1558
1602
  }
1559
- function pushCategoryIfPresent(categories, category, items) {
1560
- if ((items?.length ?? 0) === 0) return;
1561
- pushCategory(categories, category);
1562
- }
1563
1603
  function pushCategory(categories, category) {
1564
1604
  if (!categories.includes(category)) categories.push(category);
1565
1605
  }
1606
+ function getHierarchyEntryCategory(key) {
1607
+ switch (key) {
1608
+ case "heading":
1609
+ case "tree":
1610
+ case "bibliography":
1611
+ case "concept":
1612
+ case "spatialUnit":
1613
+ case "period":
1614
+ case "person":
1615
+ case "resource":
1616
+ case "text":
1617
+ case "set":
1618
+ case "dictionaryUnit": return key;
1619
+ case "propertyVariable":
1620
+ case "variable": return "propertyVariable";
1621
+ case "propertyValue":
1622
+ case "value": return "propertyValue";
1623
+ default: return null;
1624
+ }
1625
+ }
1626
+ function isRecord$3(value) {
1627
+ return typeof value === "object" && value != null;
1628
+ }
1629
+ function isResourceWrapper(value) {
1630
+ return isRecord$3(value) && !("uuid" in value) && Array.isArray(value.resource);
1631
+ }
1632
+ function sourceOrderSort(left, right) {
1633
+ const leftIndex = getXMLSourceIndex(left.item);
1634
+ const rightIndex = getXMLSourceIndex(right.item);
1635
+ if (leftIndex != null && rightIndex != null && leftIndex !== rightIndex) return leftIndex - rightIndex;
1636
+ return left.fallbackIndex - right.fallbackIndex;
1637
+ }
1638
+ function collectHierarchyEntries(hierarchy, categories) {
1639
+ const entries = [];
1640
+ if (hierarchy == null) return entries;
1641
+ let fallbackIndex = 0;
1642
+ for (const key of Object.keys(hierarchy)) {
1643
+ const category = getHierarchyEntryCategory(key);
1644
+ if (category == null || !(categories == null || categories.includes(category))) continue;
1645
+ const values = hierarchy[key];
1646
+ if (!Array.isArray(values)) continue;
1647
+ for (const value of values) {
1648
+ if (category === "resource" && isResourceWrapper(value)) {
1649
+ for (const resource of value.resource) {
1650
+ entries.push({
1651
+ category,
1652
+ item: resource,
1653
+ fallbackIndex
1654
+ });
1655
+ fallbackIndex += 1;
1656
+ }
1657
+ continue;
1658
+ }
1659
+ entries.push({
1660
+ category,
1661
+ item: value,
1662
+ fallbackIndex
1663
+ });
1664
+ fallbackIndex += 1;
1665
+ }
1666
+ }
1667
+ entries.sort(sourceOrderSort);
1668
+ return entries;
1669
+ }
1566
1670
  function inferItemCategories(hierarchy) {
1567
1671
  const categories = [];
1568
1672
  if (hierarchy == null) return categories;
1569
- for (const heading of hierarchy.heading ?? []) for (const category of inferItemCategories(heading)) pushCategory(categories, category);
1570
- for (const category of SET_ITEM_CATEGORIES) {
1571
- if (category === "propertyVariable") {
1572
- pushCategoryIfPresent(categories, category, hierarchy.propertyVariable);
1573
- pushCategoryIfPresent(categories, category, hierarchy.variable);
1574
- continue;
1575
- }
1576
- if (category === "propertyValue") {
1577
- pushCategoryIfPresent(categories, category, hierarchy.propertyValue);
1578
- pushCategoryIfPresent(categories, category, hierarchy.value);
1673
+ for (const entry of collectHierarchyEntries(hierarchy)) {
1674
+ if (entry.category === "heading") {
1675
+ for (const category of inferItemCategories(entry.item)) pushCategory(categories, category);
1579
1676
  continue;
1580
1677
  }
1581
- pushCategoryIfPresent(categories, category, hierarchy[category]);
1678
+ if (entry.category === "dictionaryUnit") continue;
1679
+ pushCategory(categories, entry.category);
1582
1680
  }
1583
1681
  return categories;
1584
1682
  }
@@ -1864,62 +1962,79 @@ function withoutItems(item) {
1864
1962
  const { items: _items, ...itemWithoutItems } = item;
1865
1963
  return itemWithoutItems;
1866
1964
  }
1965
+ function parseEmbeddedItemEntry(entry, options) {
1966
+ switch (entry.category) {
1967
+ case "tree": return parseTree(entry.item, {
1968
+ ...options,
1969
+ containedItemCategory: normalizeTreeItemCategory(options.containedItemCategory)
1970
+ });
1971
+ case "bibliography": return parseBibliography(entry.item, options);
1972
+ case "concept": return parseConcept(entry.item, options);
1973
+ case "spatialUnit": return parseSpatialUnit(entry.item, options);
1974
+ case "period": return parsePeriod(entry.item, options);
1975
+ case "person": return parsePerson(entry.item, options);
1976
+ case "propertyVariable": return parsePropertyVariable(entry.item, options);
1977
+ case "propertyValue": return parsePropertyValue(entry.item, options);
1978
+ case "resource": return parseResource(entry.item, options);
1979
+ case "text": return parseText(entry.item, options);
1980
+ case "set": return parseSet(entry.item, options);
1981
+ case "dictionaryUnit":
1982
+ case "heading": return null;
1983
+ }
1984
+ }
1867
1985
  function parseItemHierarchy(hierarchy, options, categories) {
1868
1986
  const items = [];
1869
1987
  if (hierarchy == null) return items;
1870
- const shouldParse = (category) => categories == null || categories.includes(category);
1871
- if (shouldParse("tree")) for (const tree of hierarchy.tree ?? []) items.push(parseTree(tree, options));
1872
- if (shouldParse("bibliography")) for (const bibliography of hierarchy.bibliography ?? []) items.push(parseBibliography(bibliography, options));
1873
- if (shouldParse("concept")) for (const concept of hierarchy.concept ?? []) items.push(parseConcept(concept, options));
1874
- if (shouldParse("spatialUnit")) for (const spatialUnit of hierarchy.spatialUnit ?? []) items.push(parseSpatialUnit(spatialUnit, options));
1875
- if (shouldParse("period")) for (const period of hierarchy.period ?? []) items.push(parsePeriod(period, options));
1876
- if (shouldParse("person")) for (const person of hierarchy.person ?? []) items.push(parsePerson(person, options));
1877
- if (shouldParse("propertyVariable")) {
1878
- for (const propertyVariable of hierarchy.propertyVariable ?? []) items.push(parsePropertyVariable(propertyVariable, options));
1879
- for (const propertyVariable of hierarchy.variable ?? []) items.push(parsePropertyVariable(propertyVariable, options));
1880
- }
1881
- if (shouldParse("propertyValue")) {
1882
- for (const propertyValue of hierarchy.propertyValue ?? []) items.push(parsePropertyValue(propertyValue, options));
1883
- for (const propertyValue of hierarchy.value ?? []) items.push(parsePropertyValue(propertyValue, options));
1884
- }
1885
- if (shouldParse("resource")) for (const resource of hierarchy.resource ?? []) {
1886
- if (!("uuid" in resource)) {
1887
- for (const embeddedResource of resource.resource) items.push(parseResource(embeddedResource, options));
1888
- continue;
1889
- }
1890
- items.push(parseResource(resource, options));
1988
+ for (const entry of collectHierarchyEntries(hierarchy, categories)) {
1989
+ const item = parseEmbeddedItemEntry(entry, options);
1990
+ if (item != null) items.push(item);
1891
1991
  }
1892
- if (shouldParse("text")) for (const text of hierarchy.text ?? []) items.push(parseText(text, options));
1893
- if (shouldParse("set")) for (const set of hierarchy.set ?? []) items.push(parseSet(set, options));
1894
1992
  return items;
1895
1993
  }
1896
1994
  function parseSetItemHierarchy(hierarchy, options, categories) {
1897
1995
  const items = [];
1898
1996
  if (hierarchy == null) return items;
1899
- const shouldParse = (category) => categories == null || categories.includes(category);
1900
- if (shouldParse("tree")) for (const tree of hierarchy.tree ?? []) items.push(parseSetTree(tree, options));
1901
- if (shouldParse("bibliography")) for (const bibliography of hierarchy.bibliography ?? []) items.push(parseSetBibliography(bibliography, options));
1902
- if (shouldParse("concept")) for (const concept of hierarchy.concept ?? []) items.push(parseSetConcept(concept, options));
1903
- if (shouldParse("spatialUnit")) for (const spatialUnit of hierarchy.spatialUnit ?? []) items.push(parseSetSpatialUnit(spatialUnit, options));
1904
- if (shouldParse("period")) for (const period of hierarchy.period ?? []) items.push(parseSetPeriod(period, options));
1905
- if (shouldParse("person")) for (const person of hierarchy.person ?? []) items.push(withSetItemProperties(parsePerson(person, options), person.properties, options));
1906
- if (shouldParse("propertyVariable")) {
1907
- for (const propertyVariable of hierarchy.propertyVariable ?? []) items.push(parsePropertyVariable(propertyVariable, options));
1908
- for (const propertyVariable of hierarchy.variable ?? []) items.push(parsePropertyVariable(propertyVariable, options));
1909
- }
1910
- if (shouldParse("propertyValue")) {
1911
- for (const propertyValue of hierarchy.propertyValue ?? []) items.push(withSetItemProperties(parsePropertyValue(propertyValue, options), propertyValue.properties, options));
1912
- for (const propertyValue of hierarchy.value ?? []) items.push(withSetItemProperties(parsePropertyValue(propertyValue, options), propertyValue.properties, options));
1913
- }
1914
- if (shouldParse("resource")) for (const resource of hierarchy.resource ?? []) {
1915
- if (!("uuid" in resource)) {
1916
- for (const embeddedResource of resource.resource) items.push(parseSetResource(embeddedResource, options));
1917
- continue;
1997
+ for (const entry of collectHierarchyEntries(hierarchy, categories)) switch (entry.category) {
1998
+ case "tree":
1999
+ items.push(parseSetTree(entry.item, options));
2000
+ break;
2001
+ case "bibliography":
2002
+ items.push(parseSetBibliography(entry.item, options));
2003
+ break;
2004
+ case "concept":
2005
+ items.push(parseSetConcept(entry.item, options));
2006
+ break;
2007
+ case "spatialUnit":
2008
+ items.push(parseSetSpatialUnit(entry.item, options));
2009
+ break;
2010
+ case "period":
2011
+ items.push(parseSetPeriod(entry.item, options));
2012
+ break;
2013
+ case "person": {
2014
+ const person = entry.item;
2015
+ items.push(withSetItemProperties(parsePerson(person, options), person.properties, options));
2016
+ break;
2017
+ }
2018
+ case "propertyVariable":
2019
+ items.push(parsePropertyVariable(entry.item, options));
2020
+ break;
2021
+ case "propertyValue": {
2022
+ const propertyValue = entry.item;
2023
+ items.push(withSetItemProperties(parsePropertyValue(propertyValue, options), propertyValue.properties, options));
2024
+ break;
1918
2025
  }
1919
- items.push(parseSetResource(resource, options));
2026
+ case "resource":
2027
+ items.push(parseSetResource(entry.item, options));
2028
+ break;
2029
+ case "text":
2030
+ items.push(parseText(entry.item, options));
2031
+ break;
2032
+ case "set":
2033
+ items.push(parseSetSet(entry.item, options));
2034
+ break;
2035
+ case "dictionaryUnit":
2036
+ case "heading": break;
1920
2037
  }
1921
- if (shouldParse("text")) for (const text of hierarchy.text ?? []) items.push(parseText(text, options));
1922
- if (shouldParse("set")) for (const set of hierarchy.set ?? []) items.push(parseSetSet(set, options));
1923
2038
  return items;
1924
2039
  }
1925
2040
  function normalizeTreeLinkItemsCategory(type) {
@@ -2088,26 +2203,45 @@ function parseLinks(rawLinks, options) {
2088
2203
  const links = [];
2089
2204
  if (rawLinks == null) return links;
2090
2205
  const hierarchy = rawLinks;
2091
- for (const tree of hierarchy.tree ?? []) links.push(parseTreeItemLink(tree, options));
2092
- for (const bibliography of hierarchy.bibliography ?? []) links.push(parseBibliographyItemLink(bibliography, options));
2093
- for (const concept of hierarchy.concept ?? []) links.push(parseConceptItemLink(concept, options));
2094
- for (const spatialUnit of hierarchy.spatialUnit ?? []) links.push(parseSpatialUnitItemLink(spatialUnit, options));
2095
- for (const period of hierarchy.period ?? []) links.push(parsePeriodItemLink(period, options));
2096
- for (const person of hierarchy.person ?? []) links.push(parsePersonItemLink(person, options));
2097
- for (const propertyVariable of hierarchy.propertyVariable ?? []) links.push(parsePropertyVariableItemLink(propertyVariable, options));
2098
- for (const propertyVariable of hierarchy.variable ?? []) links.push(parsePropertyVariableItemLink(propertyVariable, options));
2099
- for (const propertyValue of hierarchy.propertyValue ?? []) links.push(parsePropertyValueItemLink(propertyValue, options));
2100
- for (const propertyValue of hierarchy.value ?? []) links.push(parsePropertyValueItemLink(propertyValue, options));
2101
- for (const resource of hierarchy.resource ?? []) {
2102
- if (!("uuid" in resource)) {
2103
- for (const embeddedResource of resource.resource) links.push(parseResourceItemLink(embeddedResource, options));
2104
- continue;
2105
- }
2106
- links.push(parseResourceItemLink(resource, options));
2206
+ for (const entry of collectHierarchyEntries(hierarchy)) switch (entry.category) {
2207
+ case "tree":
2208
+ links.push(parseTreeItemLink(entry.item, options));
2209
+ break;
2210
+ case "bibliography":
2211
+ links.push(parseBibliographyItemLink(entry.item, options));
2212
+ break;
2213
+ case "concept":
2214
+ links.push(parseConceptItemLink(entry.item, options));
2215
+ break;
2216
+ case "spatialUnit":
2217
+ links.push(parseSpatialUnitItemLink(entry.item, options));
2218
+ break;
2219
+ case "period":
2220
+ links.push(parsePeriodItemLink(entry.item, options));
2221
+ break;
2222
+ case "person":
2223
+ links.push(parsePersonItemLink(entry.item, options));
2224
+ break;
2225
+ case "propertyVariable":
2226
+ links.push(parsePropertyVariableItemLink(entry.item, options));
2227
+ break;
2228
+ case "propertyValue":
2229
+ links.push(parsePropertyValueItemLink(entry.item, options));
2230
+ break;
2231
+ case "resource":
2232
+ links.push(parseResourceItemLink(entry.item, options));
2233
+ break;
2234
+ case "text":
2235
+ links.push(parseTextItemLink(entry.item, options));
2236
+ break;
2237
+ case "set":
2238
+ links.push(parseSetItemLink(entry.item, options));
2239
+ break;
2240
+ case "dictionaryUnit":
2241
+ links.push(parseDictionaryUnitItemLink(entry.item, options));
2242
+ break;
2243
+ case "heading": break;
2107
2244
  }
2108
- for (const text of hierarchy.text ?? []) links.push(parseTextItemLink(text, options));
2109
- for (const set of hierarchy.set ?? []) links.push(parseSetItemLink(set, options));
2110
- for (const dictionaryUnit of hierarchy.dictionaryUnit ?? []) links.push(parseDictionaryUnitItemLink(dictionaryUnit, options));
2111
2245
  return links;
2112
2246
  }
2113
2247
  function parseReverseLinks(rawLinks, options) {
@@ -2183,8 +2317,19 @@ function parseTree(rawTree, options) {
2183
2317
  const childOptions = getParserOptions(options);
2184
2318
  const containedItemCategory = resolveTreeItemCategory(rawTree, normalizeTreeItemCategory(options.containedItemCategory));
2185
2319
  const items = [];
2186
- if (containedItemCategory != null && isHeadingItemCategory(containedItemCategory)) for (const heading of rawTree.items?.heading ?? []) items.push(parseHeading(heading, containedItemCategory, childOptions));
2187
- if (containedItemCategory != null) items.push(...parseItemHierarchy(rawTree.items, childOptions, [containedItemCategory]));
2320
+ if (containedItemCategory != null) {
2321
+ const itemCategories = [containedItemCategory];
2322
+ if (isHeadingItemCategory(containedItemCategory)) itemCategories.push("heading");
2323
+ for (const entry of collectHierarchyEntries(rawTree.items, itemCategories)) {
2324
+ if (entry.category === "heading") {
2325
+ if (!isHeadingItemCategory(containedItemCategory)) continue;
2326
+ items.push(parseHeading(entry.item, containedItemCategory, childOptions));
2327
+ continue;
2328
+ }
2329
+ const item = parseEmbeddedItemEntry(entry, childOptions);
2330
+ if (item != null) items.push(item);
2331
+ }
2332
+ }
2188
2333
  return {
2189
2334
  ...parseBaseItem("tree", rawTree, childOptions),
2190
2335
  type: rawTree.type ?? null,
@@ -2516,22 +2661,10 @@ function parseLinkedItems(rawItems, options) {
2516
2661
  containedItemCategory: options.containedItemCategory
2517
2662
  };
2518
2663
  const items = [];
2519
- for (const tree of rawItems?.tree ?? []) items.push(parseTree(tree, {
2520
- ...parserOptions,
2521
- containedItemCategory: normalizeTreeItemCategory(options.containedItemCategory)
2522
- }));
2523
- for (const bibliography of rawItems?.bibliography ?? []) items.push(parseBibliography(bibliography, parserOptions));
2524
- for (const concept of rawItems?.concept ?? []) items.push(parseConcept(concept, parserOptions));
2525
- for (const spatialUnit of rawItems?.spatialUnit ?? []) items.push(parseSpatialUnit(spatialUnit, parserOptions));
2526
- for (const period of rawItems?.period ?? []) items.push(parsePeriod(period, parserOptions));
2527
- for (const person of rawItems?.person ?? []) items.push(parsePerson(person, parserOptions));
2528
- for (const propertyVariable of rawItems?.propertyVariable ?? []) items.push(parsePropertyVariable(propertyVariable, parserOptions));
2529
- for (const propertyVariable of rawItems?.variable ?? []) items.push(parsePropertyVariable(propertyVariable, parserOptions));
2530
- for (const propertyValue of rawItems?.propertyValue ?? []) items.push(parsePropertyValue(propertyValue, parserOptions));
2531
- for (const propertyValue of rawItems?.value ?? []) items.push(parsePropertyValue(propertyValue, parserOptions));
2532
- for (const resource of rawItems?.resource ?? []) items.push(parseResource(resource, parserOptions));
2533
- for (const text of rawItems?.text ?? []) items.push(parseText(text, parserOptions));
2534
- for (const set of rawItems?.set ?? []) items.push(parseSet(set, parserOptions));
2664
+ for (const entry of collectHierarchyEntries(rawItems)) {
2665
+ const item = parseEmbeddedItemEntry(entry, parserOptions);
2666
+ if (item != null) items.push(item);
2667
+ }
2535
2668
  return items;
2536
2669
  }
2537
2670
  function parseSetItems(rawItems, options) {
@@ -3481,6 +3614,7 @@ async function fetchGallery(params, options) {
3481
3614
  logIssues(issues);
3482
3615
  throw new Error("Failed to parse gallery XML");
3483
3616
  }
3617
+ restoreXMLMetadata(output, data);
3484
3618
  return {
3485
3619
  gallery: parseGallery(output, { languages: resolveGalleryLanguages(output, requestedLanguages) }),
3486
3620
  error: null
@@ -3532,39 +3666,46 @@ function resolveItemLinksLanguages(data, requestedLanguages) {
3532
3666
  function buildXQuery$2(uuid) {
3533
3667
  return `<ochre>{${`let $item-uuid := "${uuid}"
3534
3668
 
3535
- let $uuids :=
3536
- distinct-values((
3537
-
3538
- (: Direct links on most item categories :)
3539
- fn:collection("ochre/resource")/ochre[@uuid = $item-uuid]/resource/links/*/@uuid/string(),
3540
- fn:collection("ochre/bibliography")/ochre[@uuid = $item-uuid]/bibliography/links/*/@uuid/string(),
3541
- fn:collection("ochre/period")/ochre[@uuid = $item-uuid]/period/links/*/@uuid/string(),
3542
- fn:collection("ochre/person")/ochre[@uuid = $item-uuid]/person/links/*/@uuid/string(),
3543
- fn:collection("ochre/propertyVariable")/ochre[@uuid = $item-uuid]/propertyVariable/links/*/@uuid/string(),
3544
- fn:collection("ochre/propertyValue")/ochre[@uuid = $item-uuid]/propertyValue/links/*/@uuid/string(),
3545
- fn:collection("ochre/text")/ochre[@uuid = $item-uuid]/text/links/*/@uuid/string(),
3546
- fn:collection("ochre/tree")/ochre[@uuid = $item-uuid]/tree/links/*/@uuid/string(),
3547
- fn:collection("ochre/set")/ochre[@uuid = $item-uuid]/set/links/*/@uuid/string(),
3669
+ let $source-items := (
3670
+ fn:collection("ochre/resource")/ochre[@uuid = $item-uuid]/resource,
3671
+ fn:collection("ochre/bibliography")/ochre[@uuid = $item-uuid]/bibliography,
3672
+ fn:collection("ochre/period")/ochre[@uuid = $item-uuid]/period,
3673
+ fn:collection("ochre/person")/ochre[@uuid = $item-uuid]/person,
3674
+ fn:collection("ochre/propertyVariable")/ochre[@uuid = $item-uuid]/propertyVariable,
3675
+ fn:collection("ochre/propertyValue")/ochre[@uuid = $item-uuid]/propertyValue,
3676
+ fn:collection("ochre/text")/ochre[@uuid = $item-uuid]/text,
3677
+ fn:collection("ochre/tree")/ochre[@uuid = $item-uuid]/tree,
3678
+ fn:collection("ochre/set")/ochre[@uuid = $item-uuid]/set,
3679
+ fn:collection("ochre/spatialUnit")/ochre[@uuid = $item-uuid]/spatialUnit,
3680
+ fn:collection("ochre/concept")/ochre[@uuid = $item-uuid]/concept
3681
+ )
3548
3682
 
3549
- (: Special category structures :)
3550
- fn:collection("ochre/spatialUnit")/ochre[@uuid = $item-uuid]/spatialUnit/observations/observation/links/*/@uuid/string(),
3551
- fn:collection("ochre/concept")/ochre[@uuid = $item-uuid]/concept/interpretations/interpretation/links/*/@uuid/string()
3552
- ))
3683
+ let $link-nodes := (
3684
+ $source-items/links/*,
3685
+ $source-items/observations/observation/links/*,
3686
+ $source-items/interpretations/interpretation/links/*
3687
+ )
3553
3688
 
3554
3689
  return
3555
- <items>{(
3556
- fn:collection("ochre/resource")/ochre/resource[@uuid = $uuids],
3557
- fn:collection("ochre/bibliography")/ochre/bibliography[@uuid = $uuids],
3558
- fn:collection("ochre/period")/ochre/period[@uuid = $uuids],
3559
- fn:collection("ochre/person")/ochre/person[@uuid = $uuids],
3560
- fn:collection("ochre/propertyVariable")/ochre/propertyVariable[@uuid = $uuids],
3561
- fn:collection("ochre/propertyValue")/ochre/propertyValue[@uuid = $uuids],
3562
- fn:collection("ochre/text")/ochre/text[@uuid = $uuids],
3563
- fn:collection("ochre/tree")/ochre/tree[@uuid = $uuids],
3564
- fn:collection("ochre/set")/ochre/set[@uuid = $uuids],
3565
- fn:collection("ochre/spatialUnit")/ochre/spatialUnit[@uuid = $uuids],
3566
- fn:collection("ochre/concept")/ochre/concept[@uuid = $uuids]
3567
- )}</items>`}}</ochre>`;
3690
+ <items>{
3691
+ for $link at $position in $link-nodes
3692
+ let $uuid := $link/@uuid/string()
3693
+ let $category := name($link)
3694
+ where $uuid ne "" and not($uuid = $link-nodes[position() lt $position]/@uuid/string())
3695
+ return
3696
+ if ($category = "resource") then fn:collection("ochre/resource")/ochre/resource[@uuid = $uuid]
3697
+ else if ($category = "bibliography") then fn:collection("ochre/bibliography")/ochre/bibliography[@uuid = $uuid]
3698
+ else if ($category = "period") then fn:collection("ochre/period")/ochre/period[@uuid = $uuid]
3699
+ else if ($category = "person") then fn:collection("ochre/person")/ochre/person[@uuid = $uuid]
3700
+ else if ($category = "propertyVariable" or $category = "variable") then fn:collection("ochre/propertyVariable")/ochre/propertyVariable[@uuid = $uuid]
3701
+ else if ($category = "propertyValue" or $category = "value") then fn:collection("ochre/propertyValue")/ochre/propertyValue[@uuid = $uuid]
3702
+ else if ($category = "text") then fn:collection("ochre/text")/ochre/text[@uuid = $uuid]
3703
+ else if ($category = "tree") then fn:collection("ochre/tree")/ochre/tree[@uuid = $uuid]
3704
+ else if ($category = "set") then fn:collection("ochre/set")/ochre/set[@uuid = $uuid]
3705
+ else if ($category = "spatialUnit") then fn:collection("ochre/spatialUnit")/ochre/spatialUnit[@uuid = $uuid]
3706
+ else if ($category = "concept") then fn:collection("ochre/concept")/ochre/concept[@uuid = $uuid]
3707
+ else ()
3708
+ }</items>`}}</ochre>`;
3568
3709
  }
3569
3710
  async function fetchItemLinks(uuid, options) {
3570
3711
  try {
@@ -3583,6 +3724,7 @@ async function fetchItemLinks(uuid, options) {
3583
3724
  logIssues(issues);
3584
3725
  throw new Error("Failed to parse OCHRE item links");
3585
3726
  }
3727
+ restoreXMLMetadata(output, data);
3586
3728
  const languages = resolveItemLinksLanguages(output, requestedLanguages);
3587
3729
  return {
3588
3730
  items: parseLinkedItems(output.result.ochre.items, {
@@ -3683,6 +3825,7 @@ async function fetchItem(uuid, options) {
3683
3825
  logIssues(issues);
3684
3826
  throw new Error("Failed to parse OCHRE data");
3685
3827
  }
3828
+ restoreXMLMetadata(output, data);
3686
3829
  const category = options?.category ?? inferFetchItemCategory(output.result.ochre);
3687
3830
  assertItemCategoryAllowed(category, options?.containedItemCategory);
3688
3831
  return {
@@ -4756,6 +4899,7 @@ async function fetchSetItems(params, containedItemCategories, options) {
4756
4899
  logIssues(issues);
4757
4900
  throw new Error("Failed to parse OCHRE Set items");
4758
4901
  }
4902
+ restoreXMLMetadata(output, data);
4759
4903
  if (containedItemCategories != null) {
4760
4904
  const missingCategories = containedItemCategories.filter((category) => !hasSetItemsCategory(output.result.ochre.items, category));
4761
4905
  if (missingCategories.length > 0) throw new Error(`No Set items found for item categories: ${missingCategories.join(", ")}`);
@@ -6096,15 +6240,14 @@ function parseWebElementProperties(componentProperty, elementResource, options)
6096
6240
  break;
6097
6241
  }
6098
6242
  case "image": {
6099
- const imageLinks = getWebsiteLinks(websiteLinks, "resource").filter((link) => link.type === "image" || link.type === "IIIF");
6100
- if (imageLinks.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource));
6243
+ if (websiteLinks.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource));
6101
6244
  const imageQuality = componentReader.valueOr("image-quality", "high");
6102
6245
  const images = [];
6103
- for (const link of imageLinks) images.push({
6246
+ for (const link of websiteLinks) images.push({
6104
6247
  uuid: link.uuid,
6105
6248
  label: link.identification.label,
6106
- width: link.image?.width ?? 0,
6107
- height: link.image?.height ?? 0,
6249
+ width: "image" in link ? link.image?.width ?? 0 : 0,
6250
+ height: "image" in link ? link.image?.height ?? 0 : 0,
6108
6251
  description: link.description,
6109
6252
  quality: imageQuality
6110
6253
  });
@@ -7033,6 +7176,7 @@ async function fetchWebsite(abbreviation, options) {
7033
7176
  logIssues(issues);
7034
7177
  throw new Error("Failed to parse website XML");
7035
7178
  }
7179
+ restoreXMLMetadata(output, data);
7036
7180
  return {
7037
7181
  website: parseWebsite(output, { languages: options?.languages }),
7038
7182
  error: null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data",
@@ -45,7 +45,7 @@
45
45
  "dependencies": {
46
46
  "date-fns": "^4.1.0",
47
47
  "fast-equals": "^6.0.0",
48
- "fast-xml-parser": "^5.7.3",
48
+ "fast-xml-parser": "^5.8.0",
49
49
  "valibot": "^1.4.0"
50
50
  },
51
51
  "devDependencies": {