@office-open/xml 0.9.3 → 0.9.4

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 +28 -11
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -204,9 +204,14 @@ const ENTITY_MAP = {
204
204
  """: "\"",
205
205
  "'": "'"
206
206
  };
207
- const ENTITY_PATTERN = /&(amp|lt|gt|quot|apos);/g;
207
+ const ENTITY_PATTERN = /&(?:amp|lt|gt|quot|apos|#x[0-9a-fA-F]+|#[0-9]+);/g;
208
208
  function unescapeXml(str) {
209
- return str.replace(ENTITY_PATTERN, (match) => ENTITY_MAP[match]);
209
+ return str.replace(ENTITY_PATTERN, (match) => {
210
+ if (ENTITY_MAP[match] !== void 0) return ENTITY_MAP[match];
211
+ const body = match.slice(2, -1);
212
+ const code = body[0] === "x" || body[0] === "X" ? parseInt(body.slice(1), 16) : parseInt(body, 10);
213
+ return Number.isFinite(code) && code >= 0 ? String.fromCodePoint(code) : match;
214
+ });
210
215
  }
211
216
  function nativeTypeValue(value) {
212
217
  if (value === "") return value;
@@ -231,10 +236,6 @@ function parse(xmlString, options) {
231
236
  let i = 0;
232
237
  const len = xmlString.length;
233
238
  while (i < len) {
234
- if (!captureSpaces && isWhitespace(xmlString.charCodeAt(i))) {
235
- i++;
236
- continue;
237
- }
238
239
  if (xmlString.charCodeAt(i) !== 60) {
239
240
  const start = i;
240
241
  while (i < len && xmlString.charCodeAt(i) !== 60) i++;
@@ -242,7 +243,7 @@ function parse(xmlString, options) {
242
243
  if (trim) text = text.trim();
243
244
  if (ignoreText) continue;
244
245
  if (text.length > 0) {
245
- if (captureSpaces || text.trim().length > 0) addField(stack[stack.length - 1], "text", text);
246
+ if (captureSpaces || text.trim().length > 0 || isPreserveContext(stack)) addField(stack[stack.length - 1], "text", text);
246
247
  }
247
248
  continue;
248
249
  }
@@ -355,7 +356,7 @@ function parseAttributesFromXml(str, start) {
355
356
  i++;
356
357
  const valueStart = i;
357
358
  while (i < len && str.charCodeAt(i) !== quote) i++;
358
- attrs[name] = str.slice(valueStart, i);
359
+ attrs[name] = unescapeXml(str.slice(valueStart, i));
359
360
  i++;
360
361
  }
361
362
  return {
@@ -385,17 +386,33 @@ function parseAttributes(str) {
385
386
  i++;
386
387
  const valueStart = i;
387
388
  while (i < len && str.charCodeAt(i) !== quote) i++;
388
- result[name] = str.slice(valueStart, i);
389
+ result[name] = unescapeXml(str.slice(valueStart, i));
389
390
  i++;
390
391
  }
391
392
  return result;
392
393
  }
393
394
  function addField(parent, type, value) {
394
395
  if (!parent.elements) parent.elements = [];
396
+ if (type === "text" || type === "cdata") {
397
+ const last = parent.elements[parent.elements.length - 1];
398
+ if (last && last.type === type) {
399
+ const key = type;
400
+ last[key] = last[key] + value;
401
+ return;
402
+ }
403
+ }
395
404
  const element = { type };
396
405
  element[type] = value;
397
406
  parent.elements.push(element);
398
407
  }
408
+ /** True when the nearest ancestor with an explicit xml:space sets "preserve". */
409
+ function isPreserveContext(stack) {
410
+ for (let i = stack.length - 1; i >= 0; i--) {
411
+ const space = stack[i].attributes?.["xml:space"];
412
+ if (space !== void 0) return space === "preserve";
413
+ }
414
+ return false;
415
+ }
399
416
  function isWhitespace(ch) {
400
417
  return ch === 32 || ch === 9 || ch === 10 || ch === 13;
401
418
  }
@@ -455,8 +472,8 @@ function writeAttributes(attributes, elementName, element, attributeValueFn) {
455
472
  for (const key of Object.keys(attributes)) {
456
473
  const value = attributes[key];
457
474
  if (value === null || value === void 0) continue;
458
- let attr = String(value).replace(/"/g, "&quot;");
459
- if (attributeValueFn) attr = attributeValueFn(attr, key, elementName, element);
475
+ const raw = String(value);
476
+ const attr = attributeValueFn ? attributeValueFn(raw, key, elementName, element) : escapeXml(raw);
460
477
  parts.push(` ${key}="${attr}"`);
461
478
  }
462
479
  return parts.join("");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@office-open/xml",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "XML parsing and serialization for Office Open XML. Zero dependencies, drop-in replacement for xml + xml-js.",
5
5
  "keywords": [
6
6
  "office-open",