This commit is contained in:
wangjinlei
2024-07-17 09:23:45 +08:00
parent edf9deeb1a
commit 881ac3e056
1001 changed files with 41032 additions and 5452 deletions

View File

@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@@ -0,0 +1,52 @@
name: Deploy
on:
push:
branches:
- master
pull_request:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
### MkDocs
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Install Python Dependencies
run: pip install mkdocs-material autolink-references-mkdocs-plugin
- name: Build documentation
run: mkdocs build --site-dir public
### PHPUnit
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.2
extensions: dom, xml
coverage: xdebug
- name: Create directory public/coverage
run: mkdir ./public/coverage
- name: Install PHP Dependencies
run: composer install --ansi --prefer-dist --no-interaction --no-progress
- name: Build Coverage Report
run: XDEBUG_MODE=coverage ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./public/coverage
### PHPDoc
- name: Create directory public/docs
run: mkdir ./public/docs
- name: Install PhpDocumentor
## Support PHP 7.2
run: wget https://github.com/phpDocumentor/phpDocumentor/releases/download/v3.0.0/phpDocumentor.phar && chmod +x phpDocumentor.phar
- name: Build Documentation
run: ./phpDocumentor.phar run -d ./src -t ./public/docs
### Deploy
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/master'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public

View File

@@ -0,0 +1,106 @@
name: PHP
on:
push:
branches:
- master
pull_request:
jobs:
php-cs-fixer:
name: PHP CS Fixer
runs-on: ubuntu-latest
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
extensions: xml
- uses: actions/checkout@v4
- name: Validate composer config
run: composer validate --strict
- name: Composer Install
run: composer global require friendsofphp/php-cs-fixer
- name: Add environment path
run: export PATH="$PATH:$HOME/.composer/vendor/bin"
- name: Run PHPCSFixer
run: php-cs-fixer fix --dry-run --diff
phpstan:
name: PHP Static Analysis
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php:
- '7.1'
- '7.2'
- '7.3'
- '7.4'
- '8.0'
- '8.1'
- '8.2'
- '8.3'
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: xml
- uses: actions/checkout@v4
- name: Composer Install
run: composer install --ansi --prefer-dist --no-interaction --no-progress
- name: Run phpstan
run: ./vendor/bin/phpstan analyse -c phpstan.neon.dist
phpunit:
name: PHPUnit
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php:
- '7.1'
- '7.2'
- '7.3'
- '7.4'
- '8.0'
- '8.1'
- '8.2'
- '8.3'
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: xml
coverage: ${{ (matrix.php == '8.1') && 'xdebug' || 'none' }}
- uses: actions/checkout@v4
- name: Install dependencies
run: composer install --ansi --prefer-dist --no-interaction --no-progress
- name: Run PHPUnit
if: matrix.php != '8.1'
run: ./vendor/bin/phpunit -c phpunit.xml.dist
- name: Run PHPUnit (w CodeCoverage)
if: matrix.php == '8.1'
run: XDEBUG_MODE=coverage ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml
- name: Upload coverage results to Coveralls
if: matrix.php == '8.1'
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar
chmod +x php-coveralls.phar
php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv

9
vendor/phpoffice/math/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
.php_cs.cache
.php-cs-fixer.cache
.phpunit.cache
.phpunit.result.cache
composer.lock
phpDocumentor.phar
public/
vendor/

View File

@@ -0,0 +1,45 @@
<?php
$config = new PhpCsFixer\Config();
$config
->setUsingCache(true)
->setRiskyAllowed(true)
->setRules([
'@Symfony' => true,
'array_indentation' => true,
'cast_spaces' => [
'space' => 'single',
],
'combine_consecutive_issets' => true,
'concat_space' => [
'spacing' => 'one',
],
'error_suppression' => [
'mute_deprecation_error' => false,
'noise_remaining_usages' => false,
'noise_remaining_usages_exclude' => [],
],
'function_to_constant' => false,
'global_namespace_import' => true,
'method_chaining_indentation' => true,
'no_alias_functions' => false,
'no_superfluous_phpdoc_tags' => false,
'non_printable_character' => [
'use_escape_sequences_in_strings' => true,
],
'phpdoc_align' => [
'align' => 'left',
],
'phpdoc_summary' => false,
'protected_to_private' => false,
'self_accessor' => false,
'yoda_style' => false,
'single_line_throw' => false,
'no_alias_language_construct_call' => false,
])
->getFinder()
->in(__DIR__)
->exclude('vendor');
return $config;

21
vendor/phpoffice/math/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 PhpSpreadsheet Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

75
vendor/phpoffice/math/README.md vendored Normal file
View File

@@ -0,0 +1,75 @@
# Math
[![Latest Stable Version](https://poser.pugx.org/phpoffice/math/v/stable.png)](https://packagist.org/packages/phpoffice/math)
[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/Math/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/Math?branch=master)
[![Total Downloads](https://poser.pugx.org/phpoffice/math/downloads.png)](https://packagist.org/packages/phpoffice/math)
[![License](https://poser.pugx.org/phpoffice/math/license.png)](https://packagist.org/packages/phpoffice/math)
[![CI](https://github.com/PHPOffice/Math/actions/workflows/php.yml/badge.svg)](https://github.com/PHPOffice/Math/actions/workflows/php.yml)
Math is a library written in pure PHP that provides a set of classes to manipulate different formula file formats, i.e. [MathML](https://en.wikipedia.org/wiki/MathML) and [Office MathML (OOML)](https://en.wikipedia.org/wiki/Office_Open_XML_file_formats#Office_MathML_(OMML)).
Math is an open source project licensed under the terms of [MIT](https://github.com/PHPOffice/Math/blob/master/LICENCE). Math is aimed to be a high quality software product by incorporating [continuous integration and unit testing](https://github.com/PHPOffice/Math/actions/workflows/php.yml). You can learn more about Math by reading this Developers'Documentation and the [API Documentation](http://phpoffice.github.io/Math/docs/)
If you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpoffice-math)
Read more about Math:
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Contributing](#contributing)
- [Developers' Documentation](https://phpoffice.github.io/Math/)
## Features
- Insert elements:
* Basic :
* Identifier : <math display="inline"><mi>a</mi></math>
* Operator : <math display="inline"><mo>+</mo></math>
* Numeric : <math display="inline"><mn>2</mn></math>
* Simple :
* Fraction : <math display="inline"><mfrac><mi>a</mi><mn>3</mn></mfrac></math>
* Superscript : <math display="inline"><msup><mi>a</mi><mn>3</mn></msup></math>
* Architectural :
* Row
* Semantics
- Support
* MathML
* OfficeMathML
## Requirements
Math requires the following:
- PHP 7.1+
- [XML Parser extension](http://www.php.net/manual/en/xml.installation.php)
- [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php)
## Installation
Math is installed via [Composer](https://getcomposer.org/).
To [add a dependency](https://getcomposer.org/doc/04-schema.md#package-links) to Math in your project, either
Run the following to use the latest stable version
```sh
composer require phpoffice/math
```
or if you want the latest unreleased version
```sh
composer require phpoffice/math:dev-master
```
## Contributing
We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute.
- [Fork us](https://github.com/PHPOffice/Math/fork) and [request a pull](https://github.com/PHPOffice/Math/pulls) to the [master](https://github.com/PHPOffice/Math/tree/master) branch.
- Submit [bug reports or feature requests](https://github.com/PHPOffice/Math/issues) to GitHub.
- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter.

29
vendor/phpoffice/math/composer.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"name": "phpoffice/math",
"description": "Math - Manipulate Math Formula",
"keywords": ["PHP","mathml", "officemathml"],
"homepage": "https://phpoffice.github.io/Math/",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {
"PhpOffice\\Math\\": "src/Math/",
"Tests\\PhpOffice\\Math\\": "tests/Math/"
}
},
"authors": [
{
"name": "Progi1984",
"homepage": "https://lefevre.dev"
}
],
"require": {
"php": "^7.1|^8.0",
"ext-dom": "*",
"ext-xml": "*"
},
"require-dev": {
"phpunit/phpunit": "^7.0 || ^9.0",
"phpstan/phpstan": "^0.12.88 || ^1.0.0"
}
}

View File

@@ -0,0 +1,17 @@
window.MathJax = {
tex: {
inlineMath: [["\\(", "\\)"]],
displayMath: [["\\[", "\\]"]],
processEscapes: true,
processEnvironments: true
},
options: {
ignoreHtmlClass: ".*|",
processHtmlClass: "arithmatex"
}
};
document$.subscribe(() => {
MathJax.typesetPromise()
})

View File

@@ -0,0 +1,19 @@
# 0.1.0
## Enhancements
- Initial version by [@Progi1984](https://github/Progi1984)
- MathML Reader : Support for Semantics by [@Progi1984](https://github/Progi1984) in [#4](https://github.com/PHPOffice/Math/pull/4)
- PHPUnit : Improved Unit Tests by [@Progi1984](https://github/Progi1984) in [#8](https://github.com/PHPOffice/Math/pull/8)
## Bug fixes
- N/A
## Miscellaneous
- Github Actions : PHPCSFixer by [@Progi1984](https://github/Progi1984) in [#1](https://github.com/PHPOffice/Math/pull/1)
- Github Actions : PHPStan by [@Progi1984](https://github/Progi1984) in [#2](https://github.com/PHPOffice/Math/pull/2)
- Removed dependency friendsofphp/php-cs-fixer by [@Progi1984](https://github/Progi1984) in [#3](https://github.com/PHPOffice/Math/pull/3)
- Github Actions : Dependabot by [@Progi1984](https://github/Progi1984) in [#5](https://github.com/PHPOffice/Math/pull/5)
- Bump actions/checkout from 2 to 4 by [@dependabot](https://github/dependabot) in [#6](https://github.com/PHPOffice/Math/pull/6)
- Added documentation (MkDocs / Coverage / PHPDoc) by [@Progi1984](https://github/Progi1984) in [#7](https://github.com/PHPOffice/Math/pull/7)

8
vendor/phpoffice/math/docs/credits.md vendored Normal file
View File

@@ -0,0 +1,8 @@
## References
### MathML
- [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/MathML)
### OfficeMathML

59
vendor/phpoffice/math/docs/index.md vendored Normal file
View File

@@ -0,0 +1,59 @@
#
Math is a library written in pure PHP that provides a set of classes to manipulate different formula file formats, i.e. [MathML](https://en.wikipedia.org/wiki/MathML) and [Office MathML (OOML)](https://en.wikipedia.org/wiki/Office_Open_XML_file_formats#Office_MathML_(OMML)).
Math is an open source project licensed under the terms of [MIT](https://github.com/PHPOffice/Math/blob/master/LICENCE). Math is aimed to be a high quality software product by incorporating [continuous integration and unit testing](https://github.com/PHPOffice/Math/actions/workflows/php.yml). You can learn more about Math by reading this Developers'Documentation and the [API Documentation](http://phpoffice.github.io/Math/docs/develop/)
## Features
- Insert elements:
* Basic :
* Identifier : <math display="inline"><mi>a</mi></math>
* Operator : <math display="inline"><mo>+</mo></math>
* Numeric : <math display="inline"><mn>2</mn></math>
* Simple :
* Fraction : <math display="inline"><mfrac><mi>a</mi><mn>3</mn></mfrac></math>
* Superscript : <math display="inline"><msup><mi>a</mi><mn>3</mn></msup></math>
* Architectural :
* Row
* Semantics
## Support
### Readers
| Features | | MathML | Office MathML |
|---------------------------|----------------------|:----------------:|:----------------:|
| **Basic** | Identifier | :material-check: | :material-check: |
| | Operator | :material-check: | :material-check: |
| | Numeric | :material-check: | :material-check: |
| **Simple** | Fraction | :material-check: | :material-check: |
| | Superscript | :material-check: | |
| **Architectural** | Row | :material-check: | |
| | Semantics | :material-check: | |
### Writers
| Features | | MathML | Office MathML |
|---------------------------|----------------------|:----------------:|:----------------:|
| **Basic** | Identifier | :material-check: | :material-check: |
| | Operator | :material-check: | :material-check: |
| | Numeric | :material-check: | :material-check: |
| **Simple** | Fraction | :material-check: | :material-check: |
| | Superscript | :material-check: | |
| **Architectural** | Row | :material-check: | :material-check: |
| | Semantics | | |
## Contributing
We welcome everyone to contribute to Math. Below are some of the things that you can do to contribute:
- [Fork us](https://github.com/PHPOffice/Math/fork) and [request a pull](https://github.com/PHPOffice/Math/pulls) to the [master](https://github.com/PHPOffice/Math/tree/master) branch
- Submit [bug reports or feature requests](https://github.com/PHPOffice/Math/issues) to GitHub
- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter

25
vendor/phpoffice/math/docs/install.md vendored Normal file
View File

@@ -0,0 +1,25 @@
# Installation
## Requirements
Mandatory:
- PHP 7.1+
- PHP [DOM extension](http://php.net/manual/en/book.dom.php)
- PHP [XML Parser extension](http://www.php.net/manual/en/xml.installation.php)
- PHP [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php)
## Installation
### Using Composer
To install via [Composer](http://getcomposer.org), add the following lines to your `composer.json`:
``` json
{
"require": {
"phpoffice/math": "dev-master"
}
}
```

View File

@@ -0,0 +1,61 @@
## Usage
To create a fraction, use the `PhpOffice\Math\Element\Fraction` class.
### Methods
#### getDenominator
The method has no parameter.
#### getNumerator
The method has no parameter.
#### setDenominator
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
#### setNumerator
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
## Example
### Math
<math display="block">
<mfrac>
<mi>a</mi>
<mn>3</mn>
</mfrac>
</math>
### XML
``` xml
<math display="block">
<mfrac>
<mi>a</mi>
<mn>3</mn>
</mfrac>
</math>
```
### PHP
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
$math = new Math();
$fraction = new Element\Fraction();
$fraction->setDenominator(new Element\Identifier('a'));
$fraction->setNumerator(new Element\Numeric(3));
$math->add($fraction);
```

View File

@@ -0,0 +1,43 @@
## Usage
To create an identifier, use the `PhpOffice\Math\Element\Identifier` class.
### Methods
#### getValue
The method has no parameter.
#### setValue
The method has one parameter :
* `string` **$value**
## Example
### Math
<math display="block">
<mi>a</mi>
</math>
### XML
``` xml
<math display="block">
<mi>a</mi>
</math>
```
### PHP
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
$math = new Math();
$identifier = new Element\Identifier('a');
$math->add($identifier);
```

View File

@@ -0,0 +1,43 @@
## Usage
To create a numeric, use the `PhpOffice\Math\Element\Numeric` class.
### Methods
#### getValue
The method has no parameter.
#### setValue
The method has one parameter :
* `float` **$value**
## Example
### Math
<math display="block">
<mn>3</mn>
</math>
### XML
``` xml
<math display="block">
<mn>3</mn>
</math>
```
### PHP
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
$math = new Math();
$identifier = new Element\Numeric(3);
$math->add($identifier);
```

View File

@@ -0,0 +1,43 @@
## Usage
To create an operator, use the `PhpOffice\Math\Element\Operator` class.
### Methods
#### getValue
The method has no parameter.
#### setValue
The method has one parameter :
* `string` **$value**
## Example
### Math
<math display="block">
<mo>+</mo>
</math>
### XML
``` xml
<math display="block">
<mo>+</mo>
</math>
```
### PHP
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
$math = new Math();
$identifier = new Element\Operator('+');
$math->add($identifier);
```

View File

@@ -0,0 +1,62 @@
## Usage
To create a row, use the `PhpOffice\Math\Element\Row` class.
### Methods
#### add
The method add an element to the row.
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
#### getElements
The method return all elements of the row.
#### remove
The method remove an element to the row.
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
## Example
### Math
<math display="block">
<mrow>
<mn>1</mn>
<mo>+</mo>
<mi>K</mi>
</mrow>
</math>
### XML
``` xml
<math display="block">
<mrow>
<mn>1</mn>
<mo>+</mo>
<mi>K</mi>
</mrow>
</math>
```
### PHP
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
$math = new Math();
$row = new Element\Row();
$row->add(new Element\Numeric(1));
$row->add(new Element\Operator('+'));
$row->add(new Element\Identifier('K'));
$math->add($row);
```

View File

@@ -0,0 +1,81 @@
## Usage
To create a semantics, use the `PhpOffice\Math\Element\Semantics` class.
### Methods
#### add
The method add an element to the `semantics` element.
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
#### addAnnotation
The method add an annotation to the `semantics` element.
The method has two parameters :
* `string` **$encoding**
* `string` **$annotation**
#### getAnnotation
The method return an annotation based on its encoding.
The method has one parameter :
* `string` **$encoding**
#### getAnnotations
The method return alls annotation of the `semantics` element.
The method has no parameter.
#### getElements
The method return all elements of the `semantics` element.
#### remove
The method remove an element to the `semantics` element.
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
## Example
### Math
<math display="block">
<semantics>
<mi>y</mi>
<annotation encoding="application/x-tex"> y </annotation>
</semantics>
</math>
### XML
``` xml
<math display="block">
<semantics>
<mi>y</mi>
<annotation encoding="application/x-tex"> y </annotation>
</semantics>
</math>
```
### PHP
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
$math = new Math();
$semantics = new Element\Semantics();
$semantics->add(new Element\Identifier('y'));
$semantics->addAnnotation('application/x-tex', ' y ');
$math->add($semantics);
```

View File

@@ -0,0 +1,61 @@
## Usage
To attach a superscript to an expression, use the `PhpOffice\Math\Element\Superscript` class.
### Methods
#### getBase
The method has no parameter.
#### getSuperscript
The method has no parameter.
#### setBase
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
#### setSuperscript
The method has one parameter :
* `PhpOffice\Math\Element\AbstractElement` **$element**
## Example
### Math
<math display="block">
<msup>
<mi>X</mi>
<mn>2</mn>
</msup>
</math>
### XML
``` xml
<math display="block">
<msup>
<mi>X</mi>
<mn>2</mn>
</msup>
</math>
```
### PHP
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
$math = new Math();
$superscript = new Element\Superscript();
$superscript->setBase(new Element\Identifier('X'));
$superscript->setSuperscript(new Element\Numeric(2));
$math->add($superscript);
```

View File

@@ -0,0 +1,50 @@
## Readers
### MathML
The name of the reader is `MathML`.
``` php
<?php
use PhpOffice\Math\Reader\MathML;
$reader = new MathML();
$math = $reader->read(
'<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mi> a </mi>
</math>'
);
```
### OfficeMathML
The name of the reader is `OfficeMathML`.
``` php
<?php
use PhpOffice\Math\Reader\OfficeMathML;
$reader = new OfficeMathML();
$math = $reader->read(
'<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:oMath>
<m:f>
<m:num><m:r><m:t>π</m:t></m:r></m:num>
<m:den><m:r><m:t>2</m:t></m:r></m:den>
</m:f>
</m:oMath>
</m:oMathPara>'
);
```
## Methods
### read
The method has one parameter :
* `string` **$content**
The method returns a `PhpOffice\Math\Math` object.

View File

@@ -0,0 +1,46 @@
## Writers
### MathML
The name of the writer is `MathML`.
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
use PhpOffice\Math\Writer\MathML;
$math = new Math();
$math->add(new Element\Operator('+'));
$writer = new MathML();
$output = $writer->write($math);
```
### OfficeMathML
The name of the writer is `OfficeMathML`.
``` php
<?php
use PhpOffice\Math\Element;
use PhpOffice\Math\Math;
use PhpOffice\Math\Writer\OfficeMathML;
$math = new Math();
$math->add(new Element\Operator('+'));
$writer = new OfficeMathML();
$output = $writer->write($math);
```
## Methods
### writer
The method has one parameter :
* `PhpOffice\Math\Math` **$math**
The method returns a `string`.

64
vendor/phpoffice/math/mkdocs.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
site_name: Math
site_url: https://phpoffice.github.io/Math
repo_url: https://github.com/PHPOffice/Math
repo_name: PHPOffice/Math
edit_uri: edit/master/docs/
## Theme
theme:
name: material
palette:
primary: grey
features:
- search.highlight
- search.suggest
## Plugins
plugins:
- search
## Config
extra:
generator: false
extra_javascript:
- assets/mathjax.js
- https://polyfill.io/v3/polyfill.min.js?features=es6
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
markdown_extensions:
## Syntax highlighting
- pymdownx.highlight
- pymdownx.superfences
## Support for Math
- pymdownx.arithmatex:
generic: true
## Support for emojis
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
## Support for call-outs
- admonition
- pymdownx.details
use_directory_urls: false
## Navigation
nav:
- Introduction: 'index.md'
- Install: 'install.md'
- Usage:
- Elements:
- Fraction: 'usage/elements/fraction.md'
- Identifier: 'usage/elements/identifier.md'
- Numeric: 'usage/elements/numeric.md'
- Operator: 'usage/elements/operator.md'
- Row: 'usage/elements/row.md'
- Semantics: 'usage/elements/semantics.md'
- Superscript: 'usage/elements/superscript.md'
- Readers: 'usage/readers.md'
- Writers: 'usage/writers.md'
- Credits: 'credits.md'
- Releases:
- '0.1.0 (WIP)': 'changes/0.1.0.md'
- Developers:
- 'Coveralls': 'https://coveralls.io/github/PHPOffice/Math'
- 'Code Coverage': 'coverage/index.html'
- 'PHPDoc': 'docs/index.html'

12
vendor/phpoffice/math/phpstan.neon.dist vendored Normal file
View File

@@ -0,0 +1,12 @@
parameters:
level: 7
bootstrapFiles:
- vendor/autoload.php
paths:
- src
- tests
reportUnmatchedIgnoredErrors: false
ignoreErrors:
## Remove after remove ArrayObject
treatPhpDocTypesAsCertain: false

29
vendor/phpoffice/math/phpunit.xml.dist vendored Normal file
View File

@@ -0,0 +1,29 @@
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="./vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="PhpOffice\Math Test Suite">
<directory>./tests/Math</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="./build/coverage" />
<log type="coverage-clover" target="./build/clover.xml" />
</logging>
<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>

View File

@@ -0,0 +1,7 @@
<?php
namespace PhpOffice\Math\Element;
abstract class AbstractElement
{
}

View File

@@ -0,0 +1,35 @@
<?php
namespace PhpOffice\Math\Element;
abstract class AbstractGroupElement extends AbstractElement
{
/**
* @var AbstractElement[]
*/
protected $elements = [];
public function add(AbstractElement $element): self
{
$this->elements[] = $element;
return $this;
}
public function remove(AbstractElement $element): self
{
$this->elements = array_filter($this->elements, function ($child) use ($element) {
return $child != $element;
});
return $this;
}
/**
* @return AbstractElement[]
*/
public function getElements(): array
{
return $this->elements;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace PhpOffice\Math\Element;
class Fraction extends AbstractElement
{
/**
* @var AbstractElement
*/
protected $denominator;
/**
* @var AbstractElement
*/
protected $numerator;
public function __construct(AbstractElement $numerator, AbstractElement $denominator)
{
$this->setNumerator($numerator);
$this->setDenominator($denominator);
}
public function getDenominator(): AbstractElement
{
return $this->denominator;
}
public function getNumerator(): AbstractElement
{
return $this->numerator;
}
public function setDenominator(AbstractElement $element): self
{
$this->denominator = $element;
return $this;
}
public function setNumerator(AbstractElement $element): self
{
$this->numerator = $element;
return $this;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PhpOffice\Math\Element;
class Identifier extends AbstractElement
{
/**
* @var string
*/
protected $value;
public function __construct(string $value)
{
$this->value = $value;
}
public function getValue(): string
{
return $this->value;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PhpOffice\Math\Element;
class Numeric extends AbstractElement
{
/**
* @var float
*/
protected $value;
public function __construct(float $value)
{
$this->value = $value;
}
public function getValue(): float
{
return $this->value;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PhpOffice\Math\Element;
class Operator extends AbstractElement
{
/**
* @var string
*/
protected $value;
public function __construct(string $value)
{
$this->value = $value;
}
public function getValue(): string
{
return $this->value;
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace PhpOffice\Math\Element;
class Row extends AbstractGroupElement
{
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace PhpOffice\Math\Element;
class Semantics extends AbstractGroupElement
{
/**
* @var array<string, string>
*/
protected $annotations = [];
public function addAnnotation(string $encoding, string $annotation): self
{
$this->annotations[$encoding] = $annotation;
return $this;
}
public function getAnnotation(string $encoding): ?string
{
return $this->annotations[$encoding] ?? null;
}
/**
* @return array<string, string>
*/
public function getAnnotations(): array
{
return $this->annotations;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace PhpOffice\Math\Element;
class Superscript extends AbstractElement
{
/**
* @var AbstractElement
*/
protected $base;
/**
* @var AbstractElement
*/
protected $superscript;
public function __construct(AbstractElement $base, AbstractElement $superscript)
{
$this->setBase($base);
$this->setSuperscript($superscript);
}
public function getBase(): AbstractElement
{
return $this->base;
}
public function getSuperscript(): AbstractElement
{
return $this->superscript;
}
public function setBase(AbstractElement $element): self
{
$this->base = $element;
return $this;
}
public function setSuperscript(AbstractElement $element): self
{
$this->superscript = $element;
return $this;
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace PhpOffice\Math\Exception;
class InvalidInputException extends MathException
{
}

View File

@@ -0,0 +1,9 @@
<?php
namespace PhpOffice\Math\Exception;
use Exception;
class MathException extends Exception
{
}

View File

@@ -0,0 +1,7 @@
<?php
namespace PhpOffice\Math\Exception;
class NotImplementedException extends MathException
{
}

View File

@@ -0,0 +1,9 @@
<?php
namespace PhpOffice\Math;
use PhpOffice\Math\Element\AbstractGroupElement;
class Math extends AbstractGroupElement
{
}

View File

@@ -0,0 +1,136 @@
<?php
namespace PhpOffice\Math\Reader;
use DOMDocument;
use DOMElement;
use DOMNode;
use DOMXPath;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\InvalidInputException;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
class MathML implements ReaderInterface
{
/** @var Math */
private $math;
/** @var DOMDocument */
private $dom;
/** @var DOMXpath */
private $xpath;
public function read(string $content): ?Math
{
$content = str_replace(
[
'&InvisibleTimes;',
],
[
'<mchar name="InvisibleTimes"/>',
],
$content
);
$this->dom = new DOMDocument();
$this->dom->loadXML($content, LIBXML_DTDLOAD);
$this->math = new Math();
$this->parseNode(null, $this->math);
return $this->math;
}
/**
* @param Math|Element\AbstractGroupElement $parent
*/
protected function parseNode(?DOMNode $nodeRowElement, $parent): void
{
$this->xpath = new DOMXpath($this->dom);
foreach ($this->xpath->query('*', $nodeRowElement) ?: [] as $nodeElement) {
if ($parent instanceof Element\Semantics
&& $nodeElement instanceof DOMElement
&& $nodeElement->nodeName == 'annotation') {
$parent->addAnnotation(
$nodeElement->getAttribute('encoding'),
trim($nodeElement->nodeValue)
);
continue;
}
$element = $this->getElement($nodeElement);
$parent->add($element);
if ($element instanceof Element\AbstractGroupElement) {
$this->parseNode($nodeElement, $element);
}
}
}
protected function getElement(DOMNode $nodeElement): Element\AbstractElement
{
$nodeValue = trim($nodeElement->nodeValue);
switch ($nodeElement->nodeName) {
case 'mfrac':
$nodeList = $this->xpath->query('*', $nodeElement);
if ($nodeList && $nodeList->length == 2) {
return new Element\Fraction(
$this->getElement($nodeList->item(0)),
$this->getElement($nodeList->item(1))
);
}
throw new InvalidInputException(sprintf(
'%s : The tag `%s` has not two subelements',
__METHOD__,
$nodeElement->nodeName
));
case 'mi':
return new Element\Identifier($nodeValue);
case 'mn':
return new Element\Numeric(floatval($nodeValue));
case 'mo':
if (empty($nodeValue)) {
$nodeList = $this->xpath->query('*', $nodeElement);
if (
$nodeList
&& $nodeList->length == 1
&& $nodeList->item(0)->nodeName == 'mchar'
&& $nodeList->item(0) instanceof DOMElement
&& $nodeList->item(0)->hasAttribute('name')
) {
$nodeValue = $nodeList->item(0)->getAttribute('name');
}
}
return new Element\Operator($nodeValue);
case 'mrow':
return new Element\Row();
case 'msup':
$nodeList = $this->xpath->query('*', $nodeElement);
if ($nodeList && $nodeList->length == 2) {
return new Element\Superscript(
$this->getElement($nodeList->item(0)),
$this->getElement($nodeList->item(1))
);
}
throw new InvalidInputException(sprintf(
'%s : The tag `%s` has not two subelements',
__METHOD__,
$nodeElement->nodeName
));
case 'semantics':
return new Element\Semantics();
default:
throw new NotImplementedException(sprintf(
'%s : The tag `%s` is not implemented',
__METHOD__,
$nodeElement->nodeName
));
}
}
}

View File

@@ -0,0 +1,133 @@
<?php
namespace PhpOffice\Math\Reader;
use DOMDocument;
use DOMNode;
use DOMXPath;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\InvalidInputException;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
class OfficeMathML implements ReaderInterface
{
/** @var DOMDocument */
protected $dom;
/** @var Math */
protected $math;
/** @var DOMXpath */
protected $xpath;
/** @var string[] */
protected $operators = ['+', '-', '/', ''];
public function read(string $content): ?Math
{
$nsMath = 'xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"';
$nsWord = 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"';
$content = str_replace(
$nsMath,
$nsMath . ' ' . $nsWord,
$content
);
$this->dom = new DOMDocument();
$this->dom->loadXML($content);
$this->math = new Math();
$this->parseNode(null, $this->math);
return $this->math;
}
/**
* @see https://devblogs.microsoft.com/math-in-office/officemath/
* @see https://learn.microsoft.com/fr-fr/archive/blogs/murrays/mathml-and-ecma-math-omml
*
* @param Math|Element\AbstractGroupElement $parent
*/
protected function parseNode(?DOMNode $nodeRowElement, $parent): void
{
$this->xpath = new DOMXpath($this->dom);
foreach ($this->xpath->query('*', $nodeRowElement) ?: [] as $nodeElement) {
$element = $this->getElement($nodeElement);
$parent->add($element);
if ($element instanceof Element\AbstractGroupElement) {
$this->parseNode($nodeElement, $element);
}
}
}
protected function getElement(DOMNode $nodeElement): Element\AbstractElement
{
switch ($nodeElement->nodeName) {
case 'm:f':
// Numerator
$nodeNumerator = $this->xpath->query('m:num/m:r/m:t', $nodeElement);
if ($nodeNumerator && $nodeNumerator->length == 1) {
$value = $nodeNumerator->item(0)->nodeValue;
if (is_numeric($value)) {
$numerator = new Element\Numeric(floatval($value));
} else {
$numerator = new Element\Identifier($value);
}
} else {
throw new InvalidInputException(sprintf(
'%s : The tag `%s` has no numerator defined',
__METHOD__,
$nodeElement->nodeName
));
}
// Denominator
$nodeDenominator = $this->xpath->query('m:den/m:r/m:t', $nodeElement);
if ($nodeDenominator && $nodeDenominator->length == 1) {
$value = $nodeDenominator->item(0)->nodeValue;
if (is_numeric($value)) {
$denominator = new Element\Numeric(floatval($value));
} else {
$denominator = new Element\Identifier($value);
}
} else {
throw new InvalidInputException(sprintf(
'%s : The tag `%s` has no denominator defined',
__METHOD__,
$nodeElement->nodeName
));
}
return new Element\Fraction($numerator, $denominator);
case 'm:r':
$nodeText = $this->xpath->query('m:t', $nodeElement);
if ($nodeText && $nodeText->length == 1) {
$value = trim($nodeText->item(0)->nodeValue);
if (in_array($value, $this->operators)) {
return new Element\Operator($value);
}
if (is_numeric($value)) {
return new Element\Numeric(floatval($value));
}
return new Element\Identifier($value);
}
throw new InvalidInputException(sprintf(
'%s : The tag `%s` has no tag `m:t` defined',
__METHOD__,
$nodeElement->nodeName
));
case 'm:oMath':
return new Element\Row();
default:
throw new NotImplementedException(sprintf(
'%s : The tag `%s` is not implemented',
__METHOD__,
$nodeElement->nodeName
));
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace PhpOffice\Math\Reader;
use PhpOffice\Math\Math;
interface ReaderInterface
{
public function read(string $content): ?Math;
}

View File

@@ -0,0 +1,131 @@
<?php
namespace PhpOffice\Math\Writer;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
use XMLWriter;
class MathML implements WriterInterface
{
/** @var XMLWriter */
private $output;
/**
* @param Math $math
*
* @return string
*/
public function write(Math $math): string
{
$this->output = new XMLWriter();
$this->output->openMemory();
$this->output->startDocument('1.0', 'UTF-8');
$this->output->writeDtd('math', '-//W3C//DTD MathML 2.0//EN', 'http://www.w3.org/Math/DTD/mathml2/mathml2.dtd');
$this->output->startElement('math');
$this->output->writeAttribute('xmlns', 'http://www.w3.org/1998/Math/MathML');
foreach ($math->getElements() as $element) {
$this->writeElementItem($element);
}
$this->output->endElement();
$this->output->endDocument();
return $this->output->outputMemory();
}
protected function writeElementItem(Element\AbstractElement $element): void
{
$tagName = $this->getElementTagName($element);
// Element\AbstractGroupElement
if ($element instanceof Element\AbstractGroupElement) {
$this->output->startElement($tagName);
foreach ($element->getElements() as $childElement) {
$this->writeElementItem($childElement);
}
$this->output->endElement();
return;
}
// Element\Superscript
if ($element instanceof Element\Superscript) {
$this->output->startElement($tagName);
$this->writeElementItem($element->getBase());
$this->writeElementItem($element->getSuperscript());
$this->output->endElement();
return;
}
// Element\Fraction
if ($element instanceof Element\Fraction) {
$this->output->startElement($tagName);
$this->writeElementItem($element->getNumerator());
$this->writeElementItem($element->getDenominator());
$this->output->endElement();
return;
}
if ($element instanceof Element\Identifier
|| $element instanceof Element\Numeric
|| $element instanceof Element\Operator) {
$this->output->startElement($tagName);
$this->output->text((string) $element->getValue());
$this->output->endElement();
return;
}
/*
throw new NotImplementedException(sprintf(
'%s : The class `%s` is not implemented',
__METHOD__,
get_class($element)
));
*/
}
protected function getElementTagName(Element\AbstractElement $element): string
{
// Group
if ($element instanceof Element\Row) {
return 'mrow';
}
if ($element instanceof Element\AbstractGroupElement) {
/*
throw new NotImplementedException(sprintf(
'%s : The element of the class `%s` has no tag name',
__METHOD__,
get_class($element)
));
*/
}
if ($element instanceof Element\Superscript) {
return 'msup';
}
if ($element instanceof Element\Fraction) {
return 'mfrac';
}
if ($element instanceof Element\Identifier) {
return 'mi';
}
if ($element instanceof Element\Numeric) {
return 'mn';
}
if ($element instanceof Element\Operator) {
return 'mo';
}
throw new NotImplementedException(sprintf(
'%s : The element of the class `%s` has no tag name',
__METHOD__,
get_class($element)
));
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace PhpOffice\Math\Writer;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
use XMLWriter;
class OfficeMathML implements WriterInterface
{
/** @var XMLWriter */
private $output;
/**
* @param Math $math
*
* @return string
*/
public function write(Math $math): string
{
$this->output = new XMLWriter();
$this->output->openMemory();
$this->output->startElement('m:oMathPara');
$this->output->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');
$this->output->startElement('m:oMath');
foreach ($math->getElements() as $element) {
$this->writeElementItem($element);
}
$this->output->endElement();
$this->output->endElement();
return $this->output->outputMemory();
}
protected function writeElementItem(Element\AbstractElement $element): void
{
// Element\Row
if ($element instanceof Element\Row) {
foreach ($element->getElements() as $childElement) {
$this->writeElementItem($childElement);
}
return;
}
// Element\Fraction
if ($element instanceof Element\Fraction) {
$this->output->startElement($this->getElementTagName($element));
$this->output->startElement('m:num');
$this->writeElementItem($element->getNumerator());
$this->output->endElement();
$this->output->startElement('m:den');
$this->writeElementItem($element->getDenominator());
$this->output->endElement();
$this->output->endElement();
return;
}
if ($element instanceof Element\Identifier
|| $element instanceof Element\Numeric
|| $element instanceof Element\Operator) {
$this->output->startElement('m:r');
$this->output->startElement('m:t');
$this->output->text((string) $element->getValue());
$this->output->endElement();
$this->output->endElement();
return;
}
// Check if managed
$this->getElementTagName($element);
}
protected function getElementTagName(Element\AbstractElement $element): string
{
// Group
if ($element instanceof Element\AbstractGroupElement) {
/*
throw new NotImplementedException(sprintf(
'%s : The element of the class `%s` has no tag name',
__METHOD__,
get_class($element)
));
*/
}
if ($element instanceof Element\Fraction) {
return 'm:f';
}
throw new NotImplementedException(sprintf(
'%s : The element of the class `%s` has no tag name',
__METHOD__,
get_class($element)
));
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace PhpOffice\Math\Writer;
use PhpOffice\Math\Math;
interface WriterInterface
{
public function write(Math $math): string;
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Element;
use PhpOffice\Math\Element;
use PHPUnit\Framework\TestCase;
class AbstractGroupElementTest extends TestCase
{
public function testConstruct(): void
{
$row = new Element\Row();
$this->assertIsArray($row->getElements());
$this->assertCount(0, $row->getElements());
}
public function testAdd(): void
{
$identifierA = new Element\Identifier('a');
$row = new Element\Row();
$this->assertCount(0, $row->getElements());
$this->assertInstanceOf(Element\AbstractGroupElement::class, $row->add($identifierA));
$this->assertCount(1, $row->getElements());
$this->assertEquals([$identifierA], $row->getElements());
}
public function testRemove(): void
{
$identifierA = new Element\Identifier('a');
$row = new Element\Row();
$row->add($identifierA);
$this->assertCount(1, $row->getElements());
$this->assertInstanceOf(Element\AbstractGroupElement::class, $row->remove($identifierA));
$this->assertCount(0, $row->getElements());
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Element;
use PhpOffice\Math\Element;
use PhpOffice\Math\Element\Fraction;
use PHPUnit\Framework\TestCase;
class FractionTest extends TestCase
{
public function testConstruct(): void
{
$identifierA = new Element\Identifier('a');
$identifierB = new Element\Identifier('b');
$fraction = new Fraction($identifierA, $identifierB);
$this->assertEquals($identifierA, $fraction->getNumerator());
$this->assertEquals($identifierB, $fraction->getDenominator());
}
public function testBase(): void
{
$identifierA = new Element\Identifier('a');
$identifierB = new Element\Identifier('b');
$identifierC = new Element\Identifier('c');
$fraction = new Fraction($identifierA, $identifierB);
$this->assertEquals($identifierA, $fraction->getNumerator());
$this->assertInstanceOf(Fraction::class, $fraction->setNumerator($identifierC));
$this->assertEquals($identifierC, $fraction->getNumerator());
}
public function testFraction(): void
{
$identifierA = new Element\Identifier('a');
$identifierB = new Element\Identifier('b');
$identifierC = new Element\Identifier('c');
$fraction = new Fraction($identifierA, $identifierB);
$this->assertEquals($identifierB, $fraction->getDenominator());
$this->assertInstanceOf(Fraction::class, $fraction->setDenominator($identifierC));
$this->assertEquals($identifierC, $fraction->getDenominator());
}
}

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Element;
use PhpOffice\Math\Element\Identifier;
use PHPUnit\Framework\TestCase;
class IdentifierTest extends TestCase
{
public function testConstruct(): void
{
$operator = new Identifier('x');
$this->assertEquals('x', $operator->getValue());
}
}

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Element;
use PhpOffice\Math\Element\Numeric;
use PHPUnit\Framework\TestCase;
class NumericTest extends TestCase
{
public function testConstruct(): void
{
$numeric = new Numeric(2);
$this->assertEquals(2, $numeric->getValue());
}
}

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Element;
use PhpOffice\Math\Element\Operator;
use PHPUnit\Framework\TestCase;
class OperatorTest extends TestCase
{
public function testConstruct(): void
{
$operator = new Operator('+');
$this->assertEquals('+', $operator->getValue());
}
}

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Element;
use PhpOffice\Math\Element\Semantics;
use PHPUnit\Framework\TestCase;
class SemanticsTest extends TestCase
{
public function testConstruct(): void
{
$semantics = new Semantics();
$this->assertIsArray($semantics->getAnnotations());
$this->assertCount(0, $semantics->getAnnotations());
}
public function testAnnotation(): void
{
$semantics = new Semantics();
$this->assertIsArray($semantics->getAnnotations());
$this->assertCount(0, $semantics->getAnnotations());
$this->assertInstanceOf(Semantics::class, $semantics->addAnnotation('encoding', 'content'));
$this->assertEquals(['encoding' => 'content'], $semantics->getAnnotations());
$this->assertCount(1, $semantics->getAnnotations());
$this->assertEquals('content', $semantics->getAnnotation('encoding'));
$this->assertNull($semantics->getAnnotation('notexisting'));
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Element;
use PhpOffice\Math\Element;
use PhpOffice\Math\Element\Superscript;
use PHPUnit\Framework\TestCase;
class SuperscriptTest extends TestCase
{
public function testConstruct(): void
{
$superscript = new Superscript(new Element\Identifier('a'), new Element\Identifier('a'));
$this->assertInstanceOf(Element\Identifier::class, $superscript->getBase());
$this->assertInstanceOf(Element\Identifier::class, $superscript->getSuperscript());
}
public function testBase(): void
{
$identifierA = new Element\Identifier('a');
$identifierB = new Element\Identifier('b');
$identifierC = new Element\Identifier('c');
$superscript = new Superscript($identifierA, $identifierB);
$this->assertEquals($identifierA, $superscript->getBase());
$this->assertInstanceOf(Superscript::class, $superscript->setBase($identifierC));
$this->assertEquals($identifierC, $superscript->getBase());
}
public function testSuperscript(): void
{
$identifierA = new Element\Identifier('a');
$identifierB = new Element\Identifier('b');
$identifierC = new Element\Identifier('c');
$superscript = new Superscript($identifierA, $identifierB);
$this->assertEquals($identifierB, $superscript->getSuperscript());
$this->assertInstanceOf(Superscript::class, $superscript->setSuperscript($identifierC));
$this->assertEquals($identifierC, $superscript->getSuperscript());
}
}

View File

@@ -0,0 +1,243 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Reader;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\InvalidInputException;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
use PhpOffice\Math\Reader\MathML;
use PHPUnit\Framework\TestCase;
class MathMLTest extends TestCase
{
public function testReadBasic(): void
{
$content = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<mi>a</mi> <mo>&InvisibleTimes;</mo> <msup><mi>x</mi><mn>2</mn></msup>
<mo>+</mo><mi>b</mi><mo>&InvisibleTimes;</mo><mi>x</mi>
<mo>+</mo><mi>c</mi>
</mrow>
</math>';
$reader = new MathML();
$math = $reader->read($content);
$this->assertInstanceOf(Math::class, $math);
$elements = $math->getElements();
$this->assertCount(1, $elements);
$this->assertInstanceOf(Element\Row::class, $elements[0]);
/** @var Element\Row $element */
$element = $elements[0];
$subElements = $element->getElements();
$this->assertCount(9, $subElements);
/** @var Element\Identifier $subElement */
$subElement = $subElements[0];
$this->assertInstanceOf(Element\Identifier::class, $subElement);
$this->assertEquals('a', $subElement->getValue());
/** @var Element\Identifier $subElement */
$subElement = $subElements[1];
$this->assertInstanceOf(Element\Operator::class, $subElement);
$this->assertEquals('InvisibleTimes', $subElement->getValue());
/** @var Element\Superscript $subElement */
$subElement = $subElements[2];
$this->assertInstanceOf(Element\Superscript::class, $subElements[2]);
/** @var Element\Identifier $base */
$base = $subElement->getBase();
$this->assertInstanceOf(Element\Identifier::class, $base);
$this->assertEquals('x', $base->getValue());
/** @var Element\Numeric $superscript */
$superscript = $subElement->getSuperscript();
$this->assertInstanceOf(Element\Numeric::class, $superscript);
$this->assertEquals(2, $superscript->getValue());
/** @var Element\Operator $subElement */
$subElement = $subElements[3];
$this->assertInstanceOf(Element\Operator::class, $subElement);
$this->assertEquals('+', $subElement->getValue());
/** @var Element\Identifier $subElement */
$subElement = $subElements[4];
$this->assertInstanceOf(Element\Identifier::class, $subElement);
$this->assertEquals('b', $subElement->getValue());
/** @var Element\Operator $subElement */
$subElement = $subElements[5];
$this->assertInstanceOf(Element\Operator::class, $subElement);
$this->assertEquals('InvisibleTimes', $subElement->getValue());
/** @var Element\Identifier $subElement */
$subElement = $subElements[6];
$this->assertInstanceOf(Element\Identifier::class, $subElement);
$this->assertEquals('x', $subElement->getValue());
/** @var Element\Operator $subElement */
$subElement = $subElements[7];
$this->assertInstanceOf(Element\Operator::class, $subElement);
$this->assertEquals('+', $subElement->getValue());
/** @var Element\Identifier $subElement */
$subElement = $subElements[8];
$this->assertInstanceOf(Element\Identifier::class, $subElement);
$this->assertEquals('c', $subElement->getValue());
}
public function testReadFraction(): void
{
$content = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mfrac bevelled="true">
<mfrac>
<mi> a </mi>
<mi> b </mi>
</mfrac>
<mfrac>
<mi> c </mi>
<mi> d </mi>
</mfrac>
</mfrac>
</math>';
$reader = new MathML();
$math = $reader->read($content);
$this->assertInstanceOf(Math::class, $math);
$elements = $math->getElements();
$this->assertCount(1, $elements);
$this->assertInstanceOf(Element\Fraction::class, $elements[0]);
/** @var Element\Fraction $element */
$element = $elements[0];
$this->assertInstanceOf(Element\Fraction::class, $element->getNumerator());
/** @var Element\Fraction $subElement */
$subElement = $element->getNumerator();
/** @var Element\Identifier $numerator */
$numerator = $subElement->getNumerator();
$this->assertInstanceOf(Element\Identifier::class, $numerator);
$this->assertEquals('a', $numerator->getValue());
/** @var Element\Identifier $denominator */
$denominator = $subElement->getDenominator();
$this->assertInstanceOf(Element\Identifier::class, $denominator);
$this->assertEquals('b', $denominator->getValue());
$this->assertInstanceOf(Element\Fraction::class, $element->getDenominator());
/** @var Element\Fraction $subElement */
$subElement = $element->getDenominator();
/** @var Element\Identifier $numerator */
$numerator = $subElement->getNumerator();
$this->assertInstanceOf(Element\Identifier::class, $numerator);
$this->assertEquals('c', $numerator->getValue());
/** @var Element\Identifier $denominator */
$denominator = $subElement->getDenominator();
$this->assertInstanceOf(Element\Identifier::class, $denominator);
$this->assertEquals('d', $denominator->getValue());
}
public function testReadFractionInvalid(): void
{
$this->expectException(InvalidInputException::class);
$this->expectExceptionMessage('PhpOffice\Math\Reader\MathML::getElement : The tag `mfrac` has not two subelements');
$content = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mfrac>
<mi> a </mi>
</mfrac>
</math>';
$reader = new MathML();
$math = $reader->read($content);
}
public function testReadSuperscriptInvalid(): void
{
$this->expectException(InvalidInputException::class);
$this->expectExceptionMessage('PhpOffice\Math\Reader\MathML::getElement : The tag `msup` has not two subelements');
$content = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<msup>
<mi> a </mi>
</msup>
</math>';
$reader = new MathML();
$math = $reader->read($content);
}
public function testReadSemantics(): void
{
$content = '<?xml version="1.0" encoding="UTF-8"?>
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<semantics>
<mrow>
<mfrac>
<mi>π</mi>
<mn>2</mn>
</mfrac>
<mo stretchy="false">+</mo>
<mrow>
<mi>a</mi>
<mo stretchy="false"></mo>
<mn>2</mn>
</mrow>
</mrow>
<annotation encoding="StarMath 5.0">{π} over {2} + { a } * 2 </annotation>
</semantics>
</math>';
$reader = new MathML();
$math = $reader->read($content);
$this->assertInstanceOf(Math::class, $math);
$elements = $math->getElements();
$this->assertCount(1, $elements);
$this->assertInstanceOf(Element\Semantics::class, $elements[0]);
/** @var Element\Semantics $element */
$element = $elements[0];
// Check MathML
$subElements = $element->getElements();
$this->assertCount(1, $subElements);
$this->assertInstanceOf(Element\Row::class, $subElements[0]);
// Check Annotation
$this->assertCount(1, $element->getAnnotations());
$this->assertEquals('{π} over {2} + { a } * 2', $element->getAnnotation('StarMath 5.0'));
}
public function testReadNotImplemented(): void
{
$this->expectException(NotImplementedException::class);
$this->expectExceptionMessage('PhpOffice\Math\Reader\MathML::getElement : The tag `mnotexisting` is not implemented');
$content = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mnotexisting>
<mi> a </mi>
</mnotexisting>
</math>';
$reader = new MathML();
$math = $reader->read($content);
}
}

View File

@@ -0,0 +1,197 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Reader;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\InvalidInputException;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
use PhpOffice\Math\Reader\OfficeMathML;
use PHPUnit\Framework\TestCase;
class OfficeMathMLTest extends TestCase
{
public function testRead(): void
{
$content = '<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:oMath>
<m:f>
<m:num><m:r><m:t>2</m:t></m:r></m:num>
<m:den><m:r><m:t>π</m:t></m:r></m:den>
</m:f>
</m:oMath>
</m:oMathPara>';
$reader = new OfficeMathML();
$math = $reader->read($content);
$this->assertInstanceOf(Math::class, $math);
$elements = $math->getElements();
$this->assertCount(1, $elements);
$this->assertInstanceOf(Element\Row::class, $elements[0]);
/** @var Element\Row $element */
$element = $elements[0];
$subElements = $element->getElements();
$this->assertCount(1, $subElements);
$this->assertInstanceOf(Element\Fraction::class, $subElements[0]);
/** @var Element\Fraction $subElement */
$subElement = $subElements[0];
/** @var Element\Identifier $numerator */
$numerator = $subElement->getNumerator();
$this->assertInstanceOf(Element\Numeric::class, $numerator);
$this->assertEquals(2, $numerator->getValue());
/** @var Element\Numeric $denominator */
$denominator = $subElement->getDenominator();
$this->assertInstanceOf(Element\Identifier::class, $denominator);
$this->assertEquals('π', $denominator->getValue());
}
public function testReadWithWTag(): void
{
$content = '<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:f>
<m:num>
<m:r>
<w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr>
<m:t xml:space="preserve">π</m:t>
</m:r>
</m:num>
<m:den>
<m:r>
<w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr>
<m:t xml:space="preserve">2</m:t>
</m:r>
</m:den>
</m:f>
<m:r>
<w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr>
<m:t xml:space="preserve">+</m:t>
</m:r>
<m:r>
<w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr>
<m:t xml:space="preserve">a</m:t>
</m:r>
<m:r>
<w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr>
<m:t xml:space="preserve"></m:t>
</m:r>
<m:r>
<w:rPr><w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/></w:rPr>
<m:t xml:space="preserve">2</m:t>
</m:r>
</m:oMath>';
$reader = new OfficeMathML();
$math = $reader->read($content);
$this->assertInstanceOf(Math::class, $math);
$elements = $math->getElements();
$this->assertCount(5, $elements);
/** @var Element\Fraction $element */
$element = $elements[0];
$this->assertInstanceOf(Element\Fraction::class, $element);
/** @var Element\Identifier $numerator */
$numerator = $element->getNumerator();
$this->assertInstanceOf(Element\Identifier::class, $numerator);
$this->assertEquals('π', $numerator->getValue());
/** @var Element\Numeric $denominator */
$denominator = $element->getDenominator();
$this->assertInstanceOf(Element\Numeric::class, $denominator);
$this->assertEquals(2, $denominator->getValue());
/** @var Element\Operator $element */
$element = $elements[1];
$this->assertInstanceOf(Element\Operator::class, $element);
$this->assertEquals('+', $element->getValue());
/** @var Element\Identifier $element */
$element = $elements[2];
$this->assertInstanceOf(Element\Identifier::class, $element);
$this->assertEquals('a', $element->getValue());
/** @var Element\Operator $element */
$element = $elements[3];
$this->assertInstanceOf(Element\Operator::class, $element);
$this->assertEquals('', $element->getValue());
/** @var Element\Numeric $element */
$element = $elements[4];
$this->assertInstanceOf(Element\Numeric::class, $element);
$this->assertEquals(2, $element->getValue());
}
public function testReadFractionNoNumerator(): void
{
$this->expectException(InvalidInputException::class);
$this->expectExceptionMessage('PhpOffice\Math\Reader\OfficeMathML::getElement : The tag `m:f` has no numerator defined');
$content = '<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:oMath>
<m:f>
<m:den><m:r><m:t>2</m:t></m:r></m:den>
</m:f>
</m:oMath>
</m:oMathPara>';
$reader = new OfficeMathML();
$math = $reader->read($content);
}
public function testReadFractionNoDenominator(): void
{
$this->expectException(InvalidInputException::class);
$this->expectExceptionMessage('PhpOffice\Math\Reader\OfficeMathML::getElement : The tag `m:f` has no denominator defined');
$content = '<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:oMath>
<m:f>
<m:num><m:r><m:t>π</m:t></m:r></m:num>
</m:f>
</m:oMath>
</m:oMathPara>';
$reader = new OfficeMathML();
$math = $reader->read($content);
}
public function testReadBasicNoText(): void
{
$this->expectException(InvalidInputException::class);
$this->expectExceptionMessage('PhpOffice\Math\Reader\OfficeMathML::getElement : The tag `m:r` has no tag `m:t` defined');
$content = '<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:oMath>
<m:r>
a
</m:r>
</m:oMath>
</m:oMathPara>';
$reader = new OfficeMathML();
$math = $reader->read($content);
}
public function testReadNotImplemented(): void
{
$this->expectException(NotImplementedException::class);
$this->expectExceptionMessage('PhpOffice\Math\Reader\OfficeMathML::getElement : The tag `m:mnotexisting` is not implemented');
$content = '<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:oMath>
<m:mnotexisting>
<m:num><m:r><m:t>π</m:t></m:r></m:num>
</m:mnotexisting>
</m:oMath>
</m:oMathPara>';
$reader = new OfficeMathML();
$math = $reader->read($content);
}
}

View File

@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Writer;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
use PhpOffice\Math\Writer\MathML;
class MathMLTest extends WriterTestCase
{
public function testWrite(): void
{
$opTimes = new Element\Operator('&InvisibleTimes;');
$math = new Math();
$row = new Element\Row();
$math->add($row);
$row->add(new Element\Identifier('a'));
$row->add(clone $opTimes);
$superscript = new Element\Superscript(
new Element\Identifier('x'),
new Element\Numeric(2)
);
$row->add($superscript);
$row->add(new Element\Operator('+'));
$row->add(new Element\Identifier('b'));
$row->add(clone $opTimes);
$row->add(new Element\Identifier('x'));
$row->add(new Element\Operator('+'));
$row->add(new Element\Identifier('c'));
$writer = new MathML();
$output = $writer->write($math);
$expected = '<?xml version="1.0" encoding="UTF-8"?>'
. PHP_EOL
. '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">'
. '<math xmlns="http://www.w3.org/1998/Math/MathML">'
. '<mrow><mi>a</mi><mo>&amp;InvisibleTimes;</mo><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mi>b</mi><mo>&amp;InvisibleTimes;</mo><mi>x</mi><mo>+</mo><mi>c</mi>'
. '</mrow>'
. '</math>'
. PHP_EOL;
$this->assertEquals($expected, $output);
$this->assertIsSchemaMathMLValid($output);
}
public function testWriteFraction(): void
{
$math = new Math();
$fraction = new Element\Fraction(
new Element\Identifier('π'),
new Element\Numeric(2)
);
$math->add($fraction);
$writer = new MathML();
$output = $writer->write($math);
$expected = '<?xml version="1.0" encoding="UTF-8"?>'
. PHP_EOL
. '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">'
. '<math xmlns="http://www.w3.org/1998/Math/MathML">'
. '<mfrac>'
. '<mi>π</mi><mn>2</mn>'
. '</mfrac>'
. '</math>'
. PHP_EOL;
$this->assertEquals($expected, $output);
$this->assertIsSchemaMathMLValid($output);
}
public function testWriteNotImplemented(): void
{
$this->expectException(NotImplementedException::class);
if (method_exists($this, 'expectExceptionMessageRegExp')) {
$this->expectExceptionMessageRegExp('/PhpOffice\\\Math\\\Writer\\\MathML::getElementTagName : The element of the class/');
$this->expectExceptionMessageRegExp('/has no tag name/');
} else {
// @phpstan-ignore-next-line
$this->expectExceptionMessageMatches('/PhpOffice\\\Math\\\Writer\\\MathML::getElementTagName : The element of the class/');
// @phpstan-ignore-next-line
$this->expectExceptionMessageMatches('/has no tag name/');
}
$math = new Math();
$object = new class() extends Element\AbstractElement {};
$math->add($object);
$writer = new MathML();
$output = $writer->write($math);
}
}

View File

@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Writer;
use PhpOffice\Math\Element;
use PhpOffice\Math\Exception\NotImplementedException;
use PhpOffice\Math\Math;
use PhpOffice\Math\Writer\OfficeMathML;
class OfficeMathMLTest extends WriterTestCase
{
public function testWriteFraction(): void
{
$math = new Math();
$fraction = new Element\Fraction(
new Element\Identifier('π'),
new Element\Numeric(2)
);
$math->add($fraction);
$writer = new OfficeMathML();
$output = $writer->write($math);
$expected = '<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">'
. '<m:oMath>'
. '<m:f>'
. '<m:num><m:r><m:t>π</m:t></m:r></m:num>'
. '<m:den><m:r><m:t>2</m:t></m:r></m:den>'
. '</m:f>'
. '</m:oMath>'
. '</m:oMathPara>';
$this->assertEquals($expected, $output);
}
public function testWriteRow(): void
{
$math = new Math();
$row = new Element\Row();
$math->add($row);
$row->add(new Element\Identifier('x'));
$writer = new OfficeMathML();
$output = $writer->write($math);
$expected = '<m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">'
. '<m:oMath>'
. '<m:r><m:t>x</m:t></m:r>'
. '</m:oMath>'
. '</m:oMathPara>';
$this->assertEquals($expected, $output);
}
public function testWriteNotImplemented(): void
{
$this->expectException(NotImplementedException::class);
if (method_exists($this, 'expectExceptionMessageRegExp')) {
$this->expectExceptionMessageRegExp('/PhpOffice\\\Math\\\Writer\\\OfficeMathML::getElementTagName : The element of the class/');
$this->expectExceptionMessageRegExp('/has no tag name/');
} else {
// @phpstan-ignore-next-line
$this->expectExceptionMessageMatches('/PhpOffice\\\Math\\\Writer\\\OfficeMathML::getElementTagName : The element of the class/');
// @phpstan-ignore-next-line
$this->expectExceptionMessageMatches('/has no tag name/');
}
$math = new Math();
$object = new class() extends Element\AbstractElement {};
$math->add($object);
$writer = new OfficeMathML();
$output = $writer->write($math);
}
}

View File

@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Tests\PhpOffice\Math\Writer;
use DOMDocument;
use LibXMLError;
use PHPUnit\Framework\TestCase;
class WriterTestCase extends TestCase
{
public function assertIsSchemaMathMLValid(string $content): void
{
$dom = new DOMDocument();
$dom->loadXML($content);
$xmlSource = $dom->saveXML();
if (is_string($xmlSource)) {
$dom->loadXML($xmlSource);
$dom->schemaValidate(dirname(__DIR__, 2) . '/resources/schema/mathml3/mathml3.xsd');
$error = libxml_get_last_error();
if ($error instanceof LibXMLError) {
$this->failXmlError($error, $xmlSource);
} else {
$this->assertTrue(true);
}
return;
}
$this->fail(sprintf('The XML is not valid : %s', $content));
}
/**
* @param array<string, string> $params
*/
protected function failXmlError(LibXMLError $error, string $source, array $params = []): void
{
switch ($error->level) {
case LIBXML_ERR_WARNING:
$errorType = 'warning';
break;
case LIBXML_ERR_ERROR:
$errorType = 'error';
break;
case LIBXML_ERR_FATAL:
$errorType = 'fatal';
break;
default:
$errorType = 'Error';
break;
}
$errorLine = (int) $error->line;
$contents = explode("\n", $source);
$lines = [];
if (isset($contents[$errorLine - 2])) {
$lines[] = '>> ' . $contents[$errorLine - 2];
}
if (isset($contents[$errorLine - 1])) {
$lines[] = '>>> ' . $contents[$errorLine - 1];
}
if (isset($contents[$errorLine])) {
$lines[] = '>> ' . $contents[$errorLine];
}
$paramStr = '';
if (!empty($params)) {
$paramStr .= "\n" . ' - Parameters :' . "\n";
foreach ($params as $key => $val) {
$paramStr .= ' - ' . $key . ' : ' . $val . "\n";
}
}
$this->fail(sprintf(
"Validation %s :\n - - Line : %s\n - Message : %s - Lines :\n%s%s",
$errorType,
$error->line,
$error->message,
implode(PHP_EOL, $lines),
$paramStr
));
}
}

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:m="http://www.w3.org/1998/Math/MathML" elementFormDefault="qualified" targetNamespace="http://www.w3.org/1998/Math/MathML">
<xs:element name="math">
<xs:complexType>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:MathExpression"/>
<xs:attributeGroup ref="m:math.attributes"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="CommonDeprecatedAtt">
<xs:attribute name="other"/>
</xs:attributeGroup>
<xs:attributeGroup name="CommonAtt">
<xs:attribute name="id" type="xs:ID"/>
<xs:attribute name="xref"/>
<xs:attribute name="class" type="xs:NMTOKENS"/>
<xs:attribute name="style" type="xs:string"/>
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attributeGroup ref="m:CommonDeprecatedAtt"/>
<xs:anyAttribute namespace="##other" processContents="skip"/>
</xs:attributeGroup>
<xs:attributeGroup name="math.deprecatedattributes">
<xs:attribute name="mode" type="xs:string"/>
<xs:attribute name="macros" type="xs:string"/>
</xs:attributeGroup>
<xs:attributeGroup name="name">
<xs:attribute name="name" use="required" type="xs:NCName"/>
</xs:attributeGroup>
<xs:attributeGroup name="cd">
<xs:attribute name="cd" use="required" type="xs:NCName"/>
</xs:attributeGroup>
<xs:attributeGroup name="src">
<xs:attribute name="src" type="xs:anyURI"/>
</xs:attributeGroup>
<xs:element name="annotation">
<xs:complexType mixed="true">
<xs:attributeGroup ref="m:annotation.attributes"/>
</xs:complexType>
</xs:element>
<xs:complexType name="annotation-xml.model"><!--content model altered for libxml (annotation-xml)--><xs:sequence>
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
<xs:group name="anyElement">
<xs:choice>
<xs:any namespace="##other" processContents="skip"/>
<xs:any namespace="##local" processContents="skip"/>
</xs:choice>
</xs:group>
<xs:element name="annotation-xml">
<xs:complexType>
<xs:complexContent>
<xs:extension base="m:annotation-xml.model">
<xs:attributeGroup ref="m:annotation.attributes"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="annotation.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attribute name="cd" type="xs:NCName"/>
<xs:attribute name="name" type="xs:NCName"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attributeGroup ref="m:src"/>
</xs:attributeGroup>
<xs:attributeGroup name="DefEncAtt">
<xs:attribute name="encoding" type="xs:string"/>
<xs:attribute name="definitionURL" type="xs:anyURI"/>
</xs:attributeGroup>
<xs:group name="semantics">
<xs:sequence>
<xs:element name="semantics">
<xs:complexType>
<xs:sequence>
<xs:group ref="m:MathExpression"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:annotation"/>
<xs:element ref="m:annotation-xml"/>
</xs:choice>
</xs:sequence>
<xs:attributeGroup ref="m:semantics.attributes"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:group>
<xs:attributeGroup name="semantics.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="cd" type="xs:NCName"/>
<xs:attribute name="name" type="xs:NCName"/>
</xs:attributeGroup>
<xs:simpleType name="length">
<xs:restriction base="xs:string">
<xs:pattern value="\s*((-?[0-9]*([0-9]\.?|\.[0-9])[0-9]*(e[mx]|in|cm|mm|p[xtc]|%)?)|(negative)?((very){0,2}thi(n|ck)|medium)mathspace)\s*"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

View File

@@ -0,0 +1,681 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:m="http://www.w3.org/1998/Math/MathML" elementFormDefault="qualified" targetNamespace="http://www.w3.org/1998/Math/MathML">
<xs:include schemaLocation="mathml3-strict-content.xsd"/>
<xs:complexType name="cn.content" mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:mglyph"/>
<xs:element ref="m:sep"/>
<xs:element ref="m:PresentationExpression"/>
</xs:choice>
</xs:complexType>
<xs:attributeGroup name="cn.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="type"/>
<xs:attribute name="base"/>
</xs:attributeGroup>
<xs:attributeGroup name="ci.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="type"/>
</xs:attributeGroup>
<xs:attributeGroup name="ci.type">
<xs:attribute name="type" use="required"/>
</xs:attributeGroup>
<xs:complexType name="ci.content" mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:mglyph"/>
<xs:element ref="m:PresentationExpression"/>
</xs:choice>
</xs:complexType>
<xs:attributeGroup name="csymbol.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="type"/>
<xs:attribute name="cd" type="xs:NCName"/>
</xs:attributeGroup>
<xs:complexType name="csymbol.content" mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:mglyph"/>
<xs:element ref="m:PresentationExpression"/>
</xs:choice>
</xs:complexType>
<xs:element name="bvar">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:choice>
<xs:element ref="m:ci"/>
<xs:group ref="m:semantics-ci"/>
</xs:choice>
<xs:element ref="m:degree"/>
</xs:choice>
<xs:attributeGroup ref="m:CommonAtt"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="cbytes.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:attributeGroup>
<xs:attributeGroup name="cs.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:attributeGroup>
<!--Ambiguous content model altered (apply.content)-->
<xs:complexType name="apply.content">
<xs:sequence>
<xs:group ref="m:ContExp"/>
<xs:group ref="m:BvarQ"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:Qualifier"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:ContExp"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="bind.content">
<xs:complexContent>
<xs:extension base="m:apply.content"/>
</xs:complexContent>
</xs:complexType>
<xs:attributeGroup name="base">
<xs:attribute name="base" use="required"/>
</xs:attributeGroup>
<xs:element name="sep">
<xs:complexType/>
</xs:element>
<xs:element name="PresentationExpression" abstract="true"/>
<xs:group name="DomainQ">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:domainofapplication"/>
<xs:element ref="m:condition"/>
<!--Ambiguous content model altered (interval)--><xs:sequence>
<xs:element ref="m:lowlimit"/>
<xs:element minOccurs="0" ref="m:uplimit"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:element name="domainofapplication">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:element name="condition">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:element name="uplimit">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:element name="lowlimit">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:group name="Qualifier">
<xs:choice>
<xs:group ref="m:DomainQ"/>
<xs:element ref="m:degree"/>
<xs:element ref="m:momentabout"/>
<xs:element ref="m:logbase"/>
</xs:choice>
</xs:group>
<xs:element name="degree">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:element name="momentabout">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:element name="logbase">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="type">
<xs:attribute name="type" use="required"/>
</xs:attributeGroup>
<xs:attributeGroup name="order">
<xs:attribute name="order" use="required">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="numeric"/>
<xs:enumeration value="lexicographic"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="closure">
<xs:attribute name="closure" use="required"/>
</xs:attributeGroup>
<xs:element name="piecewise">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:piece"/>
<xs:element ref="m:otherwise"/>
</xs:choice>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="piece">
<xs:complexType>
<xs:sequence>
<xs:group ref="m:ContExp"/>
<xs:group ref="m:ContExp"/>
</xs:sequence>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="otherwise">
<xs:complexType>
<xs:group ref="m:ContExp"/>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="DeprecatedContExp" abstract="true"/>
<xs:element name="reln" substitutionGroup="m:DeprecatedContExp">
<xs:complexType>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:element name="fn" substitutionGroup="m:DeprecatedContExp">
<xs:complexType>
<xs:group ref="m:ContExp"/>
</xs:complexType>
</xs:element>
<xs:element name="declare" substitutionGroup="m:DeprecatedContExp">
<xs:complexType>
<xs:group maxOccurs="unbounded" ref="m:ContExp"/>
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="scope" type="xs:string"/>
<xs:attribute name="nargs" type="xs:nonNegativeInteger"/>
<xs:attribute name="occurrence">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="prefix"/>
<xs:enumeration value="infix"/>
<xs:enumeration value="function-model"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="interval.class" abstract="true">
<xs:complexType>
<xs:sequence>
<xs:group ref="m:ContExp"/>
<xs:group ref="m:ContExp"/>
</xs:sequence>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="closure"/>
</xs:complexType>
</xs:element>
<xs:element name="interval" substitutionGroup="m:interval.class"/>
<xs:element name="unary-functional.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="inverse" substitutionGroup="m:unary-functional.class"/>
<xs:element name="ident" substitutionGroup="m:unary-functional.class"/>
<xs:element name="domain" substitutionGroup="m:unary-functional.class"/>
<xs:element name="codomain" substitutionGroup="m:unary-functional.class"/>
<xs:element name="image" substitutionGroup="m:unary-functional.class"/>
<xs:element name="ln" substitutionGroup="m:unary-functional.class"/>
<xs:element name="log" substitutionGroup="m:unary-functional.class"/>
<xs:element name="moment" substitutionGroup="m:unary-functional.class"/>
<xs:element name="lambda.class" abstract="true">
<xs:complexType>
<xs:sequence>
<xs:group ref="m:BvarQ"/>
<xs:group ref="m:DomainQ"/>
<xs:group ref="m:ContExp"/>
</xs:sequence>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="lambda" substitutionGroup="m:lambda.class"/>
<xs:element name="nary-functional.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="compose" substitutionGroup="m:nary-functional.class"/>
<xs:group name="binary-arith.class">
<xs:choice>
<xs:element ref="m:quotient"/>
<xs:element ref="m:divide"/>
<xs:element ref="m:minus"/>
<xs:element ref="m:power"/>
<xs:element ref="m:rem"/>
<xs:element ref="m:root"/>
</xs:choice>
</xs:group>
<xs:element name="quotient">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="divide">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="minus">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="power">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="rem">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="root">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:group name="unary-arith.class">
<xs:choice>
<xs:element ref="m:factorial"/>
<!--Ambiguous content model altered (minus)--><!--Ambiguous content model altered (root)--><xs:element ref="m:abs"/>
<xs:element ref="m:conjugate"/>
<xs:element ref="m:arg"/>
<xs:element ref="m:real"/>
<xs:element ref="m:imaginary"/>
<xs:element ref="m:floor"/>
<xs:element ref="m:ceiling"/>
<xs:element ref="m:exp"/>
</xs:choice>
</xs:group>
<xs:element name="factorial">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="abs">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="conjugate">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="arg">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="real">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="imaginary">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="floor">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="ceiling">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="exp">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="nary-minmax.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="max" substitutionGroup="m:nary-minmax.class"/>
<xs:element name="min" substitutionGroup="m:nary-minmax.class"/>
<xs:element name="nary-arith.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="plus" substitutionGroup="m:nary-arith.class"/>
<xs:element name="times" substitutionGroup="m:nary-arith.class"/>
<xs:element name="gcd" substitutionGroup="m:nary-arith.class"/>
<xs:element name="lcm" substitutionGroup="m:nary-arith.class"/>
<xs:element name="nary-logical.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="and" substitutionGroup="m:nary-logical.class"/>
<xs:element name="or" substitutionGroup="m:nary-logical.class"/>
<xs:element name="xor" substitutionGroup="m:nary-logical.class"/>
<xs:element name="unary-logical.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="not" substitutionGroup="m:unary-logical.class"/>
<xs:element name="binary-logical.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="implies" substitutionGroup="m:binary-logical.class"/>
<xs:element name="equivalent" substitutionGroup="m:binary-logical.class"/>
<xs:element name="quantifier.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="forall" substitutionGroup="m:quantifier.class"/>
<xs:element name="exists" substitutionGroup="m:quantifier.class"/>
<xs:element name="nary-reln.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="eq" substitutionGroup="m:nary-reln.class"/>
<xs:element name="gt" substitutionGroup="m:nary-reln.class"/>
<xs:element name="lt" substitutionGroup="m:nary-reln.class"/>
<xs:element name="geq" substitutionGroup="m:nary-reln.class"/>
<xs:element name="leq" substitutionGroup="m:nary-reln.class"/>
<xs:element name="binary-reln.class" abstract="true"/>
<xs:element name="neq" substitutionGroup="m:binary-reln.class">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="approx" substitutionGroup="m:binary-reln.class">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="factorof" substitutionGroup="m:binary-reln.class">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="tendsto" substitutionGroup="m:binary-reln.class">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="type"/>
</xs:complexType>
</xs:element>
<xs:element name="int.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="int" substitutionGroup="m:int.class"/>
<xs:element name="Differential-Operator.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="diff" substitutionGroup="m:Differential-Operator.class"/>
<xs:element name="partialdiff.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="partialdiff" substitutionGroup="m:partialdiff.class"/>
<xs:element name="unary-veccalc.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="divergence" substitutionGroup="m:unary-veccalc.class"/>
<xs:element name="grad" substitutionGroup="m:unary-veccalc.class"/>
<xs:element name="curl" substitutionGroup="m:unary-veccalc.class"/>
<xs:element name="laplacian" substitutionGroup="m:unary-veccalc.class"/>
<xs:element name="nary-setlist-constructor.class" abstract="true"/>
<xs:element name="set" substitutionGroup="m:nary-setlist-constructor.class">
<xs:complexType>
<xs:sequence>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:BvarQ"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:DomainQ"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:ContExp"/>
</xs:sequence>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="type"/>
</xs:complexType>
</xs:element>
<xs:element name="list" substitutionGroup="m:nary-setlist-constructor.class">
<xs:complexType>
<xs:sequence>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:BvarQ"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:DomainQ"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:ContExp"/>
</xs:sequence>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
<xs:attribute name="order">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="numeric"/>
<xs:enumeration value="lexicographic"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="nary-set.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="union" substitutionGroup="m:nary-set.class"/>
<xs:element name="intersect" substitutionGroup="m:nary-set.class"/>
<xs:element name="cartesianproduct" substitutionGroup="m:nary-set.class"/>
<xs:element name="binary-set.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="in" substitutionGroup="m:binary-set.class"/>
<xs:element name="notin" substitutionGroup="m:binary-set.class"/>
<xs:element name="notsubset" substitutionGroup="m:binary-set.class"/>
<xs:element name="notprsubset" substitutionGroup="m:binary-set.class"/>
<xs:element name="setdiff" substitutionGroup="m:binary-set.class"/>
<xs:element name="nary-set-reln.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="subset" substitutionGroup="m:nary-set-reln.class"/>
<xs:element name="prsubset" substitutionGroup="m:nary-set-reln.class"/>
<xs:element name="unary-set.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="card" substitutionGroup="m:unary-set.class"/>
<xs:element name="sum.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="sum" substitutionGroup="m:sum.class"/>
<xs:element name="product.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="product" substitutionGroup="m:product.class"/>
<xs:element name="limit.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="limit" substitutionGroup="m:limit.class"/>
<xs:element name="unary-elementary.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="sin" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="cos" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="tan" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="sec" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="csc" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="cot" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="sinh" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="cosh" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="tanh" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="sech" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="csch" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="coth" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arcsin" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arccos" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arctan" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arccosh" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arccot" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arccoth" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arccsc" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arccsch" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arcsec" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arcsech" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arcsinh" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="arctanh" substitutionGroup="m:unary-elementary.class"/>
<xs:element name="nary-stats.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="mean" substitutionGroup="m:nary-stats.class"/>
<xs:element name="sdev" substitutionGroup="m:nary-stats.class"/>
<xs:element name="variance" substitutionGroup="m:nary-stats.class"/>
<xs:element name="median" substitutionGroup="m:nary-stats.class"/>
<xs:element name="mode" substitutionGroup="m:nary-stats.class"/>
<xs:element name="nary-constructor.class" abstract="true">
<xs:complexType>
<xs:sequence>
<xs:group ref="m:BvarQ"/>
<xs:group ref="m:DomainQ"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:ContExp"/>
</xs:sequence>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="vector" substitutionGroup="m:nary-constructor.class"/>
<xs:element name="matrix" substitutionGroup="m:nary-constructor.class"/>
<xs:element name="matrixrow" substitutionGroup="m:nary-constructor.class"/>
<xs:element name="unary-linalg.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="determinant" substitutionGroup="m:unary-linalg.class"/>
<xs:element name="transpose" substitutionGroup="m:unary-linalg.class"/>
<xs:element name="nary-linalg.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="selector" substitutionGroup="m:nary-linalg.class"/>
<xs:element name="binary-linalg.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="vectorproduct" substitutionGroup="m:binary-linalg.class"/>
<xs:element name="scalarproduct" substitutionGroup="m:binary-linalg.class"/>
<xs:element name="outerproduct" substitutionGroup="m:binary-linalg.class"/>
<xs:element name="constant-set.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="integers" substitutionGroup="m:constant-set.class"/>
<xs:element name="reals" substitutionGroup="m:constant-set.class"/>
<xs:element name="rationals" substitutionGroup="m:constant-set.class"/>
<xs:element name="naturalnumbers" substitutionGroup="m:constant-set.class"/>
<xs:element name="complexes" substitutionGroup="m:constant-set.class"/>
<xs:element name="primes" substitutionGroup="m:constant-set.class"/>
<xs:element name="emptyset" substitutionGroup="m:constant-set.class"/>
<xs:element name="constant-arith.class" abstract="true">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:DefEncAtt"/>
</xs:complexType>
</xs:element>
<xs:element name="exponentiale" substitutionGroup="m:constant-arith.class"/>
<xs:element name="imaginaryi" substitutionGroup="m:constant-arith.class"/>
<xs:element name="notanumber" substitutionGroup="m:constant-arith.class"/>
<xs:element name="true" substitutionGroup="m:constant-arith.class"/>
<xs:element name="false" substitutionGroup="m:constant-arith.class"/>
<xs:element name="pi" substitutionGroup="m:constant-arith.class"/>
<xs:element name="eulergamma" substitutionGroup="m:constant-arith.class"/>
<xs:element name="infinity" substitutionGroup="m:constant-arith.class"/>
</xs:schema>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:m="http://www.w3.org/1998/Math/MathML" elementFormDefault="qualified" targetNamespace="http://www.w3.org/1998/Math/MathML">
<xs:group name="ContExp">
<xs:choice>
<!--Ambiguous content model altered (ContExp)-->
<xs:element ref="m:apply"/>
<xs:element ref="m:bind"/>
<xs:element ref="m:ci"/>
<xs:element ref="m:cn"/>
<xs:element ref="m:csymbol"/>
<xs:element ref="m:cbytes"/>
<xs:element ref="m:cerror"/>
<xs:element ref="m:cs"/>
<xs:element ref="m:share"/>
<xs:element ref="m:piecewise"/>
<xs:element ref="m:DeprecatedContExp"/>
<xs:element ref="m:interval.class"/>
<xs:element ref="m:unary-functional.class"/>
<xs:element ref="m:lambda.class"/>
<xs:element ref="m:nary-functional.class"/>
<xs:group ref="m:binary-arith.class"/>
<xs:group ref="m:unary-arith.class"/>
<xs:element ref="m:nary-minmax.class"/>
<xs:element ref="m:nary-arith.class"/>
<xs:element ref="m:nary-logical.class"/>
<xs:element ref="m:unary-logical.class"/>
<xs:element ref="m:binary-logical.class"/>
<xs:element ref="m:quantifier.class"/>
<xs:element ref="m:nary-reln.class"/>
<xs:element ref="m:binary-reln.class"/>
<xs:element ref="m:int.class"/>
<xs:element ref="m:Differential-Operator.class"/>
<xs:element ref="m:partialdiff.class"/>
<xs:element ref="m:unary-veccalc.class"/>
<xs:element ref="m:nary-setlist-constructor.class"/>
<xs:element ref="m:nary-set.class"/>
<xs:element ref="m:binary-set.class"/>
<xs:element ref="m:nary-set-reln.class"/>
<xs:element ref="m:unary-set.class"/>
<xs:element ref="m:sum.class"/>
<xs:element ref="m:product.class"/>
<xs:element ref="m:limit.class"/>
<xs:element ref="m:unary-elementary.class"/>
<xs:element ref="m:nary-stats.class"/>
<xs:element ref="m:nary-constructor.class"/>
<xs:element ref="m:unary-linalg.class"/>
<xs:element ref="m:nary-linalg.class"/>
<xs:element ref="m:binary-linalg.class"/>
<xs:element ref="m:constant-set.class"/>
<xs:element ref="m:constant-arith.class"/>
</xs:choice>
</xs:group>
<xs:element name="cn">
<xs:complexType>
<xs:complexContent>
<xs:extension base="m:cn.content">
<xs:attributeGroup ref="m:cn.attributes"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:group name="semantics-ci">
<xs:sequence>
<xs:element name="semantics">
<xs:complexType>
<xs:sequence>
<xs:choice>
<xs:element ref="m:ci"/>
<xs:group ref="m:semantics-ci"/>
</xs:choice>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:annotation"/>
<xs:element ref="m:annotation-xml"/>
</xs:choice>
</xs:sequence>
<xs:attributeGroup ref="m:semantics.attributes"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:group>
<xs:group name="semantics-contexp">
<xs:sequence>
<xs:element name="semantics">
<xs:complexType>
<xs:sequence>
<xs:group ref="m:ContExp"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="m:annotation"/>
<xs:element ref="m:annotation-xml"/>
</xs:choice>
</xs:sequence>
<xs:attributeGroup ref="m:semantics.attributes"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:group>
<xs:element name="ci">
<xs:complexType>
<xs:complexContent>
<xs:extension base="m:ci.content">
<xs:attributeGroup ref="m:ci.attributes"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="csymbol">
<xs:complexType>
<xs:complexContent>
<xs:extension base="m:csymbol.content">
<xs:attributeGroup ref="m:csymbol.attributes"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:simpleType name="SymbolName">
<xs:restriction base="xs:NCName"/>
</xs:simpleType>
<xs:group name="BvarQ">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="m:bvar"/>
</xs:sequence>
</xs:group>
<xs:element name="apply">
<xs:complexType>
<xs:complexContent>
<xs:extension base="m:apply.content">
<xs:attributeGroup ref="m:CommonAtt"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="bind">
<xs:complexType>
<xs:complexContent>
<xs:extension base="m:bind.content">
<xs:attributeGroup ref="m:CommonAtt"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="share">
<xs:complexType>
<xs:attributeGroup ref="m:CommonAtt"/>
<xs:attributeGroup ref="m:src"/>
</xs:complexType>
</xs:element>
<xs:element name="cerror">
<xs:complexType>
<xs:sequence>
<xs:element ref="m:csymbol"/>
<xs:group minOccurs="0" maxOccurs="unbounded" ref="m:ContExp"/>
</xs:sequence>
<xs:attributeGroup ref="m:cerror.attributes"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="cerror.attributes">
<xs:attributeGroup ref="m:CommonAtt"/>
</xs:attributeGroup>
<xs:element name="cbytes">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="m:base64">
<xs:attributeGroup ref="m:cbytes.attributes"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:simpleType name="base64">
<xs:restriction base="xs:base64Binary"/>
</xs:simpleType>
<xs:element name="cs">
<xs:complexType mixed="true">
<xs:attributeGroup ref="m:cs.attributes"/>
</xs:complexType>
</xs:element>
<xs:group name="MathExpression">
<xs:choice>
<xs:group ref="m:ContExp"/>
<xs:element ref="m:PresentationExpression"/>
<xs:group ref="m:semantics"/>
</xs:choice>
</xs:group>
</xs:schema>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:m="http://www.w3.org/1998/Math/MathML" elementFormDefault="qualified" targetNamespace="http://www.w3.org/1998/Math/MathML">
<xs:include schemaLocation="mathml3-content.xsd"/>
<xs:include schemaLocation="mathml3-presentation.xsd"/>
<xs:include schemaLocation="mathml3-common.xsd"/>
</xs:schema>