__init__.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. """Module with some functions for MathML, like transforming MathML
  2. content in MathML presentation.
  3. To use this module, you will need lxml.
  4. """
  5. from pathlib import Path
  6. from sympy.utilities.decorator import doctest_depends_on
  7. __doctest_requires__ = {('apply_xsl', 'c2p'): ['lxml']}
  8. def add_mathml_headers(s):
  9. return """<math xmlns:mml="http://www.w3.org/1998/Math/MathML"
  10. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  11. xsi:schemaLocation="http://www.w3.org/1998/Math/MathML
  12. http://www.w3.org/Math/XMLSchema/mathml2/mathml2.xsd">""" + s + "</math>"
  13. def _read_binary(pkgname, filename):
  14. import sys
  15. if sys.version_info >= (3, 10):
  16. # files was added in Python 3.9 but only seems to work here in 3.10+
  17. from importlib.resources import files
  18. return files(pkgname).joinpath(filename).read_bytes()
  19. else:
  20. # read_binary was deprecated in Python 3.11
  21. from importlib.resources import read_binary
  22. return read_binary(pkgname, filename)
  23. def _read_xsl(xsl):
  24. # Previously these values were allowed:
  25. if xsl == 'mathml/data/simple_mmlctop.xsl':
  26. xsl = 'simple_mmlctop.xsl'
  27. elif xsl == 'mathml/data/mmlctop.xsl':
  28. xsl = 'mmlctop.xsl'
  29. elif xsl == 'mathml/data/mmltex.xsl':
  30. xsl = 'mmltex.xsl'
  31. if xsl in ['simple_mmlctop.xsl', 'mmlctop.xsl', 'mmltex.xsl']:
  32. xslbytes = _read_binary('sympy.utilities.mathml.data', xsl)
  33. else:
  34. xslbytes = Path(xsl).read_bytes()
  35. return xslbytes
  36. @doctest_depends_on(modules=('lxml',))
  37. def apply_xsl(mml, xsl):
  38. """Apply a xsl to a MathML string.
  39. Parameters
  40. ==========
  41. mml
  42. A string with MathML code.
  43. xsl
  44. A string giving the name of an xsl (xml stylesheet) file which can be
  45. found in sympy/utilities/mathml/data. The following files are supplied
  46. with SymPy:
  47. - mmlctop.xsl
  48. - mmltex.xsl
  49. - simple_mmlctop.xsl
  50. Alternatively, a full path to an xsl file can be given.
  51. Examples
  52. ========
  53. >>> from sympy.utilities.mathml import apply_xsl
  54. >>> xsl = 'simple_mmlctop.xsl'
  55. >>> mml = '<apply> <plus/> <ci>a</ci> <ci>b</ci> </apply>'
  56. >>> res = apply_xsl(mml,xsl)
  57. >>> print(res)
  58. <?xml version="1.0"?>
  59. <mrow xmlns="http://www.w3.org/1998/Math/MathML">
  60. <mi>a</mi>
  61. <mo> + </mo>
  62. <mi>b</mi>
  63. </mrow>
  64. """
  65. from lxml import etree
  66. parser = etree.XMLParser(resolve_entities=False)
  67. ac = etree.XSLTAccessControl.DENY_ALL
  68. s = etree.XML(_read_xsl(xsl), parser=parser)
  69. transform = etree.XSLT(s, access_control=ac)
  70. doc = etree.XML(mml, parser=parser)
  71. result = transform(doc)
  72. s = str(result)
  73. return s
  74. @doctest_depends_on(modules=('lxml',))
  75. def c2p(mml, simple=False):
  76. """Transforms a document in MathML content (like the one that sympy produces)
  77. in one document in MathML presentation, more suitable for printing, and more
  78. widely accepted
  79. Examples
  80. ========
  81. >>> from sympy.utilities.mathml import c2p
  82. >>> mml = '<apply> <exp/> <cn>2</cn> </apply>'
  83. >>> c2p(mml,simple=True) != c2p(mml,simple=False)
  84. True
  85. """
  86. if not mml.startswith('<math'):
  87. mml = add_mathml_headers(mml)
  88. if simple:
  89. return apply_xsl(mml, 'mathml/data/simple_mmlctop.xsl')
  90. return apply_xsl(mml, 'mathml/data/mmlctop.xsl')