+ requires 'nokogiri'
+
+ Xmlns = {
+ math: 'http://www.w3.org/1998/Math/MathML',
+ svg: 'http://www.w3.org/2000/svg',
+ }.freeze
+
+ XHTMLPublic = '-//W3C//DTD XHTML 1.1//EN'
+ MathPublic = '-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN'
+ MathSystem = 'http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd'
+ SVGPublic = '-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN'
+ SVGSystem = 'http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd'
+
+ # XSLT 1.0 as implemented in Nokogiri canot construct doctypes based
+ # on content. When using MathML or SVG elements in XHTML a different
+ # doctype is needed: select one based on which elements are present.
+ def fix_doctype(content, params = {})
+ return "#{content}" if not params[:fix_doctype]
+
+ doc = Nokogiri::XML(content)
+ doctype = doc.internal_subset
+
+ return "#{content}" if doctype.external_id != XHTMLPublic
+
+ if not doc.xpath("//svg:svg", Xmlns).empty?
+ doctype.remove
+ doc.create_internal_subset("html", SVGPublic, SVGSystem)
+ elsif not doc.xpath("//math:math", Xmlns).empty?
+ doctype.remove
+ doc.create_internal_subset("html", MathPublic, MathSystem)
+ end
+
+ return doc.to_xml
+ end