def Split(context, string, pattern=u' '): ''' Similar to Ft.Xml.Xslt.Exslt.String.Split but does not depend on a XSLT processor -- any XPath context will do. ''' string = StringValue(string) pattern = StringValue(pattern) nodeset = [] frag = context.node.ownerDocument.createDocumentFragment() def addToNodeset(token): text = context.node.ownerDocument.createTextNode(token) nodeset.append(text) return #the following causes a seg fault in cdomlette the second time around elem = context.node.ownerDocument.createElementNS(None, 'token') frag.appendChild(elem) text = context.node.ownerDocument.createTextNode(token) elem.appendChild(text) nodeset.append(elem) if pattern: if string: if pattern == ' ': pattern = None #python normalizes whitespace if pattern is None #addToNodeset(string.split(pattern)[0]) for token in string.split(pattern): addToNodeset(token) else: for ch in string: addToNodeset(token) return nodeset
def Id(context, object): """Function: <node-set> id(<object>)""" id_list = [] if type(object) != type([]): st = StringValue(object) id_list = st.split() else: for n in object: id_list.append(StringValue(n)) doc = context.node.rootNode getElementById = getattr(doc, 'getElementById', None) if not getElementById: #this is from 4suite 1.0a3's version of id(): import warnings warnings.warn("id() function not supported") #We do not (cannot, really) support the id() function return [] nodeset = [] for id in id_list: element = getElementById(id) if element: nodeset.append(element) return Set.Unique(nodeset)
def ParseDateToPyTime(context, date, format=''): """ Inverse of CurrentTime """ import calendar date = StringValue(date) format = StringValue(format) or "%Y-%m-%dT%H:%M:%S" time_tuple = time.strptime(date, format) return "%.3f" % calendar.timegm(time_tuple)
def ParseRDF(context, contents, type='unknown', uri=''): contents = StringValue(contents) type = StringValue(type) uri = StringValue(uri) if not uri: from Ft.Lib import Uuid uri = 'urn:uuid:' + Uuid.UuidAsString(Uuid.GenerateUuid()) nsRevMap = getattr(context.node.ownerDocument, 'nsRevMap', None) schemaClass = getattr(context.node.ownerDocument, 'schemaClass', RxPath.defaultSchemaClass) stmts = RxPath.parseRDFFromString(contents, uri, type) return [RxPath.RxPathDOMFromStatements(stmts, nsRevMap, uri, schemaClass)]
def Test(tester): tester.startTest("CDATA Conversions") isrc = InputSource.DefaultFactory.fromString(test,'rs') dom = tester.test_data['parse'](isrc) NormalizeNode(dom) nodes = Evaluate('//bar/text()', contextNode = dom) tester.compare(2,len(nodes)) tester.compare('normal text',StringValue(nodes[0])) tester.compare('<cdatatext>',StringValue(nodes[1])) tester.compare('<cdatatext>',Evaluate('string(//bar[2]/text())', contextNode = dom)) tester.testDone()
def _getNamesFromURI(context, uri=None): if uri is None: uri = context.node uri = StringValue(uri) qname, namespaceURI, prefix, localName = \ elementNamesFromURI(uri, context.node.ownerDocument.nsRevMap) return qname, namespaceURI, prefix, localName
def Map(context, nodeset, string): if type(nodeset) != type([]): raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'map', "expected node set argument") from Ft.Xml.XPath import parser from Ft.Lib import Set from rx import raccoon mapContext = context.clone() mapContext.size = len(nodeset) mapContext.position = 1 #note: exslt-dyn:map implies that parse exception should be caught and an empty nodeset returned expCache = raccoon.RequestProcessor.expCache xpath = StringValue(string) queryCache = getattr(context.node.ownerDocument, 'queryCache', None) def eval(l, node): mapContext.node = node mapContext.position += 1 mapContext.varBindings[(RXWIKI_XPATH_EXT_NS, 'current')] = node result = RxPath.evalXPath(xpath, mapContext, expCache, queryCache) if type(result) != type([]): if not isinstance(result, unicode): result = unicode(str(result), 'utf8') result = String2NodeSet(mapContext, result) l.extend(result) return l nodeset = reduce(eval, nodeset, []) return Set.Unique(nodeset)
def getURIFromElement(context, nodeset=None): string = None if nodeset is None: node = context.node elif type(nodeset) == type([]): if nodeset: node = nodeset[0] if node.nodeType != Node.ELEMENT_NODE: string = node else: return u'' else: string = nodeset if string is not None: qname = StringValue(string) (prefix, local) = SplitQName(qname) if prefix: try: namespace = context.processorNss[prefix] except KeyError: raise XPath.RuntimeException( XPath.RuntimeException.UNDEFINED_PREFIX, prefix) return namespace + getURIFragmentFromLocal(local) else: return getURIFromElementName(node)
def isType(context, candidate, test): ''' This function returns true if the class specified in the first argument is a subtype of the class specified in the second argument, where each string is treated as the URI reference of a class resource. ''' #design note: follow equality semantics for nodesets if not isinstance(test, list): test = [test] if not isinstance(candidate, list): candidate = [candidate] for node in test: classURI = StringValue(node) for candidateNode in candidate: if context.node.ownerDocument.schema.isCompatibleType( StringValue(candidateNode), classURI): return XTrue return XFalse
def isInstanceOf(context, candidate, test): ''' This function returns true if the resource specified in the first argument is an instance of the class resource specified in the second argument, where each string is treated as the URI reference of a resource. ''' #design note: follow equality semantics for nodesets if not isinstance(test, list): test = [test] if not isinstance(candidate, list): candidate = [candidate] for node in test: classResource = StringValue(node) for candidateNode in candidate: resource = context.node.ownerDocument.findSubject( StringValue(candidateNode)) if resource and resource.matchName(classResource, ''): return XTrue return XFalse
def SystemProperty(context, qname): ''' disable the 'http://xmlns.4suite.org/xslt/env-system-property' namespace (it is a security hole), otherwise call Ft.Xml.Xslt.XsltFunctions.SystemProperty ''' qname = StringValue(qname) if qname: (uri, local) = context.expandQName(qname) if uri == 'http://xmlns.4suite.org/xslt/env-system-property': return u'' return XsltFunctions.SystemProperty(context, qname)
def FileExists(context, uri): path = StringValue(uri) if path.startswith('file:'): path = Uri.UriToOsPath(path) #todo: security hole return Xbool(os.path.exists(path)) else: if path.startswith('path:'): path = path[len('path:'):] for prefix in InputSource.DefaultFactory.resolver.path: if os.path.exists(os.path.join(prefix.strip(), path)): return XTrue return XFalse
def FormatPyTime(context, t, format='%Y-%m-%dT%H:%M:%S'): """ Given a Python timestamp number return a formatted date string. t - a time stamp number, as from Python's time.time() if omitted, use the current time format - Python date format """ if t: t = NumberValue(t) t = time.gmtime(t) else: t = time.gmtime() return time.strftime(StringValue(format), t)
def SerializeRDF(context, resultset, type='rdfxml', nsMapString=None, fixUp=None, fixUpPredicate=None): '''Returns a nodeset containing a RDF serialization of the RxPathDOM nodes contained in resultset parameter. nsMapString is a namespace dictionary encoded as a string in the form of "prefix^uri^prefix^uri..." ''' stmts = [] uri2prefixMap = None if nsMapString: import itertools nslist = StringValue(nsMapString).split('^') uri2prefixMap = dict( itertools.izip(itertools.islice(nslist, 1, None, 2), itertools.islice(nslist, 0, None, 2))) if resultset: if uri2prefixMap is None: uri2prefixMap = resultset[0].rootNode.nsRevMap if resultset[0].nodeName == '#document': resultset = resultset[0].childNodes for n in resultset: nl = [n] if RxPath.isResource(context, nl): preds = n.childNodes elif RxPath.isPredicate(context, nl): preds = nl else: preds = [] #error? for p in preds: stmts.extend(p.getModelStatements()) if (RxPath.isResource(context, p.childNodes) and p.firstChild.isCompound()): #object is a list so add all the list items too stmts.extend(p.firstChild.getModelStatements()) return RxPath.serializeRDF(stmts, type, uri2prefixMap, fixUp, fixUpPredicate)
def instanceof(context, test, cmptype): '''sort of like the "instance of" operator in XPath 2.0''' #todo: do we really need this when there is exsl:object-type cmptype = StringValue(cmptype) if cmptype == 'number': result = isinstance(test, (int, float)) #float elif cmptype == 'string': result = isinstance(test, (unicode, str)) #string elif cmptype == 'node-set': result = isinstance(test, list) #node-set elif cmptype == 'boolean': #result = isinstance(test, (bool, XPath.boolean.BooleanType)) #boolean result = test == 1 or test == 0 elif cmptype == 'object': #true if any thing is not one of the above types result = not isinstance(test, (int, float, unicode, str, list, bool, XPath.boolean.BooleanType)) #boolean else: raise RuntimeError('unknown type specified %s' % cmptype) return Xbool(result)
def DocumentAsText(context, url): ''' Return the contents of url as a string or an empty nodeset if url is an zero length string. If the url resolves to a file thCat contains bytes sequences that are not ascii or utf-8 (e.g. a binary file) this function can not be used in contexts such as xsl:value-of however, an raw xpath expression will return a non-unicode string and thus will work in those contexts. ''' urlString = StringValue(url) if not urlString: return [] #return an empty nodeset #todo: set baseURI = this current context's $_path, #have site resolver use this as the docbase file = InputSource.DefaultFactory.fromUri(urlString) bytes = file.read() file.close() #print 'bytes', bytes[0:100] return bytes
def rdfDocument(context, object, type='unknown', nodeset=None): '''Equivalent to XSLT's document() function except it parses RDF and returns RxPath Document nodes instead of XML Document nodes. The first and third arguments are equivalent to document()'s first and second arguments, respectively, and the second argument is converted to a string that names the format of the RDF being parsed. The format names recognized are the same as the ones used by parseRDFFromString(). ParseException will be raised if the RDF can not be parsed. Note: this is only available in the context of an XSLT processor. ''' type = StringValue(type) oldDocReader = context.processor._docReader class RDFDocReader: def __init__(self, uri2prefixMap, type, schemaClass): self.uri2prefixMap = uri2prefixMap self.type = type self.schemaClass = schemaClass def parse(self, isrc): contents = isrc.stream.read() isrc.stream.close() stmts = parseRDFFromString(contents, isrc.uri, self.type) return RxPathDOMFromStatements(stmts, self.uri2prefixMap, isrc.uri, self.schemaClass) nsRevMap = getattr(context.node.ownerDocument, 'nsRevMap', None) schemaClass = getattr(context.node.ownerDocument, 'schemaClass', defaultSchemaClass) context.processor._docReader = RDFDocReader(nsRevMap, type, defaultSchemaClass) from Ft.Xml.Xslt import XsltFunctions result = XsltFunctions.Document(context, object, nodeset) context.processor._docReader = oldDocReader return result
def addRxdom2Model(rootNode, model, rdfdom=None, thisResource=None, scope=''): '''given a DOM of a RXML document, iterate through it, adding its statements to the specified 4Suite model Note: no checks if the statement is already in the model ''' nsMap = {None: RX_NS, 'rx': RX_NS} #todo: bug! revNsMap doesn't work with 2 prefixes one ns #revNsMap = dict(map(lambda x: (x[1], x[0]), nsMap.items()) )#reverse namespace map #rxNSPrefix = revNsMap[RX_NS] rxNSPrefix = [x[0] for x in nsMap.items() if x[1] == RX_NS] if not rxNSPrefix: #if RX_NS is missing from the nsMap add the 'rx' prefix if not already specified rxNSPrefix = [] if not nsMap.get('rx'): nsMap['rx'] = RX_NS rxNSPrefix.append('rx') #if no default prefix was set, also make RX_NS the default if None not in nsMap: nsMap[None] = RX_NS rxNSPrefix.append(None) if not nsMap.get('rdf'): nsMap['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' if not nsMap.get('rdfs'): nsMap['rdfs'] = 'http://www.w3.org/2000/01/rdf-schema#' for s in rootNode.childNodes: if s.nodeType != s.ELEMENT_NODE: continue if matchName(s, rxNSPrefix, 'rx'): #optional root element rootNode = s else: break for s in rootNode.childNodes: if s.nodeType != s.ELEMENT_NODE: continue if matchName(s, rxNSPrefix, 'prefixes'): for nsElem in s.childNodes: if nsElem.nodeType != nsElem.ELEMENT_NODE: continue if matchName(nsElem, rxNSPrefix, RX_META_DEFAULT): ns = None #'' else: ns = nsElem.localName from Ft.Xml.XPath.Conversions import StringValue nsMap[ns] = StringValue(nsElem).strip() #revNsMap[nsElem.stringValue] = ns continue elif matchName(s, rxNSPrefix, 'res-query'): assert rdfdom if rdfdom: result = rdfdom.evalXPath( s.getAttributeNS(EMPTY_NAMESPACE, 'id'), nsMap) if isinstance(result, (type(''), type(u''))): resources = [result] else: resources = map( lambda x: x.getAttributeNS(RDF_MS_BASE, 'about'), result) else: resources = [] else: resource, typeName = getResource(s, rxNSPrefix, nsMap, thisResource) if typeName: model.addStatement( Statement(resource, RDF_MS_BASE + 'type', typeName, OBJECT_TYPE_RESOURCE, scope)) resources = [resource] for resource in resources: addResource(model, scope, resource, s, rxNSPrefix, nsMap, thisResource, len(resources) > 1) return nsMap
def GenerateBnode(context, name=None): if name is not None: name = StringValue(name) return RxPath.generateBnode(name)
if BuiltInExtFunctions.ExtFunctions.has_key((FT_EXT_NAMESPACE, 'spawnv')): for functionDict in extFuncDicts: del functionDict[(FT_EXT_NAMESPACE, 'spawnv')] del functionDict[(FT_EXT_NAMESPACE, 'system')] del functionDict[(FT_EXT_NAMESPACE, 'env-var')] #1.0a4 version of 4Suite deleted deprecated functions, so re-add the ones we still use if not BuiltInExtFunctions.ExtFunctions.has_key( (FT_EXT_NAMESPACE, 'escape-url')): for functionDict in extFuncDicts: #4Suite 1.0a4's pytime-to-exslt is broken, reimplement it: functionDict[(FT_EXT_NAMESPACE, 'pytime-to-exslt')] = lambda context, t=None:\ t and unicode(Time.FromPythonTime(NumberValue(t))) or unicode(Time.FromPythonTime()) #todo: we should stop using this and use exslt:string's encode-uri functionDict[(FT_EXT_NAMESPACE, 'escape-url' )] = lambda context, uri: urllib.quote(StringValue(uri)) if Exslt.ExtElements.has_key(("http://exslt.org/common", 'document')): #document only can write to the local files system and does use our secure URI resolver del Exslt.ExtElements[("http://exslt.org/common", 'document')] def SystemProperty(context, qname): ''' disable the 'http://xmlns.4suite.org/xslt/env-system-property' namespace (it is a security hole), otherwise call Ft.Xml.Xslt.XsltFunctions.SystemProperty ''' qname = StringValue(qname) if qname: (uri, local) = context.expandQName(qname)