def SubstringAfter(context, outer, inner): """Function: <string> substring-after(<string>, <string>)""" outer = Conversions.StringValue(outer) inner = Conversions.StringValue(inner) index = string.find(outer, inner) if index == -1: return '' return outer[index + len(inner):]
def SubstringBefore(context, outer, inner): """Function: <string> substring-before(<string>, <string>)""" outer = Conversions.StringValue(outer) inner = Conversions.StringValue(inner) index = string.find(outer, inner) if index == -1: return '' return outer[:index]
def Replace(context, old, new, arg=None): """Do a global search and replace of the string contents""" if not arg: arg = context.node arg = Conversions.StringValue(arg) old = Conversions.StringValue(old) new = Conversions.StringValue(new) return string.replace(arg, old, new)
def Contains(context, outer, inner): """Function: <string> contains(<string>, <string>)""" outer = Conversions.StringValue(outer) inner = Conversions.StringValue(inner) if len(inner) == 1: return inner in outer and boolean.true or boolean.false else: return string.find(outer, inner) != -1 and boolean.true or boolean.false
def Document(context, object, nodeSet=None): result = [] baseUri = getattr(context.stylesheet, 'baseUri', '') #if baseUri: baseUri= baseUri + '/' if nodeSet: baseUri = getattr(nodeSet[0], 'baseUri', 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 = [context.stylesheet.ownerDocument] context.stylesheet.newSource(context.stylesheet.ownerDocument, context.processor) #Util.IndexDocument(context.stylesheet.ownerDocument) else: try: #FIXME: Discard fragments before checking for dupes uri = Conversions.StringValue(object) if context.documents.has_key(uri): result = context.documents[uri] else: try: doc = context.stylesheet._docReader.fromUri( uri, baseUri=baseUri) except: raise #Util.IndexDocument(doc) context.stylesheet.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: uri = Conversions.StringValue(object) #FIXME: Discard fragments before checking for dupes if context.documents.has_key(uri): result = context.documents[uri] else: doc = context.stylesheet._docReader.fromUri( uri, baseUri=baseUri) #Util.IndexDocument(doc) context.stylesheet.newSource(doc, context.processor) result = [doc] except IOError: pass return result
def evaluate(self, context): if self._op == "=": true = boolean.true false = boolean.false else: true = boolean.false false = boolean.true lrt = self._left.evaluate(context) rrt = self._right.evaluate(context) lType = type(lrt) rType = type(rrt) if lType == list == rType: # Node set to node set for right_curr in rrt: right_curr = Conversions.StringValue(right_curr) for left_curr in lrt: if right_curr == Conversions.StringValue(left_curr): return true return false elif lType == list or rType == list: func = None if lType == list: set = lrt val = rrt else: set = rrt val = lrt if type(val) in NumberTypes: func = Conversions.NumberValue elif boolean.IsBooleanType(val): func = Conversions.BooleanValue elif type(val) == bytes: func = Conversions.StringValue else: # Deal with e.g. RTFs val = Conversions.StringValue(val) func = Conversions.StringValue for n in set: if func(n) == val: return true return false if boolean.IsBooleanType(lrt) or boolean.IsBooleanType(rrt): rt = Conversions.BooleanValue(lrt) == Conversions.BooleanValue(rrt) elif lType in NumberTypes or rType in NumberTypes: rt = Conversions.NumberValue(lrt) == Conversions.NumberValue(rrt) else: rt = Conversions.StringValue(lrt) == Conversions.StringValue(rrt) if rt: # Due to the swapping of true/false, true might evaluate to 0 # We cannot compact this to 'rt and true or false' return true return false
def Key(context, qname, keyList): result = [] name = Util.ExpandQName(Conversions.StringValue(qname), namespaces=context.processorNss) if context.stylesheet.keys.has_key(name): a_dict = context.stylesheet.keys[name] if type(keyList) != type([]): keyList = [keyList] for key in keyList: key = Conversions.StringValue(key) result = result + a_dict.get(key, []) return result
def Translate(context, source, fromChars, toChars): """Function: <string> translate(<string>, <string>, <string>)""" source = Conversions.StringValue(source) fromChars = Conversions.StringValue(fromChars) toChars = Conversions.StringValue(toChars) # string.maketrans/translate do not handle unicode translate = {} for from_char, to_char in map(None, fromChars, toChars): translate[ord(from_char)] = to_char result = reduce(lambda a, b, t=translate: a + (t.get(ord(b), b) or ''), source, '') return result
def instantiate(self, context, processor): origState = context.copy() context.setNamespaces(self._nss) name = self._name.evaluate(context) namespace = self._namespace.evaluate(context) (prefix, local) = xml.dom.ext.SplitQName(name) if not namespace: if prefix: namespace = context.processorNss[prefix] if local == 'xmlns': name = prefix #FIXME: Add error checking of child nodes processor.pushResult() for child in self.childNodes: context = child.instantiate(context, processor)[0] rtf = processor.popResult() value = Conversions.StringValue(rtf) processor.writers[-1].attribute(name, value, namespace) processor.releaseRtf(rtf) context.set(origState) return (context, )
def String(context, object=None): """Function: <string> string(<object>?)""" if type(object) in g_stringTypes: return object if object is None: object = [context.node] return Conversions.StringValue(object)
def Match(context, pattern, arg=None): """Do a regular expression match against the argument""" if not arg: arg = context.node arg = Conversions.StringValue(arg) bool = re.match(pattern, arg) and boolean.true or boolean.false return bool
def SearchRePy20(context, pattern, arg=None): """Do a regular expression search against the argument (i.e. get all matches)""" if not arg: arg = context.node arg = Conversions.StringValue(arg) proc = context.processor matches_nodeset = [] _re = re.compile(pattern) _match = _re.search(arg) while _match: proc.pushResult() proc.writers[-1].startElement("Match", EMPTY_NAMESPACE) _groups = _match.groups() # .groups() return empty tuple when the pattern did not do grouping if not _groups: _groups = tuple(_match.group()) for group in _groups: proc.writers[-1].startElement("Group", EMPTY_NAMESPACE) # MatchObject groups return None if unmatched # unlike .findall() returning empty strings proc.writers[-1].text(group or "") proc.writers[-1].endElement("Group") proc.writers[-1].endElement("Match") frag = proc.popResult() context.rtfs.append(frag) matches_nodeset.append(frag.childNodes[0]) _match = _re.search(arg, _match.end()) return matches_nodeset
def Map(context, funcname, *nodesets): """ Apply the function serially over the given node sets. In iteration i, the function is passed N parameters where N is the number of argument node sets. Each parameter is a node set of size 1, whose node is the ith node of the corresponding argument node set. The return value is a node set consisting of a series of result-tree nodes, each of which is a text node whose value is the string value of the result of the ith function invocation. Warning: this function uses the implied ordering of the node set Based on its implementation as a Python list. But in reality There is no reliable ordering of XPath node sets. In other words, this function is voodoo. """ (prefix, local) = ExpandQName(funcname, namespaces=context.processorNss) func = g_extFunctions.get(expanded) or CoreFunctions.CoreFunctions.get( expanded, None ) if not func: raise Exception("Dynamically invoked function %s not found." % funcname) flist = [f] * len(nodesets) lf = lambda x, f, *args: f(*args) retlist = list(map(*(lf, flist) + nodesets)) proc = context.processor result_nodeset = [] for ret in retlist: proc.pushResult() proc.writers[-1].text(Conversions.StringValue(ret)) frag = proc.popResult() context.rtfs.append(frag) result_nodeset.append(frag.childNodes[0]) return result_nodeset
def Concat(context, *args): """Function: <string> concat(<string>, <string>, ...)""" if len(args) < 1: raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'concat', _("at least 2 arguments expected")) return reduce(lambda a, b, c=context: a + Conversions.StringValue(b), args, '')
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 instantiate(self, context, processor, nodeList=None, specList=None): if nodeList is None: nodeList = [] if specList is None: specList = [] origState = context.copy() context.setNamespaces(self._nss) if self._data_type: data_type = self._data_type.evaluate(context) if data_type not in ['text', 'number']: raise XsltException(Error.ILLEGAL_SORT_DATA_TYPE_VALUE) else: data_type = 'text' if self._case_order: case_order = self._case_order.evaluate(context) if case_order not in ['upper-first', 'lower-first']: raise XsltException(Error.ILLEGAL_SORT_CASE_ORDER_VALUE) else: case_order = 'lower-first' if self._order: order = self._order.evaluate(context) if order not in ['ascending', 'descending']: raise XsltException(Error.ILLEGAL_SORT_ORDER_VALUE) else: order = 'ascending' keys = [] node_dict = {} pos = 1 size = len(nodeList) tempState = context.copyNodePosSize() for node in nodeList: context.setNodePosSize((node, pos, size)) result = self._expr.evaluate(context) key = Conversions.StringValue(result) if not key in keys: keys.append(key) if node_dict.has_key(key): node_dict[key].append(node) else: node_dict[key] = [node] pos = pos + 1 context.setNodePosSize(tempState) keys.sort(lambda x, y, o=order, d=data_type, c=case_order: Cmp( x, y, o, d, c)) sorted_list = [] for key in keys: sub_list = node_dict[key] if len(sub_list) > 1 and specList: sub_list = specList[0].instantiate(context, processor, sub_list, specList[1:])[1] sorted_list = sorted_list + sub_list context.set(origState) return (context, sorted_list)
def evaluate(self, context): result = '' expansions = map( lambda x, c=context: Conversions.StringValue(x.evaluate(c)), self._parsedParts) for i in range(len(self._parsedParts)): result = result + self._plainParts[i] + expansions[i] result = result + self._plainParts[-1] return result
def distinct(context, nodeset): if type(nodeset) != type([]): raise Exception("'distinct' parameter must be of type node-set!") nodes = {} for node in nodeset: nodes[Conversions.StringValue(node)] = node return list(nodes.values())
def split(context, arg, delim=None): doc = context.node while doc.parentNode: doc = doc.parentNode nodeset = [] for token in string.split(Conversions.StringValue(arg), delim): nodeset.append(doc.createTextNode(token)) return nodeset
def Id(context, object): """Function: <node-set> id(<object>)""" id_list = [] if type(object) != type([]): st = Conversions.StringValue(object) id_list = string.split(st) else: for n in object: id_list.append(Conversions.StringValue(n)) rt = [] for id in id_list: doc = context.node.ownerDocument or context.node elements = Util.ElementsById(doc.documentElement, id) if len(elements) > 1: raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'id', _("argument not unique")) elif elements: # Must be 1 rt.append(elements[0]) return rt
def FormatNumber(context, number, formatString, decimalFormatName=None): decimal_format = '' num = Conversions.NumberValue(number) format_string = Conversions.StringValue(formatString) if decimalFormatName is not None: split_name = Util.ExpandQName(decimalFormatName, namespaces=context.processorNss) decimal_format = context.stylesheet.decimalFormats[split_name] else: decimal_format = context.stylesheet.decimalFormats[''] from Ft.Lib import routines result = routines.FormatNumber(num, format_string) return result
def instantiate(self, context, processor): #original = context.processorNss original = context.copy() context.processorNss = self._nss result = self._expr.evaluate(context) text = Conversions.StringValue(result) if self._disable_output_escaping: processor.writers[-1].text(text, escapeOutput=0) else: processor.writers[-1].text(text) #context.processorNss = original context.set(original) return (context, )
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 Substring(context, st, start, end=None): """Function: <string> substring(<string>, <number>, <number>?)""" st = Conversions.StringValue(st) start = Conversions.NumberValue(start) if start is NaN: return '' start = int(round(start)) start = start > 1 and start - 1 or 0 if end is None: return st[start:] end = Conversions.NumberValue(end) if start is NaN: return st[start:] end = int(round(end)) return st[start:start + end]
def instantiate(self, context, processor): origState = context.copy() context.setNamespaces(self._nss) #FIXME: Add error checking of child nodes processor.pushResult() for child in self.childNodes: context = child.instantiate(context, processor)[0] result = processor.popResult() data = Conversions.StringValue(result) processor.writers[-1].comment(data) processor.releaseRtf(result) context.set(origState) return (context, )
def instantiate(self, context, processor): origState = context.copy() context.setNamespaces(self._nss) expResult = self._expr.evaluate(context) if hasattr(expResult, "nodeType") and expResult.nodeType in g_xsltRecognizedNodes: expResult = [expResult] if type(expResult) == type([]): for child in expResult: self.__copyNode(processor, child) else: st = Conversions.StringValue(expResult) processor.writers[-1].text(st) context.set(origState) return (context, )
def Lang(context, lang): """Function: <boolean> lang(<string>)""" lang = string.upper(Conversions.StringValue(lang)) node = context.node while node: lang_attr = filter(lambda x: x.name == 'xml:lang' and x.value, node.attributes.values()) value = lang_attr and lang_attr[0].nodeValue or None if value: # See if there is a suffix index = string.find(value, '-') if index != -1: value = value[:index] value = string.upper(value) return value == lang and boolean.true or boolean.false node = node.nodeType == Node.ATTRIBUTE_NODE and node.ownerElement or node.parentNode return boolean.false
def instantiate(self, context, processor): origState = context.copy() context.setNamespaces(self._nss) processor.pushResult() for child in self.childNodes: context = child.instantiate(context, processor)[0] result = processor.popResult() msg = Conversions.StringValue(result) processor.releaseRtf(result) if self._terminate == 'yes': raise XsltException(Error.STYLESHEET_REQUESTED_TERMINATION, msg) else: processor.xslMessage(msg) context.set(origState) return (context,)
def instantiate(self, context, processor): origState = context.copy() context.setNamespaces(self._nss) target = self._target.evaluate(context) #FIXME: Add error checking of child nodes processor.pushResult() for child in self.childNodes: context = child.instantiate(context, processor)[0] result = processor.popResult() processor.writers[-1].processingInstruction( target, Conversions.StringValue(result)) processor.releaseRtf(result) context.set(origState) return (context, )
def SearchRe(context, pattern, arg=None): """Do a regular expression search against the argument (i.e. get all matches)""" if not arg: arg = context.node arg = Conversions.StringValue(arg) matches = re.findall(pattern, arg) proc = context.processor matches_nodeset = [] for groups in matches: proc.pushResult() proc.writers[-1].startElement("Match", EMPTY_NAMESPACE) if type(groups) != type(()): groups = (groups,) for group in groups: proc.writers[-1].startElement("Group", EMPTY_NAMESPACE) proc.writers[-1].text(group) proc.writers[-1].endElement("Group") proc.writers[-1].endElement("Match") frag = proc.popResult() context.rtfs.append(frag) matches_nodeset.append(frag.childNodes[0]) return matches_nodeset