1"""SAX filter for MathML-to-SVG conversion.""" 2 3import sys 4from xml import sax 5from mathnode import MathNode 6from mathconfig import MathConfig 7from nodelocator import NodeLocator 8 9# MathML namespace 10MathNS = u"http://www.w3.org/1998/Math/MathML" 11 12class MathHandler (sax.ContentHandler): 13 """SAX ContentHandler for converting MathML formulae to SVG. 14 15 Instances of this class read MathML through SAX callbacks, and write 16 SVG to the destination (specified as another SAX ContentHandler). 17 Uses namespace-aware SAX calls for both input and output.""" 18 19 def __init__(self, saxoutput, config): 20 self.config = MathConfig(config) 21 self.output = saxoutput 22 self.skip = 0 23 self.currentNode = None 24 self.locator = None 25 26 27 def setDocumentLocator(self, locator): 28 self.locator = locator 29 30 31 def startDocument(self): 32 self.output.startDocument() 33 34 35 def endDocument(self): 36 self.output.endDocument() 37 38 39 def startElementNS(self, elementName, qName, attributes): 40 if self.skip > 0: self.skip += 1; return 41 42 locator = NodeLocator(self.locator) 43 (namespace, localName) = elementName 44 if namespace and namespace != MathNS: 45 if self.config.verbose: 46 locator.message("Skipped element '%s' from an unknown namespace '%s'" % (localName, namespace), "INFO") 47 self.skip = 1; return 48 49 properties = {} 50 for (attName, value) in attributes.items(): 51 (attNamespace, attLocalName) = attName 52 if attNamespace and attNamespace != MathNS: 53 if self.config.verbose: 54 locator.message("Ignored attribute '%s' from an unknown namespace '%s'" % (attLocalName, attNamespace), "INFO") 55 continue 56 properties[attLocalName] = value 57 58 self.currentNode = MathNode (localName, properties, locator, self.config, self.currentNode) 59 60 61 def endElementNS(self, elementName, qName): 62 if self.skip > 0: 63 self.skip -= 1 64 if self.skip > 0: return 65 66 (namespace, localname) = elementName 67 if namespace and namespace != MathNS: 68 raise sax.SAXParseException("SAX parser error: namespace on opening and closing elements don't match", None, self.locator) 69 if self.currentNode is None: 70 raise sax.SAXParseException("SAX parser error: unmatched closing tag", None, self.locator) 71 72 # Normalize text 73 self.currentNode.text = u' '.join(self.currentNode.text.split()) 74 75 # If we're back to the top of the tree, measure and draw everything 76 if self.currentNode.parent is None: 77 self.currentNode.makeImage(self.output) 78 79 self.currentNode = self.currentNode.parent 80 81 82 def characters(self, content): 83 if self.skip > 0: return 84 if self.currentNode: 85 self.currentNode.text += content 86 87