shared-strings-xform.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. const XmlStream = require('../../../utils/xml-stream');
  2. const BaseXform = require('../base-xform');
  3. const SharedStringXform = require('./shared-string-xform');
  4. class SharedStringsXform extends BaseXform {
  5. constructor(model) {
  6. super();
  7. this.model = model || {
  8. values: [],
  9. count: 0,
  10. };
  11. this.hash = Object.create(null);
  12. this.rich = Object.create(null);
  13. }
  14. get sharedStringXform() {
  15. return this._sharedStringXform || (this._sharedStringXform = new SharedStringXform());
  16. }
  17. get values() {
  18. return this.model.values;
  19. }
  20. get uniqueCount() {
  21. return this.model.values.length;
  22. }
  23. get count() {
  24. return this.model.count;
  25. }
  26. getString(index) {
  27. return this.model.values[index];
  28. }
  29. add(value) {
  30. return value.richText ? this.addRichText(value) : this.addText(value);
  31. }
  32. addText(value) {
  33. let index = this.hash[value];
  34. if (index === undefined) {
  35. index = this.hash[value] = this.model.values.length;
  36. this.model.values.push(value);
  37. }
  38. this.model.count++;
  39. return index;
  40. }
  41. addRichText(value) {
  42. // TODO: add WeakMap here
  43. const xml = this.sharedStringXform.toXml(value);
  44. let index = this.rich[xml];
  45. if (index === undefined) {
  46. index = this.rich[xml] = this.model.values.length;
  47. this.model.values.push(value);
  48. }
  49. this.model.count++;
  50. return index;
  51. }
  52. // <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  53. // <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="<%=totalRefs%>" uniqueCount="<%=count%>">
  54. // <si><t><%=text%></t></si>
  55. // <si><r><rPr></rPr><t></t></r></si>
  56. // </sst>
  57. render(xmlStream, model) {
  58. model = model || this._values;
  59. xmlStream.openXml(XmlStream.StdDocAttributes);
  60. xmlStream.openNode('sst', {
  61. xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
  62. count: model.count,
  63. uniqueCount: model.values.length,
  64. });
  65. const sx = this.sharedStringXform;
  66. model.values.forEach(sharedString => {
  67. sx.render(xmlStream, sharedString);
  68. });
  69. xmlStream.closeNode();
  70. }
  71. parseOpen(node) {
  72. if (this.parser) {
  73. this.parser.parseOpen(node);
  74. return true;
  75. }
  76. switch (node.name) {
  77. case 'sst':
  78. return true;
  79. case 'si':
  80. this.parser = this.sharedStringXform;
  81. this.parser.parseOpen(node);
  82. return true;
  83. default:
  84. throw new Error(`Unexpected xml node in parseOpen: ${JSON.stringify(node)}`);
  85. }
  86. }
  87. parseText(text) {
  88. if (this.parser) {
  89. this.parser.parseText(text);
  90. }
  91. }
  92. parseClose(name) {
  93. if (this.parser) {
  94. if (!this.parser.parseClose(name)) {
  95. this.model.values.push(this.parser.model);
  96. this.model.count++;
  97. this.parser = undefined;
  98. }
  99. return true;
  100. }
  101. switch (name) {
  102. case 'sst':
  103. return false;
  104. default:
  105. throw new Error(`Unexpected xml node in parseClose: ${name}`);
  106. }
  107. }
  108. }
  109. module.exports = SharedStringsXform;