########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Xml/Xslt/SaxWriter.py,v 1.9 2005/03/18 23:47:19 jkloth Exp $
"""
SAX2 event writer for XSLT output
Copyright 2005 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""
import os
from Ft.Xml import EMPTY_NAMESPACE,XMLNS_NAMESPACE
from Ft.Xml import CheckVersion
from Ft.Xml.Domlette import implementation
from Ft.Xml.Lib.XmlString import IsXmlSpace,SplitQName
from Ft.Xml.XPath import Util
from Ft.Xml.Xslt import XSL_NAMESPACE,TextSax
from Ft.Xml.Xslt import OutputParameters
class ElementData:
def __init__(self, name, attrs, extraNss=None):
self.name = name
self.attrs = attrs
self.extraNss = extraNss or {}
try:
from xml.dom.ext.reader import Sax,Sax2,HtmlSax
except ImportError:
#It will be caught if a SaxWriter is created
pass
class SaxWriter:
"""
Requires PyXML (will be checked at instantiation time).
"""
def __init__(self, outputParams, saxHandler=None, fragment=False):
CheckVersion(feature="4XSLT's SaxWriter")
self.__fragment = fragment
self.__firstElementFlag = True
self.__orphanedNodes = []
self.__saxHandlerClass = None
self.__saxHandler = None
self.__stateStack = []
self.__currElement = None
self.__currText = u''
self._outputParams = outputParams or OutputParameters.OutputParameters()
if saxHandler:
self.__saxHandler = saxHandler
elif self.__outputParams.method == 'xml':
self.__initSaxHandler(Sax2.XmlDomGenerator)
if self.__outputParams.omitXmlDeclaration in [None, 'no']:
self.__saxHandler.xmlDecl(
self.__outputParams.version,
self.__outputParams.encoding,
self.__outputParams.standalone
)
elif self.__outputParams.method == 'html':
self.__initSaxHandler(HtmlSax.HtmlDomGenerator)
elif self.__outputParams.method == 'text':
self.__initSaxHandler(TextSax.TextGenerator)
def startDocument(self):
return
def endDocument(self):
return
def complete(self):
return self.__saxHandler and self.__saxHandler.getRootNode() or None
def getResult(self):
self.__completeTextNode()
return self.__saxHandler.getRootNode()
def __initSaxHandler(self, saxHandlerClass):
self.__saxHandlerClass = saxHandlerClass
self.__saxHandler = saxHandlerClass(keepAllWs=1)
for o_node in self.__orphanedNodes:
if o_node[0] == 'pi':
self.__saxHandler.processingInstruction(o_node[1], o_node[2])
elif o_node[0] == 'comment':
self.__saxHandler.comment(o_node[1])
del self.__orphanedNodes
return
def __initSax2Doc(self, doctype):
self.__firstElementFlag = False
if not self.__fragment:
if not self.__saxHandler:
self.__initSaxHandler(Sax2.XmlDomGenerator)
if self.__outputParams.omitXmlDeclaration in [None, 'no']:
self.__saxHandler.xmlDecl(
self.__outputParams.version,
self.__outputParams.encoding,
self.__outputParams.standalone
)
self.__saxHandler.startDTD(doctype, self.__outputParams.doctypeSystem, self.__outputParams.doctypePublic)
self.__saxHandler.endDTD()
return
def __initHtmlSaxDoc(self, doctype):
self.__firstElementFlag = False
if not self.__saxHandler:
self.__initSaxHandler(HtmlSax.HtmlDomGenerator)
#self.__saxHandler._4dom_startDTD(doctype, self.__outputParams.doctypeSystem, self.__outputParams.doctypePublic)
#self.__saxHandler.endDTD()
def __completeTextNode(self):
#FIXME: This does not allow multiple root nodes, which is required to be supported
if self.__currText:
if IsXmlSpace(self.__currText):
self.__saxHandler.ignorableWhitespace(self.__currText)
else:
self.__saxHandler.characters(self.__currText)
self.__currText = u''
return
def startElement(self, name, namespace=EMPTY_NAMESPACE, extraNss=None):
extraNss = extraNss or {}
attrs = {}
if self.__firstElementFlag:
if not self.__outputParams.method:
if not namespace and name.upper() == 'HTML':
self.__outputParams.method = 'html'
else:
self.__outputParams.method = 'xml'
if self.__outputParams.method == 'xml':
self.__initSax2Doc(name)
else:
self.__initHtmlSaxDoc(name)
self.__firstElementFlag = False
self.__completeTextNode()
if self.__currElement:
self.__saxHandler.startElement(self.__currElement.name, self.__currElement.attrs)
self.__currElement = None
self.__currElement = ElementData(name, attrs, extraNss)
if self.__outputParams.method == 'xml':
if namespace:
(prefix, local) = SplitQName(name)
if prefix:
self.__currElement.attrs["xmlns:"+prefix] = namespace
else:
self.__currElement.attrs["xmlns"] = namespace
for prefix in extraNss.keys():
if prefix:
new_element.setAttributeNS(XMLNS_NAMESPACE,
u'xmlns:'+prefix,
extraNss[prefix])
else:
new_element.setAttributeNS(XMLNS_NAMESPACE,
u'xmlns',
extraNss[''])
return
def endElement(self, name):
self.__completeTextNode()
if self.__currElement:
self.__saxHandler.startElement(
self.__currElement.name,
self.__currElement.attrs
)
self.__currElement = None
self.__saxHandler.endElement(name)
return
def text(self, text, escapeOutput=True):
if self.__currElement:
self.__saxHandler.startElement(
self.__currElement.name,
self.__currElement.attrs
)
self.__currElement = None
self.__saxHandler.characters(text)
return
def attribute(self, name, value, namespace=EMPTY_NAMESPACE):
self.__currElement.attrs[name] = value
if namespace:
(prefix, local) = SplitQName(name)
if prefix:
self.__currElement.attrs[u"xmlns:"+prefix] = namespace
return
def processingInstruction(self, target, data):
self.__completeTextNode()
if self.__saxHandler:
self.__saxHandler.processingInstruction(target, data)
else:
self.__orphanedNodes.append(('pi', target, data))
return
def comment(self, body):
self.__completeTextNode()
if self.__saxHandler:
self.__saxHandler.comment(body)
else:
self.__orphanedNodes.append(('comment', body))
return
|