[DOC-CVS] [phd] master: Support MathML (mml:*) elements for XHTML rendering (#236)
[email protected] (Louis-Arnaud via GitHub)
| Newsgroups | php.doc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Louis-Arnaud (lacatoire)
Committer: GitHub (web-flow)
Pusher: Girgias
Date: 2026-02-05T17:04:33Z
Commit: https://github.com/php/phd/commit/61ad3e7cb0631a16ca603837c2213951f62d11ec
Raw diff: https://github.com/php/phd/commit/61ad3e7cb0631a16ca603837c2213951f62d11ec.diff
Support MathML (mml:*) elements for XHTML rendering (#236)
Closes #172
Changed paths:
A tests/package/php/data/mathml_rendering.xml
A tests/package/php/mathml_rendering.phpt
M phpdotnet/phd/Package/Generic/XHTML.php
M phpdotnet/phd/Reader.php
Diff:
diff --git a/phpdotnet/phd/Package/Generic/XHTML.php b/phpdotnet/phd/Package/Generic/XHTML.php
index 156c5d03..52433334 100644
--- a/phpdotnet/phd/Package/Generic/XHTML.php
+++ b/phpdotnet/phd/Package/Generic/XHTML.php
@@ -392,6 +392,48 @@ abstract class Package_Generic_XHTML extends Format_Abstract_XHTML {
//phd
'phd:toc' => 'format_phd_toc',
+ // MathML (namespace http://www.w3.org/1998/Math/MathML)
+ 'mml:math' => 'format_mml_element',
+ // Token
+ 'mml:mi' => 'format_mml_element',
+ 'mml:mn' => 'format_mml_element',
+ 'mml:mo' => 'format_mml_element',
+ 'mml:mtext' => 'format_mml_element',
+ 'mml:mspace' => 'format_mml_element',
+ 'mml:ms' => 'format_mml_element',
+ // Layout
+ 'mml:mrow' => 'format_mml_element',
+ 'mml:mfrac' => 'format_mml_element',
+ 'mml:msqrt' => 'format_mml_element',
+ 'mml:mroot' => 'format_mml_element',
+ 'mml:mstyle' => 'format_mml_element',
+ 'mml:merror' => 'format_mml_element',
+ 'mml:mpadded' => 'format_mml_element',
+ 'mml:mphantom' => 'format_mml_element',
+ 'mml:mfenced' => 'format_mml_element',
+ 'mml:menclose' => 'format_mml_element',
+ // Scripts and limits
+ 'mml:msub' => 'format_mml_element',
+ 'mml:msup' => 'format_mml_element',
+ 'mml:msubsup' => 'format_mml_element',
+ 'mml:munder' => 'format_mml_element',
+ 'mml:mover' => 'format_mml_element',
+ 'mml:munderover' => 'format_mml_element',
+ 'mml:mmultiscripts' => 'format_mml_element',
+ 'mml:mprescripts' => 'format_mml_element',
+ 'mml:none' => 'format_mml_element',
+ // Tables
+ 'mml:mtable' => 'format_mml_element',
+ 'mml:mtr' => 'format_mml_element',
+ 'mml:mtd' => 'format_mml_element',
+ 'mml:mlabeledtr' => 'format_mml_element',
+ // Semantics
+ 'mml:semantics' => 'format_mml_element',
+ 'mml:annotation' => 'format_mml_element',
+ 'mml:annotation-xml' => 'format_mml_element',
+ // Actions
+ 'mml:maction' => 'format_mml_element',
+
); /* }}} */
private $mytextmap = array(
@@ -631,6 +673,37 @@ function format_phd_toc($open, $name, $attrs, $props) {
) . "</div>\n";
}
+ /**
+ * Handle MathML elements (mml:* namespace).
+ * Strips the "mml:" prefix and outputs the HTML5 local name.
+ */
+ public function format_mml_element($open, $name, $attrs, $props) {
+ $localName = substr($name, 4);
+
+ if ($open) {
+ $attrStr = '';
+
+ // Add xmlns on the <math> root element for XHTML compatibility
+ if ($localName === 'math') {
+ $attrStr .= ' xmlns="' . Reader::XMLNS_MATHML . '"';
+ }
+
+ // Preserve MathML attributes (stored under XMLNS_DOCBOOK as they have no namespace)
+ foreach ($attrs[Reader::XMLNS_DOCBOOK] as $attr => $val) {
+ $attrStr .= ' ' . $attr . '="' . $this->TEXT($val) . '"';
+ }
+
+ // Preserve xml:id as id
+ if (isset($attrs[Reader::XMLNS_XML]["id"])) {
+ $attrStr .= ' id="' . $attrs[Reader::XMLNS_XML]["id"] . '"';
+ }
+
+ return '<' . $localName . $attrStr . ($props["empty"] ? '/>' : '>');
+ }
+
+ return '</' . $localName . '>';
+ }
+
public function createLink($for, &$desc = null, $type = Format::SDESC) {
$retval = null;
if (isset($this->indexes[$for])) {
diff --git a/phpdotnet/phd/Reader.php b/phpdotnet/phd/Reader.php
index 796a2d71..47240f14 100644
--- a/phpdotnet/phd/Reader.php
+++ b/phpdotnet/phd/Reader.php
@@ -7,6 +7,7 @@ class Reader extends \XMLReader
const XMLNS_XLINK = "http://www.w3.org/1999/xlink";
const XMLNS_PHD = "http://www.php.net/ns/phd";
const XMLNS_DOCBOOK = "http://docbook.org/ns/docbook";
+ const XMLNS_MATHML = "http://www.w3.org/1998/Math/MathML";
protected OutputHandler $outputHandler;
diff --git a/tests/package/php/data/mathml_rendering.xml b/tests/package/php/data/mathml_rendering.xml
new file mode 100644
index 00000000..c32c7dfe
--- /dev/null
+++ b/tests/package/php/data/mathml_rendering.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<chapter xml:id="mathml_rendering" xmlns="http://docbook.org/ns/docbook" xmlns:mml="http://www.w3.org/1998/Math/MathML">
+
+ <section>
+ <para>1. Inline MathML equation</para>
+ <para>
+ The quadratic formula is
+ <mml:math display="inline"><mml:mi>x</mml:mi><mml:mo>=</mml:mo><mml:mfrac><mml:mrow><mml:mo>-</mml:mo><mml:mi>b</mml:mi><mml:mo>±</mml:mo><mml:msqrt><mml:mrow><mml:msup><mml:mi>b</mml:mi><mml:mn>2</mml:mn></mml:msup><mml:mo>-</mml:mo><mml:mn>4</mml:mn><mml:mi>a</mml:mi><mml:mi>c</mml:mi></mml:mrow></mml:msqrt></mml:mrow><mml:mrow><mml:mn>2</mml:mn><mml:mi>a</mml:mi></mml:mrow></mml:mfrac></mml:math>.
+ </para>
+ </section>
+
+ <section>
+ <para>2. Self-closing mspace element</para>
+ <para>
+ <mml:math><mml:mi>a</mml:mi><mml:mspace width="1em"/><mml:mi>b</mml:mi></mml:math>
+ </para>
+ </section>
+
+ <section>
+ <para>3. Element with mathvariant attribute</para>
+ <para>
+ <mml:math><mml:mi mathvariant="bold">x</mml:mi></mml:math>
+ </para>
+ </section>
+
+</chapter>
diff --git a/tests/package/php/mathml_rendering.phpt b/tests/package/php/mathml_rendering.phpt
new file mode 100644
index 00000000..f755da39
--- /dev/null
+++ b/tests/package/php/mathml_rendering.phpt
@@ -0,0 +1,46 @@
+--TEST--
+MathML rendering
+--FILE--
+<?php
+namespace phpdotnet\phd;
+
+require_once __DIR__ . "/../../setup.php";
+
+$xmlFile = __DIR__ . "/data/mathml_rendering.xml";
+
+$config->xmlFile = $xmlFile;
+
+$format = new TestPHPChunkedXHTML($config, $outputHandler);
+
+$render = new TestRender(new Reader($outputHandler), $config, $format);
+
+$render->run();
+?>
+--EXPECT--
+Filename: mathml_rendering.html
+Content:
+<div id="mathml_rendering" class="chapter">
+
+ <div class="section">
+ <p class="para">1. Inline MathML equation</p>
+ <p class="para">
+ The quadratic formula is
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mi>x</mi><mo>=</mo><mfrac><mrow><mo>-</mo><mi>b</mi><mo>±</mo><msqrt><mrow><msup><mi>b</mi><mn>2</mn></msup><mo>-</mo><mn>4</mn><mi>a</mi><mi>c</mi></mrow></msqrt></mrow><mrow><mn>2</mn><mi>a</mi></mrow></mfrac></math>.
+ </p>
+ </div>
+
+ <div class="section">
+ <p class="para">2. Self-closing mspace element</p>
+ <p class="para">
+ <math xmlns="http://www.w3.org/1998/Math/MathML"><mi>a</mi><mspace width="1em"/><mi>b</mi></math>
+ </p>
+ </div>
+
+ <div class="section">
+ <p class="para">3. Element with mathvariant attribute</p>
+ <p class="para">
+ <math xmlns="http://www.w3.org/1998/Math/MathML"><mi mathvariant="bold">x</mi></math>
+ </p>
+ </div>
+
+</div>