######################################################################## # # File Name: XsltFunctions.py # # Docs: http://docs.4suite.org/XSLT/XsltFunctions.py.html # """ WWW: http://4suite.org/XSLT e-mail: support@4suite.org Copyright (c) 1999-2001 Fourthought Inc, USA. All Rights Reserved. See http://4suite.org/COPYRIGHT for license and copyright information """ import cStringIO, os, re, urlparse, urllib import xml.dom.ext from xml.dom import Node from xml.dom.DocumentFragment import DocumentFragment from xml.xpath import CoreFunctions, Conversions, Util, g_extFunctions from xml.xslt import XsltException, Error, XSL_NAMESPACE from xml.xslt import g_extElements from Ft.Lib import Uri from Ft import __version__ def Document(context, object, nodeSet=None): result = [] #Or should it be loading just the imported portion of the stylesheet if called form an imported instruction? sheet = context.currentInstruction.ownerDocument.documentElement baseUri = context.currentInstruction.baseUri if nodeSet: baseUri = getattr(nodeSet[0].ownerDocument or nodeSet[0], 'refUri', baseUri) if nodeSet is None: if type(object) == type([]): for curr_node in object: result = result + Document( context, Conversions.StringValue(curr_node), [curr_node] ) elif object == '': result = [sheet.ownerDocument] sheet.newSource(sheet.ownerDocument, context.processor) #Util.IndexDocument(context.stylesheet.ownerDocument) else: try: #FIXME: Discard fragments before checking for dupes uri = Uri.BASIC_RESOLVER.normalize( Conversions.StringValue(object), baseUri ) if context.documents.has_key(uri): result = [context.documents[uri]] else: try: doc = sheet._docReader.fromUri(uri) except: raise #Util.IndexDocument(doc) context.documents[uri] = doc sheet.newSource(doc, context.processor) result = [doc] except IOError: pass elif type(nodeSet) == type([]): if type(object) == type([]): for curr_node in object: result = result + Document( context, Conversions.StringValue(curr_node), nodeSet ) else: try: #FIXME: Discard fragments before checking for dupes uri = Uri.BASIC_RESOLVER.normalize( Conversions.StringValue(object), baseUri ) if context.documents.has_key(uri): result = [context.documents[uri]] else: doc = sheet._docReader.fromUri(uri) #Util.IndexDocument(doc) context.documents[uri] = doc sheet.newSource(doc, context.processor) result = [doc] except IOError: pass return result def Key(context, qname, keyList): result = [] name = Util.ExpandQName(Conversions.StringValue(qname), namespaces=context.processorNss) doc = context.node.ownerDocument or context.node try: context_key = context.processor.keys[doc] except KeyError: raise XsltException(Error.KEY_WITH_RTF_CONTEXT) if context_key.has_key(name): a_dict = context_key[name] if type(keyList) != type([]): keyList = [keyList] for key in keyList: key = Conversions.StringValue(key) result = result + a_dict.get(key, []) return result def Current(context): return [context.currentNode] def UnparsedEntityUri(context, name): if hasattr(context.node.ownerDoc, '_unparsedEntities'): return context.node.ownerDoc._unparsedEntities.get(name, '') return '' def GenerateId(context, nodeSet=None): if nodeSet is not None and type(nodeSet) != type([]): raise XsltException(Error.WRONG_ARGUMENT_TYPE) if not nodeSet: return 'id' + `id(context.node)` else: node = Util.SortDocOrder(nodeSet)[0] return 'id' + `id(node)` def SystemProperty(context, qname): uri, lname = Util.ExpandQName(Conversions.StringValue(qname), namespaces=context.processorNss) if uri == XSL_NAMESPACE: if lname == 'version': return 1.0 if lname == 'vendor': return "Fourthought Inc." if lname == 'vendor-url': return "http://4Suite.org" elif uri == 'http://xmlns.4suite.org/xslt/env-system-property': return os.environ.get(lname, '') elif uri == 'http://xmlns.4suite.org': if lname == 'version': return __version__ return '' def FunctionAvailable(context, qname): split_name = Util.ExpandQName(Conversions.StringValue(qname), namespaces=context.processorNss) if g_extFunctions.has_key(split_name) or CoreFunctions.CoreFunctions.has_key(split_name): return CoreFunctions.True(context) else: return CoreFunctions.False(context) def ElementAvailable(context, qname): split_name = Util.ExpandQName(Conversions.StringValue(qname), namespaces=context.processorNss) if g_extElements.has_key(split_name) or CoreFunctions.CoreFunctions.has_key(split_name): return CoreFunctions.True(context) else: return CoreFunctions.False(context) def XsltStringValue(object): #def XsltStringValue(object, cache=None): #print "XsltStringValue cache", cache #if cache and cache.has_key(object): #print "found:", cache[object] #return cache[object] if hasattr(object, 'stringValue'): return 1, object.stringValue if hasattr(object, 'nodeType') and object.nodeType == Node.DOCUMENT_NODE: result = '' for node in object.childNodes: result = result + Conversions.CoreStringValue(node)[1] #if cache is not None: cache[object] = result return 1, result return 0, None def XsltNumberValue(object): handled, value = XsltStringValue(object) if handled: return 1, Conversions.NumberValue(value) return 0, None def XsltBooleanValue(object): handled, value = XsltStringValue(object) if handled: return 1, Conversions.BooleanValue(value) return 0, None ##0 decimal-separator ##1 grouping-separator ##2 infinity ##3 minus-sign ##4 NaN ##5 percent ##6 per-mille ##7 zero-digit ##8 digit ##9 pattern-separator def FormatNumber(context, number, formatString, decimalFormatName=None): decimal_format = '' num = Conversions.NumberValue(number) format_string = Conversions.StringValue(formatString) sheet = context.stylesheet or \ context.currentInstruction.ownerDocument.documentElement if decimalFormatName is not None: split_name = Util.ExpandQName(decimalFormatName, namespaces=context.processorNss) decimal_format = sheet.decimalFormats[split_name] else: decimal_format = sheet.decimalFormats[''] from Ft.Lib import routines result = routines.FormatNumber(num, format_string) return result Conversions.g_stringConversions.insert(0, XsltStringValue) Conversions.g_numberConversions.insert(0, XsltNumberValue) Conversions.g_booleanConversions.insert(0, XsltBooleanValue) ExtFunctions = { ('', 'document'): Document, ('', 'key'): Key, ('', 'current'): Current, ('', 'generate-id'): GenerateId, ('', 'system-property'): SystemProperty, ('', 'function-available'): FunctionAvailable, ('', 'element-available'): ElementAvailable, ('', 'string-value'): XsltStringValue, ('', 'format-number'): FormatNumber, ('', 'unparsed-entity-uri'): UnparsedEntityUri }