rebuild_stree.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import { Attribute } from '../enrich_mathml/enrich_attr.js';
  2. import { NamedSymbol } from '../semantic_tree/semantic_attr.js';
  3. import { SemanticFont, SemanticRole, SemanticType } from '../semantic_tree/semantic_meaning.js';
  4. import { SemanticNodeFactory } from '../semantic_tree/semantic_node_factory.js';
  5. import { SemanticSkeleton } from '../semantic_tree/semantic_skeleton.js';
  6. import { SemanticTree } from '../semantic_tree/semantic_tree.js';
  7. import * as WalkerUtil from './walker_util.js';
  8. export class RebuildStree {
  9. static textContent(snode, node, ignore) {
  10. if (!ignore && node.textContent) {
  11. snode.textContent = node.textContent;
  12. return;
  13. }
  14. const operator = WalkerUtil.splitAttribute(WalkerUtil.getAttribute(node, Attribute.OPERATOR));
  15. if (operator.length > 1) {
  16. snode.textContent = operator[1];
  17. }
  18. }
  19. static isPunctuated(collapsed) {
  20. return (!SemanticSkeleton.simpleCollapseStructure(collapsed) &&
  21. collapsed[1] &&
  22. SemanticSkeleton.contentCollapseStructure(collapsed[1]));
  23. }
  24. constructor(mathml) {
  25. this.mathml = mathml;
  26. this.factory = new SemanticNodeFactory();
  27. this.nodeDict = {};
  28. this.mmlRoot = WalkerUtil.getSemanticRoot(mathml);
  29. this.streeRoot = this.assembleTree(this.mmlRoot);
  30. this.stree = SemanticTree.fromNode(this.streeRoot, this.mathml);
  31. this.xml = this.stree.xml();
  32. }
  33. getTree() {
  34. return this.stree;
  35. }
  36. assembleTree(node) {
  37. const snode = this.makeNode(node);
  38. const children = WalkerUtil.splitAttribute(WalkerUtil.getAttribute(node, Attribute.CHILDREN));
  39. const content = WalkerUtil.splitAttribute(WalkerUtil.getAttribute(node, Attribute.CONTENT));
  40. if (content.length === 0 && children.length === 0) {
  41. RebuildStree.textContent(snode, node);
  42. return snode;
  43. }
  44. if (content.length > 0) {
  45. const fcontent = WalkerUtil.getBySemanticId(this.mathml, content[0]);
  46. if (fcontent) {
  47. RebuildStree.textContent(snode, fcontent, true);
  48. }
  49. }
  50. snode.contentNodes = content.map((id) => this.setParent(id, snode));
  51. snode.childNodes = children.map((id) => this.setParent(id, snode));
  52. const collapsed = WalkerUtil.getAttribute(node, Attribute.COLLAPSED);
  53. return collapsed ? this.postProcess(snode, collapsed) : snode;
  54. }
  55. makeNode(node) {
  56. const type = WalkerUtil.getAttribute(node, Attribute.TYPE);
  57. const role = WalkerUtil.getAttribute(node, Attribute.ROLE);
  58. const font = WalkerUtil.getAttribute(node, Attribute.FONT);
  59. const annotation = WalkerUtil.getAttribute(node, Attribute.ANNOTATION) || '';
  60. const attributes = WalkerUtil.getAttribute(node, Attribute.ATTRIBUTES) || '';
  61. const id = WalkerUtil.getAttribute(node, Attribute.ID);
  62. const embellished = WalkerUtil.getAttribute(node, Attribute.EMBELLISHED);
  63. const fencepointer = WalkerUtil.getAttribute(node, Attribute.FENCEPOINTER);
  64. const snode = this.createNode(parseInt(id, 10));
  65. snode.type = type;
  66. snode.role = role;
  67. snode.font = font ? font : SemanticFont.UNKNOWN;
  68. snode.parseAnnotation(annotation);
  69. snode.parseAttributes(attributes);
  70. if (fencepointer) {
  71. snode.fencePointer = fencepointer;
  72. }
  73. if (embellished) {
  74. snode.embellished = embellished;
  75. }
  76. return snode;
  77. }
  78. makePunctuation(id) {
  79. const node = this.createNode(id);
  80. node.updateContent(NamedSymbol.invisibleComma);
  81. node.role = SemanticRole.DUMMY;
  82. return node;
  83. }
  84. makePunctuated(snode, collapsed, role) {
  85. const punctuated = this.createNode(collapsed[0]);
  86. punctuated.type = SemanticType.PUNCTUATED;
  87. punctuated.embellished = snode.embellished;
  88. punctuated.fencePointer = snode.fencePointer;
  89. punctuated.role = role;
  90. const cont = collapsed.splice(1, 1)[0].slice(1);
  91. punctuated.contentNodes = cont.map(this.makePunctuation.bind(this));
  92. this.collapsedChildren_(collapsed);
  93. }
  94. makeEmpty(snode, collapsed, role) {
  95. const empty = this.createNode(collapsed);
  96. empty.type = SemanticType.EMPTY;
  97. empty.embellished = snode.embellished;
  98. empty.fencePointer = snode.fencePointer;
  99. empty.role = role;
  100. }
  101. makeIndex(snode, collapsed, role) {
  102. if (RebuildStree.isPunctuated(collapsed)) {
  103. this.makePunctuated(snode, collapsed, role);
  104. collapsed = collapsed[0];
  105. return;
  106. }
  107. if (SemanticSkeleton.simpleCollapseStructure(collapsed) &&
  108. !this.nodeDict[collapsed.toString()]) {
  109. this.makeEmpty(snode, collapsed, role);
  110. }
  111. }
  112. postProcess(snode, collapsed) {
  113. const array = SemanticSkeleton.fromString(collapsed).array;
  114. if (snode.type === SemanticRole.SUBSUP) {
  115. const subscript = this.createNode(array[1][0]);
  116. subscript.type = SemanticType.SUBSCRIPT;
  117. subscript.role = SemanticRole.SUBSUP;
  118. snode.type = SemanticType.SUPERSCRIPT;
  119. subscript.embellished = snode.embellished;
  120. subscript.fencePointer = snode.fencePointer;
  121. this.makeIndex(snode, array[1][2], SemanticRole.RIGHTSUB);
  122. this.makeIndex(snode, array[2], SemanticRole.RIGHTSUPER);
  123. this.collapsedChildren_(array);
  124. return snode;
  125. }
  126. if (snode.type === SemanticType.SUBSCRIPT) {
  127. this.makeIndex(snode, array[2], SemanticRole.RIGHTSUB);
  128. this.collapsedChildren_(array);
  129. return snode;
  130. }
  131. if (snode.type === SemanticType.SUPERSCRIPT) {
  132. this.makeIndex(snode, array[2], SemanticRole.RIGHTSUPER);
  133. this.collapsedChildren_(array);
  134. return snode;
  135. }
  136. if (snode.type === SemanticType.TENSOR) {
  137. this.makeIndex(snode, array[2], SemanticRole.LEFTSUB);
  138. this.makeIndex(snode, array[3], SemanticRole.LEFTSUPER);
  139. this.makeIndex(snode, array[4], SemanticRole.RIGHTSUB);
  140. this.makeIndex(snode, array[5], SemanticRole.RIGHTSUPER);
  141. this.collapsedChildren_(array);
  142. return snode;
  143. }
  144. if (snode.type === SemanticType.PUNCTUATED) {
  145. if (RebuildStree.isPunctuated(array)) {
  146. const cont = array.splice(1, 1)[0].slice(1);
  147. snode.contentNodes = cont.map(this.makePunctuation.bind(this));
  148. }
  149. return snode;
  150. }
  151. if (snode.type === SemanticRole.UNDEROVER) {
  152. const score = this.createNode(array[1][0]);
  153. if (snode.childNodes[1].role === SemanticRole.OVERACCENT) {
  154. score.type = SemanticType.OVERSCORE;
  155. snode.type = SemanticType.UNDERSCORE;
  156. }
  157. else {
  158. score.type = SemanticType.UNDERSCORE;
  159. snode.type = SemanticType.OVERSCORE;
  160. }
  161. score.role = SemanticRole.UNDEROVER;
  162. score.embellished = snode.embellished;
  163. score.fencePointer = snode.fencePointer;
  164. this.collapsedChildren_(array);
  165. return snode;
  166. }
  167. return snode;
  168. }
  169. createNode(id) {
  170. const node = this.factory.makeNode(id);
  171. this.nodeDict[id.toString()] = node;
  172. return node;
  173. }
  174. collapsedChildren_(collapsed) {
  175. const recurseCollapsed = (coll) => {
  176. const parent = this.nodeDict[coll[0]];
  177. parent.childNodes = [];
  178. for (let j = 1, l = coll.length; j < l; j++) {
  179. const id = coll[j];
  180. parent.childNodes.push(SemanticSkeleton.simpleCollapseStructure(id)
  181. ? this.nodeDict[id]
  182. : recurseCollapsed(id));
  183. }
  184. return parent;
  185. };
  186. recurseCollapsed(collapsed);
  187. }
  188. setParent(id, snode) {
  189. const mml = WalkerUtil.getBySemanticId(this.mathml, id);
  190. const sn = this.assembleTree(mml);
  191. sn.parent = snode;
  192. return sn;
  193. }
  194. }