4 * ASCIIMathPHP and associated classes:
\r
6 * -- MathMLNode extends XMLNode
\r
8 * These classes are a PHP port of ASCIIMath
\r
9 * Version 1.3 Feb 19 2004, (c) Peter Jipsen http://www.chapman.edu/~jipsen
\r
11 * ASCIIMathPHP Version 1.11, 26 April 2006, (c) Kee-Lin Steven Chan (kc56@cornell.edu)
\r
13 * This program is free software; you can redistribute it and/or modify
\r
14 * it under the terms of the GNU General Public License as published by
\r
15 * the Free Software Foundation; either version 2 of the License, or (at
\r
16 * your option) any later version.
\r
18 * This program is distributed in the hope that it will be useful,
\r
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
21 * General Public License (at http://www.gnu.org/copyleft/gpl.html)
\r
27 * -- PHP5 only version of ASCIIMathPHP
\r
30 * -- Included the missing setCurrExpr() method
\r
33 * -- Added changes that David Lippman <DLippman@pierce.ctc.edu> made to bring ASCIIMathPHP up to
\r
34 * ASCIIMath 1.4.7 functionality.
\r
35 * -- Added parseIntExpr, for intermediate expression parsing rule, allowing x^2/x^3 to render as (x^2)/(x^3)
\r
36 * -- Added quotes as another way of designating text; "hello" is equivalent to text(hello)
\r
37 * -- Added FUNC designator to allow sin, cos, etc to act as functions, so sin(x)/x renders as {sin(x)}/x
\r
40 * -- Fixed bug that stopped script execution for incomplete expressions
\r
41 * -- Changed the algorithm for parsing expressions so that it matches the longest string possible (greedy)
\r
44 * -- Added definition support
\r
45 * -- Added stackrel support
\r
46 * -- Added a bunch of different symbols etc. >>, << and definitions like dx, dy, dz etc.
\r
49 * -- Fixed bug with mbox and text
\r
50 * -- Fixed spacing bug with mbox and text
\r
53 * -- Fixed Bug that did not parse symbols greater than a single character
\r
54 * correctly when appearing at end of expression.
\r
60 // Private variables
\r
72 function XMLNode($id = NULL)
\r
74 $this->_id = isset($id) ? $id : md5(uniqid(rand(),1));
\r
76 $this->_content = '';
\r
77 $this->_mt_elem_flg = FALSE;
\r
78 $this->_attr_arr = array();
\r
79 $this->_child_arr = array();
\r
81 $this->_nmspc_alias = '';
\r
82 $this->_parent_id = FALSE;
\r
83 $this->_parent_node = NULL;
\r
86 function addChild(&$node)
\r
88 $this->_child_arr[$node->getId()] = $node;
\r
89 $node->setParentId($this->_id);
\r
90 $node->setParentNode($this);
\r
93 function addChildArr(&$node_arr)
\r
95 $key_arr = array_keys($node_arr);
\r
96 $num_key = count($key_arr);
\r
98 for ($i = 0; $i < $num_key; $i++) {
\r
99 $node = $node_arr[$key_arr[$i]];
\r
100 $this->addChild($node);
\r
104 function insertChildBefore($idx,&$node)
\r
106 $key_arr = array_keys($this->_child_arr);
\r
107 $num_key = count($key_arr);
\r
110 for ($i = 0;$i < $num_key;$i++) {
\r
112 $tmp_arr[$node->getId()] = $node;
\r
114 $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]];
\r
116 $this->_child_arr = $tmp_arr;
\r
119 function insertChildAfter($idx,&$node)
\r
121 $key_arr = array_keys($this->_child_arr);
\r
122 $num_key = count($key_arr);
\r
125 for ($i = 0;$i < $num_key;$i++) {
\r
126 $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]];
\r
128 $tmp_arr[$node->getId()] = $node;
\r
131 $this->_child_arr = $tmp_arr;
\r
134 function setId($id)
\r
139 function setName($name)
\r
141 $this->_name = $name;
\r
144 function setNamepace($nmspc)
\r
146 $this->_nmspc = $nmspc;
\r
149 function setNamespaceAlias($nmspc_alias)
\r
151 $this->_nmspc_alias = $nmspc_alias;
\r
154 function setContent($content)
\r
156 $this->_content = $content;
\r
159 function setEmptyElem($mt_elem_flg)
\r
161 $this->_mt_elem_flg = $mt_elem_flg;
\r
164 function setAttr($attr_nm,$attr_val)
\r
166 $this->_attr_arr[$attr_nm] = $attr_val;
\r
169 function setAttrArr($attr_arr)
\r
171 $this->_attr_arr = $attr_arr;
\r
174 function setParentId($id)
\r
176 $this->_parent_id = $id;
\r
179 function setParentNode(&$node)
\r
181 $this->_parent_node = $node;
\r
186 return($this->_id);
\r
191 return($this->_name);
\r
194 function getNamespace()
\r
196 return($this->_nmspc);
\r
199 function getNamespaceAlias()
\r
201 return($this->_nmspc_alias);
\r
204 function getContent()
\r
206 return($this->_content);
\r
209 function getAttr($attr_nm)
\r
211 if (isset($this->_attr_arr[$attr_nm])) {
\r
212 return($this->_attr_arr[$attr_nm]);
\r
218 function getAttrArr()
\r
220 return($this->_attr_arr);
\r
223 function getParentId()
\r
225 return($this->parent_id);
\r
228 function getParentNode()
\r
230 return($this->_parent_node);
\r
233 function getChild($id)
\r
235 if (isset($this->_child_arr[$id])) {
\r
236 return($this->_child_arr[$id]);
\r
242 function getFirstChild()
\r
244 $id_arr = array_keys($this->_child_arr);
\r
245 $num_child = count($id_arr);
\r
247 if ($num_child > 0) {
\r
248 return($this->_child_arr[$id_arr[0]]);
\r
254 function getLastChild()
\r
256 $id_arr = array_keys($this->_child_arr);
\r
257 $num_child = count($id_arr);
\r
259 if ($num_child > 0) {
\r
260 return($this->_child_arr[$id_arr[$num_child - 1]]);
\r
266 function getChildByIdx($idx)
\r
268 $id_arr = array_keys($this->_child_arr);
\r
270 if (isset($this->_child_arr[$id_arr[$idx]])) {
\r
271 return($this->_child_arr[$id_arr[$idx]]);
\r
277 function getNumChild()
\r
279 return(count($this->_child_arr));
\r
282 function removeChild($id)
\r
284 unset($this->_child_arr[$id]);
\r
287 function removeChildByIdx($idx)
\r
289 $key_arr = array_keys($this->_child_arr);
\r
290 unset($this->_child_arr[$key_arr[$idx]]);
\r
293 function removeFirstChild()
\r
295 $key_arr = array_keys($this->_child_arr);
\r
296 unset($this->_child_arr[$key_arr[0]]);
\r
299 function removeLastChild()
\r
301 $key_arr = array_keys($this->_child_arr);
\r
302 unset($this->_child_arr[$key_arr[count($key_arr)-1]]);
\r
305 function dumpXML($indent_str = "\t")
\r
307 $attr_txt = $this->_dumpAttr();
\r
308 $name = $this->_dumpName();
\r
309 $xmlns = $this->_dumpXmlns();
\r
310 $lvl = $this->_getCurrentLevel();
\r
311 $indent = str_pad('',$lvl,$indent_str);
\r
313 if ($this->_mt_elem_flg) {
\r
314 $tag = "$indent<$name$xmlns$attr_txt />";
\r
317 $key_arr = array_keys($this->_child_arr);
\r
318 $num_child = count($key_arr);
\r
320 $tag = "$indent<$name$xmlns$attr_txt>$this->_content";
\r
322 for ($i = 0;$i < $num_child;$i++) {
\r
323 $node = $this->_child_arr[$key_arr[$i]];
\r
325 $child_txt = $node->dumpXML($indent_str);
\r
326 $tag .= "\n$child_txt";
\r
329 $tag .= ($num_child > 0 ? "\n$indent</$name>" : "</$name>");
\r
334 function _dumpAttr()
\r
336 $id_arr = array_keys($this->_attr_arr);
\r
337 $id_arr_cnt = count($id_arr);
\r
340 for($i = 0;$i < $id_arr_cnt;$i++) {
\r
341 $key = $id_arr[$i];
\r
342 $attr_txt .= " $key=\"{$this->_attr_arr[$key]}\"";
\r
348 function _dumpName()
\r
350 $alias = $this->getNamespaceAlias();
\r
351 if ($alias == '') {
\r
352 return($this->getName());
\r
354 return("$alias:" . $this->getName());
\r
358 function _dumpXmlns()
\r
360 $nmspc = $this->getNamespace();
\r
361 $alias = $this->getNamespaceAlias();
\r
363 if ($nmspc != '') {
\r
364 if ($alias == '') {
\r
365 return(" xmlns=\"" . $nmspc . "\"");
\r
367 return(" xmlns:$alias=\"" . $nmspc . "\"");
\r
374 function _getCurrentLevel()
\r
376 if ($this->_parent_id === FALSE) {
\r
379 $node = $this->getParentNode();
\r
380 $lvl = $node->_getCurrentLevel();
\r
387 class MathMLNode extends XMLNode
\r
389 function MathMLNode($id = NULL)
\r
391 parent::XMLNode($id);
\r
394 function removeBrackets()
\r
396 if ($this->_name == 'mrow') {
\r
397 if ($c_node_0 = $this->getFirstChild()) {
\r
398 $c_node_0->isLeftBracket() ? $this->removeFirstChild() : 0;
\r
401 if ($c_node_0 = $this->getLastChild()) {
\r
402 $c_node_0->isRightBracket() ? $this->removeLastChild() : 0;
\r
407 function isLeftBracket()
\r
409 switch ($this->_content) {
\r
419 function isRightBracket()
\r
421 switch ($this->_content) {
\r
441 function ASCIIMathPHP($symbol_arr,$expr = NULL)
\r
443 $this->_symbol_arr = $symbol_arr;
\r
444 if (isset($expr)) {
\r
445 $this->setExpr($expr);
\r
450 * Returns an empty node (containing a non-breaking space) 26-Apr-2006
\r
452 * Used when an expression is incomplete
\r
458 function emptyNode()
\r
460 $tmp_node = $this->createNode();
\r
461 $tmp_node->setName('mn');
\r
462 $tmp_node->setContent('&#' . hexdec('200B') . ';');
\r
466 function pushExpr($prefix) // 2005-06-11 wes
\r
468 $this->_curr_expr = $prefix . $this->_curr_expr;
\r
471 function setExpr($expr)
\r
473 $this->_expr = $expr;
\r
474 $this->_curr_expr = $expr;
\r
475 $this->_prev_expr = $expr;
\r
477 $this->_node_arr = array();
\r
478 $this->_node_cntr = 0;
\r
481 function genMathML($attr_arr = NULL)
\r
484 $node_0 = $this->createNode();
\r
485 $node_0->setName('math');
\r
486 $node_0->setNamepace('http://www.w3.org/1998/Math/MathML');
\r
489 if (isset($attr_arr)) {
\r
490 $node_1 = $this->createNode();
\r
491 $node_1->setName('mstyle');
\r
492 $node_1->setAttrArr($attr_arr);
\r
494 $node_arr = $this->parseExpr();
\r
496 $node_1->addChildArr($node_arr);
\r
497 $node_0->addChild($node_1);
\r
499 $node_arr = $this->parseExpr();
\r
500 $node_0->addChildArr($node_arr);
\r
507 function mergeNodeArr(&$node_arr_0,&$node_arr_1)
\r
509 $key_arr_0 = array_keys($node_arr_0);
\r
510 $key_arr_1 = array_keys($node_arr_1);
\r
512 $num_key_0 = count($key_arr_0);
\r
513 $num_key_1 = count($key_arr_1);
\r
515 $merge_arr = array();
\r
517 for ($i = 0;$i < $num_key_0;$i++) {
\r
518 $merge_arr[$key_arr_0[$i]] = $node_arr_0[$key_arr_0[$i]];
\r
521 for ($j = 0;$j < $num_key_1;$i++) {
\r
522 $merge_arr[$key_arr_1[$i]] = $node_arr_1[$key_arr_1[$i]];
\r
525 return($merge_arr);
\r
529 //Broken out of parseExpr Sept 7, 2006 David Lippman for
\r
530 //ASCIIMathML 1.4.7 compatibility
\r
531 function parseIntExpr()
\r
533 $sym_0 = $this->getSymbol();
\r
534 $node_0 = $this->parseSmplExpr();
\r
535 $sym = $this->getSymbol();
\r
537 if (isset($sym['infix']) && $sym['input'] != '/') {
\r
538 $this->chopExpr($sym['symlen']);
\r
539 $node_1 = $this->parseSmplExpr();
\r
541 if ($node_1 === FALSE) { //show box in place of missing argument
\r
542 $node_1 = $this->emptyNode();//??
\r
544 $node_1->removeBrackets();
\r
547 // If 'sub' -- subscript
\r
548 if ($sym['input'] == '_') {
\r
550 $sym_1 = $this->getSymbol();
\r
552 // If 'sup' -- superscript
\r
553 if ($sym_1['input'] == '^') {
\r
554 $this->chopExpr($sym_1['symlen']);
\r
555 $node_2 = $this->parseSmplExpr();
\r
556 $node_2->removeBrackets();
\r
558 $node_3 = $this->createNode();
\r
559 $node_3->setName(isset($sym_0['underover']) ? 'munderover' : 'msubsup');
\r
560 $node_3->addChild($node_0);
\r
561 $node_3->addChild($node_1);
\r
562 $node_3->addChild($node_2);
\r
564 $node_4 = $this->createNode();
\r
565 $node_4->setName('mrow');
\r
566 $node_4->addChild($node_3);
\r
570 $node_2 = $this->createNode();
\r
571 $node_2->setName(isset($sym_0['underover']) ? 'munder' : 'msub');
\r
572 $node_2->addChild($node_0);
\r
573 $node_2->addChild($node_1);
\r
578 $node_2 = $this->createNode();
\r
579 $node_2->setName($sym['tag']);
\r
580 $node_2->addChild($node_0);
\r
581 $node_2->addChild($node_1);
\r
585 } elseif ($node_0 !== FALSE) {
\r
588 return $this->emptyNode();
\r
593 function parseExpr()
\r
595 // Child/Fragment array
\r
596 $node_arr = array();
\r
598 // Deal whole expressions like 'ax + by + c = 0' etc.
\r
600 $sym_0 = $this->getSymbol();
\r
601 $node_0 = $this->parseIntExpr();
\r
602 $sym = $this->getSymbol();
\r
605 if (isset($sym['infix']) && $sym['input'] == '/') {
\r
606 $this->chopExpr($sym['symlen']);
\r
607 $node_1 = $this->parseIntExpr();
\r
609 if ($node_1 === FALSE) { //should show box in place of missing argument
\r
610 $node_1 = $this->emptyNode();
\r
614 $node_1->removeBrackets();
\r
616 // If 'div' -- divide
\r
617 $node_0->removeBrackets();
\r
618 $node_2 = $this->createNode();
\r
619 $node_2->setName($sym['tag']);
\r
620 $node_2->addChild($node_0);
\r
621 $node_2->addChild($node_1);
\r
622 $node_arr[$node_2->getId()] = $node_2;
\r
624 } elseif ($node_0 !== FALSE) {
\r
625 $node_arr[$node_0->getId()] = $node_0;
\r
627 } while (!isset($sym['right_bracket']) && $sym !== FALSE && $sym['output'] != '');
\r
630 // Possibly to deal with matrices
\r
631 if (isset($sym['right_bracket'])) {
\r
632 $node_cnt = count($node_arr);
\r
633 $key_node_arr = array_keys($node_arr);
\r
635 if ($node_cnt > 1) {
\r
636 $node_5 = $node_arr[$key_node_arr[$node_cnt-1]];
\r
637 $node_6 = $node_arr[$key_node_arr[$node_cnt-2]];
\r
643 // Dealing with matrices
\r
644 if ($node_5 !== FALSE && $node_6 !== FALSE &&
\r
646 $node_5->getName() == 'mrow' &&
\r
647 $node_6->getName() == 'mo' &&
\r
648 $node_6->getContent() == ',') {
\r
650 // Checking if Node 5 has a LastChild
\r
651 if ($node_7 = $node_5->getLastChild()) {
\r
652 $node_7_cntnt = $node_7->getContent();
\r
654 $node_7_cntnt = FALSE;
\r
657 // If there is a right bracket
\r
658 if ($node_7 !== FALSE && ($node_7_cntnt == ']' || $node_7_cntnt == ')')) {
\r
660 // Checking if Node 5 has a firstChild
\r
661 if ($node_8 = $node_5->getFirstChild()) {
\r
662 $node_8_cntnt = $node_8->getContent();
\r
664 $node_8_cntnt = FALSE;
\r
667 // If there is a matching left bracket
\r
668 if ($node_8 !== FALSE &&
\r
669 (($node_8_cntnt == '(' && $node_7_cntnt == ')' && $sym['output'] != '}') ||
\r
670 ($node_8_cntnt == '[' && $node_7_cntnt == ']'))) {
\r
672 $is_mtrx_flg = TRUE;
\r
673 $comma_pos_arr = array();
\r
677 while ($i < $node_cnt && $is_mtrx_flg) {
\r
678 $tmp_node = $node_arr[$key_node_arr[$i]];
\r
680 if($tmp_node_first = $tmp_node->getFirstChild()) {
\r
681 $tnfc = $tmp_node_first->getContent();
\r
686 if($tmp_node_last = $tmp_node->getLastChild()) {
\r
687 $tnlc = $tmp_node_last->getContent();
\r
692 if (isset($key_node_arr[$i+1])) {
\r
693 $next_tmp_node = $node_arr[$key_node_arr[$i+1]];
\r
694 $ntnn = $next_tmp_node->getName();
\r
695 $ntnc = $next_tmp_node->getContent();
\r
701 // Checking each node in node array for matrix criteria
\r
702 if ($is_mtrx_flg) {
\r
703 $is_mtrx_flg = $tmp_node->getName() == 'mrow' &&
\r
704 ($i == $node_cnt-1 || $ntnn == 'mo' && $ntnc == ',') &&
\r
705 $tnfc == $node_8_cntnt && $tnlc == $node_7_cntnt;
\r
708 if ($is_mtrx_flg) {
\r
709 for ($j = 0;$j < $tmp_node->getNumChild();$j++) {
\r
710 $tmp_c_node = $tmp_node->getChildByIdx($j);
\r
712 if ($tmp_c_node->getContent() == ',') {
\r
713 $comma_pos_arr[$i][] = $j;
\r
718 if ($is_mtrx_flg && $i > 1) {
\r
720 $cnt_cpan = isset($comma_pos_arr[$i]) ? count($comma_pos_arr[$i]) : NULL;
\r
721 $cnt_cpap = isset($comma_pos_arr[$i-2]) ? count($comma_pos_arr[$i-2]) : NULL;
\r
722 $is_mtrx_flg = $cnt_cpan == $cnt_cpap;
\r
728 // If the node passes the matrix tests
\r
729 if ($is_mtrx_flg) {
\r
730 $tab_node_arr = array();
\r
732 for ($i = 0;$i < $node_cnt;$i += 2) {
\r
733 $tmp_key_node_arr = array_keys($node_arr);
\r
734 if (!($tmp_node = $node_arr[$tmp_key_node_arr[0]])) {
\r
737 $num_child = $tmp_node->getNumChild();
\r
740 $tmp_node->removeFirstChild();
\r
742 $row_node_arr = array();
\r
743 $row_frag_node_arr = array();
\r
745 for ($j = 1;$j < ($num_child-1);$j++) {
\r
746 if (isset($comma_pos_arr[$i][$k]) &&
\r
747 $j == $comma_pos_arr[$i][$k]) {
\r
749 $tmp_node->removeFirstChild();
\r
751 $tmp_c_node = $this->createNode();
\r
752 $tmp_c_node->setName('mtd');
\r
753 $tmp_c_node->addChildArr($row_frag_node_arr);
\r
754 $row_frag_node_arr = array();
\r
756 $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
\r
761 if ($tmp_c_node = $tmp_node->getFirstChild()) {
\r
762 $row_frag_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
\r
763 $tmp_node->removeFirstChild();
\r
768 $tmp_c_node = $this->createNode();
\r
769 $tmp_c_node->setName('mtd');
\r
770 $tmp_c_node->addChildArr($row_frag_node_arr);
\r
772 $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
\r
774 if (count($node_arr) > 2) {
\r
775 $tmp_key_node_arr = array_keys($node_arr);
\r
776 unset($node_arr[$tmp_key_node_arr[0]]);
\r
777 unset($node_arr[$tmp_key_node_arr[1]]);
\r
780 $tmp_c_node = $this->createNode();
\r
781 $tmp_c_node->setName('mtr');
\r
782 $tmp_c_node->addChildArr($row_node_arr);
\r
784 $tab_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
\r
787 $tmp_c_node = $this->createNode();
\r
788 $tmp_c_node->setName('mtable');
\r
789 $tmp_c_node->addChildArr($tab_node_arr);
\r
791 if (isset($sym['invisible'])) {
\r
792 $tmp_c_node->setAttr('columnalign','left');
\r
795 $key_node_arr = array_keys($node_arr);
\r
796 $tmp_c_node->setId($key_node_arr[0]);
\r
798 $node_arr[$tmp_c_node->getId()] = $tmp_c_node;
\r
804 $this->chopExpr($sym['symlen']);
\r
805 if (!isset($sym['invisible'])) {
\r
806 $node_7 = $this->createNode();
\r
807 $node_7->setName('mo');
\r
808 $node_7->setContent($sym['output']);
\r
809 $node_arr[$node_7->getId()] = $node_7;
\r
816 function parseSmplExpr()
\r
818 $sym = $this->getSymbol();
\r
820 if (!$sym || isset($sym['right_bracket'])) //return FALSE;
\r
821 return $this->emptyNode();
\r
823 $this->chopExpr($sym['symlen']);
\r
825 // 2005-06-11 wes: add definition type support
\r
826 if(isset($sym['definition'])) {
\r
827 $this->pushExpr($sym['output']);
\r
828 $sym = $this->getSymbol();
\r
829 $this->chopExpr($sym['symlen']);
\r
832 if (isset($sym['left_bracket'])) {
\r
833 $node_arr = $this->parseExpr();
\r
835 if (isset($sym['invisible'])) {
\r
836 $node_0 = $this->createNode();
\r
837 $node_0->setName('mrow');
\r
838 $node_0->addChildArr($node_arr);
\r
842 $node_0 = $this->createNode();
\r
843 $node_0->setName('mo');
\r
844 $node_0->setContent($sym['output']);
\r
846 $node_1 = $this->createNode();
\r
847 $node_1->setName('mrow');
\r
848 $node_1->addChild($node_0);
\r
849 $node_1->addChildArr($node_arr);
\r
853 } elseif (isset($sym['unary'])) {
\r
855 if ($sym['input'] == 'sqrt') {
\r
856 $node_0 = $this->parseSmplExpr();
\r
857 $node_0->removeBrackets();
\r
859 $node_1 = $this->createNode();
\r
860 $node_1->setName($sym['tag']);
\r
861 $node_1->addChild($node_0);
\r
864 } elseif (isset($sym['func'])) { //added 2006-9-7 David Lippman
\r
865 $expr = ltrim($this->getCurrExpr());
\r
867 $node_0 = $this->parseSmplExpr();
\r
868 //$node_0->removeBrackets();
\r
869 if ($st=='^' || $st == '_' || $st=='/' || $st=='|' || $st==',') {
\r
870 $node_1 = $this->createNode();
\r
871 $node_1->setName($sym['tag']);
\r
872 $node_1->setContent($sym['output']);
\r
873 $this->setCurrExpr($expr);
\r
876 $node_1 = $this->createNode();
\r
877 $node_1->setName('mrow');
\r
878 $node_2 = $this->createNode();
\r
879 $node_2->setName($sym['tag']);
\r
880 $node_2->setContent($sym['output']);
\r
881 $node_1->addChild($node_2);
\r
882 $node_1->addChild($node_0);
\r
885 } elseif ($sym['input'] == 'text' || $sym['input'] == 'mbox' || $sym['input'] == '"') {
\r
886 $expr = ltrim($this->getCurrExpr());
\r
887 if ($sym['input']=='"') {
\r
889 $txt = substr($expr,0,strpos($expr,$end_brckt));
\r
902 $end_brckt = chr(11); // A character that will never be matched.
\r
905 $txt = substr($expr,1,strpos($expr,$end_brckt)-1);
\r
908 //$txt = substr($expr,1,strpos($expr,$end_brckt)-1);
\r
909 $len = strlen($txt);
\r
911 $node_0 = $this->createNode();
\r
912 $node_0->setName('mrow');
\r
915 if ($txt{0} == " ") {
\r
916 $node_1 = $this->createNode();
\r
917 $node_1->setName('mspace');
\r
918 $node_1->setAttr('width','1ex');
\r
920 $node_0->addChild($node_1);
\r
923 $node_3 = $this->createNode();
\r
924 $node_3->setName($sym['tag']);
\r
925 $node_3->setContent(trim($txt));
\r
927 $node_0->addChild($node_3);
\r
929 if ($len > 1 && $txt{$len-1} == " ") {
\r
930 $node_2 = $this->createNode();
\r
931 $node_2->setName('mspace');
\r
932 $node_2->setAttr('width','1ex');
\r
934 $node_0->addChild($node_2);
\r
937 $this->chopExpr($len+2);
\r
941 } elseif (isset($sym['acc'])) {
\r
942 $node_0 = $this->parseSmplExpr();
\r
943 $node_0->removeBrackets();
\r
945 $node_1 = $this->createNode();
\r
946 $node_1->setName($sym['tag']);
\r
947 $node_1->addChild($node_0);
\r
949 $node_2 = $this->createNode();
\r
950 $node_2->setName('mo');
\r
951 $node_2->setContent($sym['output']);
\r
953 $node_1->addChild($node_2);
\r
956 // Font change commands -- to complete
\r
958 } elseif (isset($sym['binary'])) {
\r
959 $node_arr = array();
\r
961 $node_0 = $this->parseSmplExpr();
\r
962 $node_0->removeBrackets();
\r
964 $node_1 = $this->parseSmplExpr();
\r
965 $node_1->removeBrackets();
\r
967 /* 2005-06-05 wes: added stackrel */
\r
968 if ($sym['input'] == 'root' || $sym['input'] == 'stackrel') {
\r
969 $node_arr[$node_1->getId()] = $node_1;
\r
970 $node_arr[$node_0->getId()] = $node_0;
\r
971 } elseif ($sym['input'] == 'frac') {
\r
972 $node_arr[$node_0->getId()] = $node_0;
\r
973 $node_arr[$node_1->getId()] = $node_1;
\r
976 $node_2 = $this->createNode();
\r
977 $node_2->setName($sym['tag']);
\r
978 $node_2->addChildArr($node_arr);
\r
981 } elseif (isset($sym['infix'])) {
\r
982 $node_0 = $this->createNode();
\r
983 $node_0->setName('mo');
\r
984 $node_0->setContent($sym['output']);
\r
987 } elseif (isset($sym['space'])) {
\r
988 $node_0 = $this->createNode();
\r
989 $node_0->setName('mrow');
\r
991 $node_1 = $this->createNode();
\r
992 $node_1->setName('mspace');
\r
993 $node_1->setAttr('width',$sym['space']);
\r
995 $node_2 = $this->createNode();
\r
996 $node_2->setName($sym['tag']);
\r
997 $node_2->setContent($sym['output']);
\r
999 $node_3 = $this->createNode();
\r
1000 $node_3->setName('mspace');
\r
1001 $node_3->setAttr('width',$sym['space']);
\r
1003 $node_0->addChild($node_1);
\r
1004 $node_0->addChild($node_2);
\r
1005 $node_0->addChild($node_3);
\r
1011 $node_0 = $this->createNode();
\r
1012 $node_0->setName($sym['tag']);
\r
1013 $node_0->setContent($sym['output']);
\r
1017 // Return an empty node
\r
1018 return $this->emptyNode();
\r
1021 function getMathML()
\r
1023 $root = $this->_node_arr[0];
\r
1024 return($root->dumpXML());
\r
1027 function getCurrExpr()
\r
1029 return($this->_curr_expr);
\r
1032 function setCurrExpr($str)
\r
1034 $this->_curr_expr = $str;
\r
1037 function getExpr()
\r
1039 return($this->_expr);
\r
1042 function getPrevExpr()
\r
1044 return($this->_prev_expr);
\r
1047 function createNode()
\r
1049 $node = new MathMLNode($this->_node_cntr);
\r
1050 // $node->setNamespaceAlias('m');
\r
1051 $this->_node_arr[$this->_node_cntr] = $node;
\r
1052 $this->_node_cntr++;
\r
1057 * Gets the largest symbol in the expression (greedy). Changed from non-greedy 26-Apr-2006
\r
1059 * @parameter boolean[optional] Chop original string?
\r
1065 function getSymbol($chop_flg = FALSE)
\r
1067 // Implemented a reverse symbol matcher.
\r
1068 // Instead of going front to back, it goes back to front. Steven 26-Apr-2006
\r
1069 $chr_cnt = strlen($this->_curr_expr);
\r
1071 if ($chr_cnt == 0) return FALSE;
\r
1073 for ($i = $chr_cnt; $i > 0; $i--) {
\r
1074 $sym_0 = substr($this->_curr_expr,0,$i);
\r
1076 // Reading string for numeric values
\r
1077 if (is_numeric($sym_0)) {
\r
1079 if ($chop_flg) $this->chopExpr($i);
\r
1080 return array('input'=>$sym_0, 'tag'=>'mn', 'output'=>$sym_0, 'symlen'=>$i);
\r
1082 } elseif (isset($this->_symbol_arr[$sym_0])) {
\r
1084 if ($chop_flg) $this->chopExpr($i);
\r
1085 $sym_arr = $this->_symbol_arr[$sym_0];
\r
1086 $sym_arr['symlen'] = $i;
\r
1091 // Reading string for alphabetic constants and the minus sign
\r
1092 $char = $this->_curr_expr{0};
\r
1093 $len_left = $chop_flg ? $this->chopExpr(1) : strlen($this->_curr_expr)-1;
\r
1095 // Deals with expressions of length 1
\r
1096 if ($len_left == 0 && isset($this->_symbol_arr[$char])) {
\r
1097 $sym_arr = $this->_symbol_arr[$char];
\r
1098 $sym_arr['symlen'] = 1;
\r
1101 $tag = preg_match('/[a-z]/i',$char) ? 'mi' : 'mo';
\r
1102 return array('input'=>$char, 'tag'=>$tag, 'output'=>$char, 'symlen'=>1);
\r
1106 function chopExpr($strlen)
\r
1108 $this->_prev_expr = $this->_curr_expr;
\r
1110 if ($strlen == strlen($this->_curr_expr)) {
\r
1111 $this->_curr_expr = '';
\r
1114 $this->_curr_expr = ltrim(substr($this->_curr_expr,$strlen));
\r
1115 return(strlen($this->_curr_expr));
\r