node-pptx-templater 1.0.6 → 1.0.8
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.
- package/README.md +258 -2
- package/package.json +1 -1
- package/src/core/PPTXTemplater.js +92 -1
- package/src/core/TemplateEngine.js +126 -0
- package/src/core/ValidationEngine.js +179 -0
- package/src/managers/ChartManager.js +383 -21
- package/src/managers/TextManager.js +271 -0
- package/src/managers/charts/ChartCacheGenerator.js +427 -1
- package/src/managers/charts/ChartWorkbookUpdater.js +204 -33
|
@@ -16,7 +16,12 @@ class ChartCacheGenerator {
|
|
|
16
16
|
*/
|
|
17
17
|
static generateNumCache(values) {
|
|
18
18
|
const ptEntries = values
|
|
19
|
-
.map((val, i) =>
|
|
19
|
+
.map((val, i) => {
|
|
20
|
+
if (val === null || val === undefined) {
|
|
21
|
+
return `<c:pt idx="${i}"/>`
|
|
22
|
+
}
|
|
23
|
+
return `<c:pt idx="${i}"><c:v>${val}</c:v></c:pt>`
|
|
24
|
+
})
|
|
20
25
|
.join('')
|
|
21
26
|
return `<c:numCache><c:formatCode>General</c:formatCode><c:ptCount val="${values.length}"/>${ptEntries}</c:numCache>`
|
|
22
27
|
}
|
|
@@ -162,6 +167,427 @@ class ChartCacheGenerator {
|
|
|
162
167
|
}
|
|
163
168
|
}
|
|
164
169
|
|
|
170
|
+
static updateDataLabelsInXml(xml, seriesIndex, options, categories = [], seriesData = {}) {
|
|
171
|
+
let serIndex = 0
|
|
172
|
+
const serPattern = /(<c:ser>)([\s\S]*?)(<\/c:ser>)/g
|
|
173
|
+
|
|
174
|
+
return xml.replace(serPattern, (match, open, content, close) => {
|
|
175
|
+
if (serIndex !== seriesIndex) {
|
|
176
|
+
serIndex++
|
|
177
|
+
return match
|
|
178
|
+
}
|
|
179
|
+
serIndex++
|
|
180
|
+
|
|
181
|
+
let pointsCount = categories.length
|
|
182
|
+
if (pointsCount === 0) {
|
|
183
|
+
const valMatch = /<c:val>([\s\S]*?)<\/c:val>/.exec(content)
|
|
184
|
+
if (valMatch) {
|
|
185
|
+
const countMatch = /<c:ptCount val="(\d+)"\/>/.exec(valMatch[1])
|
|
186
|
+
if (countMatch) pointsCount = parseInt(countMatch[1], 10)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (pointsCount === 0 && options.labels) {
|
|
190
|
+
pointsCount = options.labels.length
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Parse existing styling and flags from the current <c:dLbls> block
|
|
194
|
+
let existingTxPr = ''
|
|
195
|
+
let existingDLblPos = ''
|
|
196
|
+
let existingNumFmt = ''
|
|
197
|
+
let existingSpPr = ''
|
|
198
|
+
const existingDLblSpPrs = {}
|
|
199
|
+
const existingShowTags = {}
|
|
200
|
+
|
|
201
|
+
const dLblsMatch = /<c:dLbls>([\s\S]*?)<\/c:dLbls>/.exec(content)
|
|
202
|
+
if (dLblsMatch) {
|
|
203
|
+
const dLblsContent = dLblsMatch[1]
|
|
204
|
+
const txPrMatch = /(<c:txPr>[\s\S]*?<\/c:txPr>)/.exec(dLblsContent)
|
|
205
|
+
if (txPrMatch) {
|
|
206
|
+
existingTxPr = txPrMatch[1]
|
|
207
|
+
}
|
|
208
|
+
const dLblPosMatch = /(<c:dLblPos\s+[^>]*\/>)/.exec(dLblsContent)
|
|
209
|
+
if (dLblPosMatch) {
|
|
210
|
+
existingDLblPos = dLblPosMatch[1]
|
|
211
|
+
}
|
|
212
|
+
const numFmtMatch = /(<c:numFmt\s+[^>]*\/>)/.exec(dLblsContent)
|
|
213
|
+
if (numFmtMatch) {
|
|
214
|
+
existingNumFmt = numFmtMatch[1]
|
|
215
|
+
}
|
|
216
|
+
const spPrMatch = /(<c:spPr>[\s\S]*?<\/c:spPr>)/.exec(dLblsContent)
|
|
217
|
+
if (spPrMatch) {
|
|
218
|
+
existingSpPr = spPrMatch[1]
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Parse individual <c:dLbl> shape properties to map their background fills
|
|
222
|
+
const dLblPattern = /<c:dLbl>([\s\S]*?)<\/c:dLbl>/g
|
|
223
|
+
let dLblMatch
|
|
224
|
+
while ((dLblMatch = dLblPattern.exec(dLblsContent)) !== null) {
|
|
225
|
+
const dLblContent = dLblMatch[1]
|
|
226
|
+
const idxMatch = /<c:idx val="(\d+)"\/>/.exec(dLblContent)
|
|
227
|
+
if (idxMatch) {
|
|
228
|
+
const idx = parseInt(idxMatch[1], 10)
|
|
229
|
+
const dLblSpPrMatch = /(<c:spPr>[\s\S]*?<\/c:spPr>)/.exec(dLblContent)
|
|
230
|
+
if (dLblSpPrMatch) {
|
|
231
|
+
existingDLblSpPrs[idx] = dLblSpPrMatch[1]
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const showTagsList = [
|
|
237
|
+
'showLegendKey',
|
|
238
|
+
'showVal',
|
|
239
|
+
'showCatName',
|
|
240
|
+
'showSerName',
|
|
241
|
+
'showPercent',
|
|
242
|
+
'showBubbleSize',
|
|
243
|
+
]
|
|
244
|
+
showTagsList.forEach(tag => {
|
|
245
|
+
const tagPattern = new RegExp(`(<c:${tag}\\s+val="([^"]*)"\\s*\\/>)`)
|
|
246
|
+
const tagMatch = tagPattern.exec(dLblsContent)
|
|
247
|
+
if (tagMatch) {
|
|
248
|
+
existingShowTags[tag] = tagMatch[1]
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const dLblsXml = this.generateDLblsXml(
|
|
254
|
+
pointsCount,
|
|
255
|
+
options,
|
|
256
|
+
categories,
|
|
257
|
+
seriesData,
|
|
258
|
+
existingTxPr,
|
|
259
|
+
existingDLblPos,
|
|
260
|
+
existingNumFmt,
|
|
261
|
+
existingShowTags,
|
|
262
|
+
existingSpPr,
|
|
263
|
+
existingDLblSpPrs
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
let updatedContent = content
|
|
267
|
+
const dLblsPattern = /(<c:dLbls>[\s\S]*?<\/c:dLbls>)/
|
|
268
|
+
if (dLblsPattern.test(updatedContent)) {
|
|
269
|
+
updatedContent = updatedContent.replace(dLblsPattern, dLblsXml)
|
|
270
|
+
} else {
|
|
271
|
+
const insertBefore = /(<c:cat>|<c:val>|<c:extLst>)/
|
|
272
|
+
if (insertBefore.test(updatedContent)) {
|
|
273
|
+
updatedContent = updatedContent.replace(insertBefore, `${dLblsXml}$1`)
|
|
274
|
+
} else {
|
|
275
|
+
updatedContent += dLblsXml
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return `${open}${updatedContent}${close}`
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
static generateDLblsXml(
|
|
284
|
+
pointsCount,
|
|
285
|
+
options,
|
|
286
|
+
categories = [],
|
|
287
|
+
seriesData = {},
|
|
288
|
+
existingTxPr = '',
|
|
289
|
+
existingDLblPos = '',
|
|
290
|
+
existingNumFmt = '',
|
|
291
|
+
existingShowTags = {},
|
|
292
|
+
existingSpPr = '',
|
|
293
|
+
existingDLblSpPrs = {}
|
|
294
|
+
) {
|
|
295
|
+
const { labels, labelsFromCells, template, position, labelStyle, labelMap } = options
|
|
296
|
+
|
|
297
|
+
let xml = '<c:dLbls>'
|
|
298
|
+
|
|
299
|
+
const posMap = {
|
|
300
|
+
center: 'ctr',
|
|
301
|
+
insideEnd: 'inEnd',
|
|
302
|
+
insideBase: 'inBase',
|
|
303
|
+
outsideEnd: 'outEnd',
|
|
304
|
+
bestFit: 'bestFit',
|
|
305
|
+
left: 'l',
|
|
306
|
+
right: 'r',
|
|
307
|
+
top: 't',
|
|
308
|
+
bottom: 'b',
|
|
309
|
+
}
|
|
310
|
+
const openxmlPos = position ? posMap[position] : null
|
|
311
|
+
|
|
312
|
+
const values = seriesData.values || []
|
|
313
|
+
const sumValues = values.reduce((sum, v) => sum + (Number(v) || 0), 0)
|
|
314
|
+
const seriesName = seriesData.name || ''
|
|
315
|
+
|
|
316
|
+
const hasCustomLabels = labels || labelsFromCells || template || labelMap
|
|
317
|
+
|
|
318
|
+
if (hasCustomLabels && pointsCount > 0) {
|
|
319
|
+
for (let i = 0; i < pointsCount; i++) {
|
|
320
|
+
const cat = categories[i] !== undefined ? String(categories[i]) : ''
|
|
321
|
+
const val = values[i] !== undefined ? values[i] : ''
|
|
322
|
+
|
|
323
|
+
let pct = 0
|
|
324
|
+
if (sumValues > 0 && val !== '') {
|
|
325
|
+
pct = Math.round((Number(val) / sumValues) * 100)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
let customLabel = ''
|
|
329
|
+
if (labels && labels[i] !== undefined) {
|
|
330
|
+
customLabel = String(labels[i])
|
|
331
|
+
} else if (labelMap && cat && labelMap[cat] !== undefined) {
|
|
332
|
+
customLabel = String(labelMap[cat])
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
let textContent = customLabel
|
|
336
|
+
if (template) {
|
|
337
|
+
textContent = template
|
|
338
|
+
.replace(/{category}/g, cat)
|
|
339
|
+
.replace(/{value}/g, String(val))
|
|
340
|
+
.replace(/{percentage}/g, String(pct))
|
|
341
|
+
.replace(/{series}/g, seriesName)
|
|
342
|
+
.replace(/{customLabel}/g, customLabel)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
xml += `<c:dLbl>`
|
|
346
|
+
xml += `<c:idx val="${i}"/>`
|
|
347
|
+
|
|
348
|
+
if (labelsFromCells && !template) {
|
|
349
|
+
const range = ChartWorkbookUpdater.parseCellRange(labelsFromCells)
|
|
350
|
+
const startColNum = ChartWorkbookUpdater.colLetterToNum(range.startCol)
|
|
351
|
+
|
|
352
|
+
let cellRef
|
|
353
|
+
if (range.startRow === range.endRow) {
|
|
354
|
+
cellRef = `${ChartWorkbookUpdater.numToColLetter(startColNum + i)}${range.startRow}`
|
|
355
|
+
} else {
|
|
356
|
+
cellRef = `${range.startCol}${range.startRow + i}`
|
|
357
|
+
}
|
|
358
|
+
const fullCellRef = `${range.sheetName}!$${cellRef.replace(/(\d+)/, '$$$1')}`
|
|
359
|
+
const displayVal = textContent || customLabel || ''
|
|
360
|
+
|
|
361
|
+
xml += `<c:tx>`
|
|
362
|
+
xml += `<c:strRef>`
|
|
363
|
+
xml += `<c:f>${fullCellRef}</c:f>`
|
|
364
|
+
xml += `<c:strCache>`
|
|
365
|
+
xml += `<c:ptCount val="1"/>`
|
|
366
|
+
xml += `<c:pt idx="0"><c:v>${this.#escapeXml(displayVal)}</c:v></c:pt>`
|
|
367
|
+
xml += `</c:strCache>`
|
|
368
|
+
xml += `</c:strRef>`
|
|
369
|
+
xml += `</c:tx>`
|
|
370
|
+
} else if (textContent) {
|
|
371
|
+
if (labelsFromCells) {
|
|
372
|
+
const range = ChartWorkbookUpdater.parseCellRange(labelsFromCells)
|
|
373
|
+
const startColNum = ChartWorkbookUpdater.colLetterToNum(range.startCol)
|
|
374
|
+
let cellRef
|
|
375
|
+
if (range.startRow === range.endRow) {
|
|
376
|
+
cellRef = `${ChartWorkbookUpdater.numToColLetter(startColNum + i)}${range.startRow}`
|
|
377
|
+
} else {
|
|
378
|
+
cellRef = `${range.startCol}${range.startRow + i}`
|
|
379
|
+
}
|
|
380
|
+
const fullCellRef = `${range.sheetName}!$${cellRef.replace(/(\d+)/, '$$$1')}`
|
|
381
|
+
|
|
382
|
+
xml += `<c:tx>`
|
|
383
|
+
xml += `<c:strRef>`
|
|
384
|
+
xml += `<c:f>${fullCellRef}</c:f>`
|
|
385
|
+
xml += `<c:strCache>`
|
|
386
|
+
xml += `<c:ptCount val="1"/>`
|
|
387
|
+
xml += `<c:pt idx="0"><c:v>${this.#escapeXml(textContent)}</c:v></c:pt>`
|
|
388
|
+
xml += `</c:strCache>`
|
|
389
|
+
xml += `</c:strRef>`
|
|
390
|
+
xml += `</c:tx>`
|
|
391
|
+
} else {
|
|
392
|
+
xml += `<c:tx>`
|
|
393
|
+
xml += `<c:rich>`
|
|
394
|
+
xml += `<a:bodyPr/>`
|
|
395
|
+
xml += `<a:lstStyle/>`
|
|
396
|
+
xml += `<a:p>`
|
|
397
|
+
xml += `<a:r>`
|
|
398
|
+
xml += `<a:t>${this.#escapeXml(textContent)}</a:t>`
|
|
399
|
+
xml += `</a:r>`
|
|
400
|
+
xml += `</a:p>`
|
|
401
|
+
xml += `</c:rich>`
|
|
402
|
+
xml += `</c:tx>`
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Restore individual point-level spPr (background fill, border, line) from template.
|
|
407
|
+
// Priority: individual dLbl spPr → first available individual dLbl spPr → series-level spPr.
|
|
408
|
+
// The series-level spPr fallback ensures fills are preserved even when the template stores
|
|
409
|
+
// styling only at the dLbls level (not per individual dLbl override).
|
|
410
|
+
if (existingDLblSpPrs && existingDLblSpPrs[i]) {
|
|
411
|
+
xml += existingDLblSpPrs[i]
|
|
412
|
+
} else {
|
|
413
|
+
const firstIdx =
|
|
414
|
+
existingDLblSpPrs && Object.keys(existingDLblSpPrs).length > 0
|
|
415
|
+
? Object.keys(existingDLblSpPrs)[0]
|
|
416
|
+
: undefined
|
|
417
|
+
if (firstIdx !== undefined && existingDLblSpPrs[firstIdx]) {
|
|
418
|
+
xml += existingDLblSpPrs[firstIdx]
|
|
419
|
+
} else if (existingSpPr) {
|
|
420
|
+
// Fall back to series-level spPr so fills are preserved on each label
|
|
421
|
+
xml += existingSpPr
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (labelStyle) {
|
|
426
|
+
xml += this.generateTxPrXml(labelStyle)
|
|
427
|
+
} else if (existingTxPr) {
|
|
428
|
+
xml += existingTxPr
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (openxmlPos) {
|
|
432
|
+
xml += `<c:dLblPos val="${openxmlPos}"/>`
|
|
433
|
+
} else if (existingDLblPos) {
|
|
434
|
+
xml += existingDLblPos
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
xml += `<c:showLegendKey val="0"/>`
|
|
438
|
+
xml += `<c:showVal val="0"/>`
|
|
439
|
+
xml += `<c:showCatName val="0"/>`
|
|
440
|
+
xml += `<c:showSerName val="0"/>`
|
|
441
|
+
xml += `<c:showPercent val="0"/>`
|
|
442
|
+
xml += `<c:showBubbleSize val="0"/>`
|
|
443
|
+
|
|
444
|
+
xml += `</c:dLbl>`
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (existingNumFmt) {
|
|
449
|
+
xml += existingNumFmt
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Restore series-level spPr (background fill, border, line) from template
|
|
453
|
+
if (existingSpPr) {
|
|
454
|
+
xml += existingSpPr
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (labelStyle) {
|
|
458
|
+
xml += this.generateTxPrXml(labelStyle)
|
|
459
|
+
} else if (existingTxPr) {
|
|
460
|
+
xml += existingTxPr
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (openxmlPos) {
|
|
464
|
+
xml += `<c:dLblPos val="${openxmlPos}"/>`
|
|
465
|
+
} else if (existingDLblPos) {
|
|
466
|
+
xml += existingDLblPos
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// showLegendKey
|
|
470
|
+
if (existingShowTags['showLegendKey']) {
|
|
471
|
+
xml += existingShowTags['showLegendKey']
|
|
472
|
+
} else {
|
|
473
|
+
xml += `<c:showLegendKey val="0"/>`
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// showVal
|
|
477
|
+
const defaultShowVal = hasCustomLabels ? '0' : '1'
|
|
478
|
+
if (existingShowTags['showVal'] && !hasCustomLabels) {
|
|
479
|
+
xml += existingShowTags['showVal']
|
|
480
|
+
} else {
|
|
481
|
+
xml += `<c:showVal val="${defaultShowVal}"/>`
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// showCatName
|
|
485
|
+
if (existingShowTags['showCatName']) {
|
|
486
|
+
xml += existingShowTags['showCatName']
|
|
487
|
+
} else {
|
|
488
|
+
xml += `<c:showCatName val="0"/>`
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// showSerName
|
|
492
|
+
if (existingShowTags['showSerName']) {
|
|
493
|
+
xml += existingShowTags['showSerName']
|
|
494
|
+
} else {
|
|
495
|
+
xml += `<c:showSerName val="0"/>`
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// showPercent
|
|
499
|
+
const defaultShowPercent = hasCustomLabels || !options.showPercent ? '0' : '1'
|
|
500
|
+
if (options.showPercent !== undefined) {
|
|
501
|
+
xml += `<c:showPercent val="${options.showPercent ? '1' : '0'}"/>`
|
|
502
|
+
} else if (existingShowTags['showPercent'] && !hasCustomLabels) {
|
|
503
|
+
xml += existingShowTags['showPercent']
|
|
504
|
+
} else {
|
|
505
|
+
xml += `<c:showPercent val="${defaultShowPercent}"/>`
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// showBubbleSize
|
|
509
|
+
if (existingShowTags['showBubbleSize']) {
|
|
510
|
+
xml += existingShowTags['showBubbleSize']
|
|
511
|
+
} else {
|
|
512
|
+
xml += `<c:showBubbleSize val="0"/>`
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
xml += '</c:dLbls>'
|
|
516
|
+
return xml
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
static generateTxPrXml(style) {
|
|
520
|
+
const { fontFamily, fontSize, bold, italic, underline, color } = style
|
|
521
|
+
|
|
522
|
+
const sz = fontSize ? ` sz="${fontSize * 100}"` : ''
|
|
523
|
+
const b = bold !== undefined ? ` b="${bold ? '1' : '0'}"` : ''
|
|
524
|
+
const i = italic !== undefined ? ` i="${italic ? '1' : '0'}"` : ''
|
|
525
|
+
const u = underline !== undefined ? ` u="${underline ? 'sng' : 'none'}"` : ''
|
|
526
|
+
|
|
527
|
+
let fillXml = ''
|
|
528
|
+
if (color) {
|
|
529
|
+
const cleanColor = color.replace('#', '')
|
|
530
|
+
fillXml = `<a:solidFill><a:srgbClr val="${cleanColor}"/></a:solidFill>`
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
let latinXml = ''
|
|
534
|
+
if (fontFamily) {
|
|
535
|
+
latinXml = `<a:latin typeface="${fontFamily}"/><a:cs typeface="${fontFamily}"/>`
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return `<c:txPr>
|
|
539
|
+
<a:bodyPr/>
|
|
540
|
+
<a:lstStyle/>
|
|
541
|
+
<a:p>
|
|
542
|
+
<a:pPr>
|
|
543
|
+
<a:defRPr${sz}${b}${i}${u}>
|
|
544
|
+
${fillXml}
|
|
545
|
+
${latinXml}
|
|
546
|
+
</a:defRPr>
|
|
547
|
+
</a:pPr>
|
|
548
|
+
<a:endParaRPr lang="en-US"/>
|
|
549
|
+
</a:p>
|
|
550
|
+
</c:txPr>`
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
static getDataLabelsFromXml(xml, seriesIndex) {
|
|
554
|
+
const serPattern = /<c:ser>([\s\S]*?)<\/c:ser>/g
|
|
555
|
+
const matches = [...xml.matchAll(serPattern)]
|
|
556
|
+
if (seriesIndex >= matches.length) return []
|
|
557
|
+
|
|
558
|
+
const serXml = matches[seriesIndex][1]
|
|
559
|
+
const dLblsMatch = /<c:dLbls>([\s\S]*?)<\/c:dLbls>/.exec(serXml)
|
|
560
|
+
if (!dLblsMatch) return []
|
|
561
|
+
|
|
562
|
+
const dLblsXml = dLblsMatch[1]
|
|
563
|
+
const dLblPattern = /<c:dLbl>([\s\S]*?)<\/c:dLbl>/g
|
|
564
|
+
const result = []
|
|
565
|
+
|
|
566
|
+
let dLblMatch
|
|
567
|
+
while ((dLblMatch = dLblPattern.exec(dLblsXml)) !== null) {
|
|
568
|
+
const dLblXml = dLblMatch[1]
|
|
569
|
+
const idxMatch = /<c:idx val="(\d+)"\/>/.exec(dLblXml)
|
|
570
|
+
if (!idxMatch) continue
|
|
571
|
+
const point = parseInt(idxMatch[1], 10)
|
|
572
|
+
|
|
573
|
+
let value = ''
|
|
574
|
+
const strCacheMatch = /<c:strCache>([\s\S]*?)<\/c:strCache>/.exec(dLblXml)
|
|
575
|
+
if (strCacheMatch) {
|
|
576
|
+
const vMatch = /<c:v>([^<]*)<\/c:v>/.exec(strCacheMatch[1])
|
|
577
|
+
if (vMatch) value = vMatch[1]
|
|
578
|
+
} else {
|
|
579
|
+
const tPattern = /<a:t>([^<]*)<\/a:t>/g
|
|
580
|
+
let tMatch
|
|
581
|
+
while ((tMatch = tPattern.exec(dLblXml)) !== null) {
|
|
582
|
+
value += tMatch[1]
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
result.push({ point, value })
|
|
587
|
+
}
|
|
588
|
+
return result
|
|
589
|
+
}
|
|
590
|
+
|
|
165
591
|
static #escapeXml(str) {
|
|
166
592
|
return str
|
|
167
593
|
.replace(/&/g, '&')
|