def prepare(self, element, value): if value is None: return self.default if not value: raise XsltException(Error.INVALID_NCNAME_ATTR, value) if ':' in value: raise XsltException(Error.INVALID_NCNAME_ATTR, value) return value
def prepare(self, element, value): if value is None: return self.default if not value: raise XsltException(Error.INVALID_PREFIX_ATTR, value) if ':' in value: raise XsltException(Error.INVALID_PREFIX_ATTR, value) if value == '#default': value = None return value
def prepare(self, element, value): if value is None: return self.default if self._isNsName and \ value == XML_NAMESPACE or value == XMLNS_NAMESPACE: raise XsltException(Error.INVALID_NS_URIREF_ATTR, value) return value
def prepare(self, element, value): if value is None: return self.default try: return float(value or self.default) except: raise XsltException(Error.INVALID_NUMBER_ATTR, value)
def _finalize(self, method): try: writerClass = self._methods[method] except KeyError: if method[0] is None: # display only localName if in the null namespace method = method[1] raise XsltException(Error.UNKNOWN_OUTPUT_METHOD, str(method)) else: self._outputParams.setDefault('method', method) if writerClass is XmlWriter.XmlWriter and \ self._outputParams.cdataSectionElements: writerClass = XmlWriter.CdataSectionXmlWriter # Save our instance variables for use after reinitializing stream, stack = self._stream, self._stack del self._stream del self._stack self.__class__ = writerClass writerClass.__init__(self, self._outputParams, stream) # Do the saved callbacks self.startDocument() newline = 0 for cmd, args, kw in stack: if newline: self.text(u'\n') else: newline = 1 getattr(self, cmd)(*args, **kw) return
def parseAVT(self, avt): """DEPRECATED: specify an attribute in 'legalAttrs' instead.""" if avt is None: return None try: return AttributeValueTemplate.AttributeValueTemplate(avt) except SyntaxError, error: raise XsltException(Error.INVALID_AVT, avt, self.baseUri, self.lineNumber, self.columnNumber, str(error))
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default elif not IsQName(value): raise XsltException(Error.INVALID_QNAME_ATTR, value) return SplitQName(value)
def attribute(self, name, value, namespace=EMPTY_NAMESPACE): """ add an attribute to an element name - the qualified name of the attribute value - the attribute value: must be Unicode namespace - must be Unicode or Ft.Xml.EMPTY_NAMESPACE (the default) Strives for "sanity". For brilliant definition thereof, c.f. Joe English http://lists.xml.org/archives/xml-dev/200204/msg00170.html Uses terminology from that article See also discussions starting http://lists.fourthought.com/pipermail/4suite-dev/2003-March/001294.html http://lists.fourthought.com/pipermail/4suite-dev/2003-March/001283.html Note: attribute output is computed as invoked. This means that the ugly case attribute(u"foo", u"bar", "http://some-ns/") attribute(u"x:foo", u"baz", "http://some-ns/") will result in the ugly xmlns:org.4suite.4xslt.ns0="http://some-ns/" org.4suite.4xslt.ns0:foo="baz" The user can easily correct this by reversing the order of the calls """ if not self._elementName: if self._inFirstElement: raise XsltException(Error.ATTRIBUTE_ADDED_TOO_LATE) else: raise XsltException(Error.ATTRIBUTE_ADDED_TO_NON_ELEMENT) (prefix, local) = SplitQName(name) if namespace != EMPTY_NAMESPACE: new_name = self._updateNamespace(prefix, namespace, local, forcePrefix=1) if new_name: name = new_name else: name = local self._attributes[name] = value return
def parsePattern(self, pattern): """DEPRECATED: specify an attribute in 'legalAttrs' instead.""" if pattern is None: return None p = _xpattern_parser.new() try: return p.parse(pattern) except SyntaxError, error: raise XsltException(Error.INVALID_PATTERN, pattern, self.baseUri, self.lineNumber, self.columnNumber, str(error))
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default elif not value: raise XsltException(Error.QNAME_BUT_NOT_NCNAME, value) try: index = value.index(':') except ValueError: raise XsltException(Error.QNAME_BUT_NOT_NCNAME, value) prefix, local = value[:index], value[index+1:] try: namespace = element.namespaces[prefix] except KeyError: raise XsltRuntimeException(Error.UNDEFINED_PREFIX, element, prefix) return (namespace, local)
def parseExpression(self, expression): """DEPRECATED: specify an attribute in 'legalAttrs' instead.""" if expression is None: return None p = _xpath_parser.new() try: return p.parse(expression) except SyntaxError, error: raise XsltException(Error.INVALID_EXPRESSION, expression, self.baseUri, self.lineNumber, self.columnNumber, str(error))
def __init__(self, source, validator=None, element=None): self.source = source self.validator = validator self.element = element try: # parts is a list of unicode and/or parsed XPath parts = _AvtParser.parse(source) except SyntaxError, exc: raise XsltException(Error.AVT_SYNTAX)
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default try: expression = _xpath_parser.parse(value) except SyntaxError, error: raise XsltException(Error.INVALID_EXPRESSION, value, element.baseUri, element.lineNumber, element.columnNumber, str(error))
def prepare(self, element, value): if value is None: return _ConstantValue(self.reprocess(element, self.default)) elif '{' not in value and '}' not in value: return _ConstantValue(self.reprocess(element, value)) try: return AttributeValueTemplate(value, self, element) except SyntaxError, error: # an error from the XPath parser raise XsltException(Error.INVALID_AVT, value, element.baseUri, element.lineNumber, element.columnNumber, str(error))
def prepare(self, element, value): if value is None: if self.default: value = self.default else: return None try: return _xpattern_parser.parse(value) except SyntaxError, error: raise XsltException(Error.INVALID_PATTERN, value, element.baseUri, element.lineNumber, element.columnNumber, str(error))
def prepare(self, element, value): if value is None: return self.default if value not in self.values: # check for a AttributeInfo instance allowed = filter(lambda v, t=type(self): type(v) is t, self.values) for info in allowed: try: allowed.prepare(element, value) return value except: pass # if we get here it is an error raise XsltException(Error.INVALID_ATTR_CHOICE, value, str(self)) return value
def prepare(self, element, value): if value is None: if self.default is None: return None value = self.default elif not IsQName(value): raise XsltException(Error.INVALID_QNAME_ATTR, value) prefix, local = SplitQName(value) if prefix: try: namespace = element.namespaces[prefix] except KeyError: raise XsltRuntimeException(Error.UNDEFINED_PREFIX, element, prefix) else: namespace = EMPTY_NAMESPACE return (namespace, local)
class XsltElement(XsltNode): category = CategoryTypes.RESULT_ELEMENT content = ContentInfo.Template validator = ContentInfo.Validator(content) legalAttrs = None # this means no error checking or defaulting def __init__(self, root, namespaceUri, localName, baseUri): self.root = root self.baseUri = baseUri self.expandedName = (namespaceUri, localName) self.children = [] self.attributes = {} self.namespaces = {} return def insertChild(self, index, child): """INTERNAL USE ONLY""" self.children.insert(index, child) child.parent = self if child.doesSetup: child.setup() return def appendChild(self, child): """INTERNAL USE ONLY""" self.children.append(child) child.parent = self if child.doesSetup: child.setup() return def parseAVT(self, avt): """DEPRECATED: specify an attribute in 'legalAttrs' instead.""" if avt is None: return None try: return AttributeValueTemplate.AttributeValueTemplate(avt) except SyntaxError, error: raise XsltException(Error.INVALID_AVT, avt, self.baseUri, self.lineNumber, self.columnNumber, str(error)) except XsltException, error: raise XsltException(Error.INVALID_AVT, avt, self.baseUri, self.lineNumber, self.columnNumber, error.args[0])
def _setupNamespaceAliases(self, aliases): merged = {} for alias in aliases: stylesheet_ns = alias.namespaces[alias._stylesheet_prefix] if stylesheet_ns in merged: existing = merged[stylesheet_ns].importIndex if existing < alias.importIndex: merged[stylesheet_ns] = alias elif existing == alias.importIndex: raise XsltException(Error.DUPLICATE_NAMESPACE_ALIAS, alias._stylesheet_prefix) else: merged[stylesheet_ns] = alias for stylesheet_ns, alias in merged.items(): namespace = alias.namespaces[alias._result_prefix] prefix = alias._result_prefix self.namespaceAliases[stylesheet_ns] = (namespace, prefix) return
def __init__(self, format): self._format = format groups = _token_re.findall(format) if not groups: raise XsltException(Error.ILLEGAL_NUMBER_FORMAT_VALUE, self._format) self.prefix = groups[0][0] self.suffix = groups[-1][2] toks = self.tokens = [] seps = self.separators = [] for group in groups[:-1]: toks.append(group[1]) seps.append(group[2]) toks.append(groups[-1][1]) if not seps: seps.append('.') return
def setup(self): # Check for deprecated f:node-set if (FT_EXT_NAMESPACE, 'node-set') in self.attributes: warnings.warn( "You are using the deprecated f:node-set attribute" " on xsl:variable or xsl:param. Please switch to" " using exslt:node-set", DeprecationWarning, 2) # check for a bad binding if self._select and self.children: raise XsltException(Error.VAR_WITH_CONTENT_AND_SELECT, self._name) # See the bottom of this file for these helper "nodes" binding_save = self.parent.children[0] if not isinstance(binding_save, PushVariablesNode): # varBindings not yet saved for this level in the stylesheet tree parent = self.parent binding_save = PushVariablesNode(parent.root, parent.baseUri) parent.insertChild(0, binding_save) parent.root.primeInstructions.append(binding_save) return
def _parseSrc(self, isrc, features, properties): self._input_source = isrc parser = Sax.CreateParser() parser.setContentHandler(self) for featurename, value in features: parser.setFeature(featurename, value) # Always set whitespace rules property parser.setProperty(Sax.PROPERTY_WHITESPACE_RULES, STYLESHEET_WHITESPACE_RULES) for propertyname, value in properties: parser.setProperty(propertyname, value) try: parser.parse(isrc) except SAXParseException, e: e = e.getException() or e if isinstance(e, XsltException): raise e raise XsltException(Error.STYLESHEET_PARSE_ERROR, isrc.uri, e)
def _computeGlobalVar(self, vname, context, processed, deferred, overriddenParams, processor): vnode = self._topVariables[0][vname] if vnode in deferred: raise XsltException(Error.CIRCULAR_VAR, vname[0], vname[1]) if vnode in processed: return # Is it an <xsl:param>? # expandedName is a tuple (namespace-uri, local-name) if vnode.expandedName[1][0] == 'p': if vname in overriddenParams: context.varBindings[vname] = overriddenParams[vname] else: finished = 0 while not finished: orig_depth = len(processor.writers) try: vnode.instantiate(context, processor) finished = 1 except XPath.RuntimeException, e: if e.errorCode == XPath.RuntimeException.UNDEFINED_VARIABLE: #Remove any aborted and possibly unbalanced #outut handlers on the stack depth = len(processor.writers) for i in xrange(depth - orig_depth): processor.writers.pop() #Defer the current and try evaluating the #one that turned up undefined deferred.append(vnode) self._computeGlobalVar((e.params[0], e.params[1]), context, processed, deferred, overriddenParams, processor) deferred.remove(vnode) else: raise #Set up so that later stylesheets will get overridden by #parameter values set in higher-priority stylesheets overriddenParams[vname] = context.varBindings[vname]
def _setupDecimalFormats(self, decimal_formats): for df in decimal_formats: name, format = df.getFormatInfo() existing = self.decimalFormats.get(name) if existing and existing != format: # conflicting formats if name: # name is (namespace-uri, local-name) if name[0]: name = df.namespaces[name[0]] + ':' + name[1] else: name = name[1] else: name = '#default' raise XsltException(Error.DUPLICATE_DECIMAL_FORMAT, name) self.decimalFormats[name] = format if None not in self.decimalFormats: # no default format specified self.decimalFormats[None] = ('.', ',', 'Infinity', '-', 'NaN', '%', unichr(0x2030), '0', '#', ';') return
def format(self, numbers, groupSize, groupSeparator): result = [] zipped = map(None, numbers, self.tokens, self.separators) last_separator = self.prefix for number, token, separator in zipped[:len(numbers)]: if number < 0: number = 0 result.append(last_separator) token = token or self.tokens[-1] last_separator = separator or self.separators[-1] if token[-1] == '1': result.append( self._numeric(number, len(token), groupSize, groupSeparator)) elif re.match('[A-HJ-Za-hj-z]$', token): result.append(self._alpha(number, token[0])) elif token in ('I', 'i'): result.append(self._roman(number, token.islower())) else: raise XsltException(Error.ILLEGAL_NUMBER_FORMAT_VALUE, self._format) result.append(self.suffix) return u''.join(result)
def setup(self): if not self.children: raise XsltException(Error.CHOOSE_REQUIRES_WHEN) return
def _setupTemplates(self, templates): named_tpls = self.namedTemplates match_tpls = self.matchTemplates shortcuts = [] for template, position in zip(templates, xrange(len(templates))): # A 'shortcut' is (sort_key, template_info) (shorts, name) = template.getTemplateInfo(position) if name: # for call-templates existing = named_tpls.get(name) if existing: if existing.importIndex == template.importIndex: raise XsltException(Error.DUPLICATE_NAMED_TEMPLATE, name) elif existing.importIndex > template.importIndex: pass else: # The new template has a higher import precedence # so replace what was already there. named_tpls[name] = template else: # The first occurrence of a template with this name. named_tpls[name] = template shortcuts.extend(shorts) # Sort using the sort key, where it is: # (<import precedence>, <template priority>, <stylesheet position>) shortcuts.sort() # We want the highest numbers first shortcuts.reverse() # Make the lookup tables. A lookup table is first keyed by mode, # then keyed by node type, then, if an element, keyed by expanded name for sort_key, template_info in shortcuts: mode, pattern_info, (node_type, expanded_name) = template_info # Save the sort key for use in matching pattern_info = (sort_key, pattern_info) mode_table = match_tpls.get(mode) if not mode_table: mode_table = match_tpls[mode] = {} type_table = mode_table.get(node_type) if not type_table: if node_type == Node.ELEMENT_NODE: # Elements are further keyed by expanded name type_list = [pattern_info] mode_table[node_type] = {expanded_name : type_list} else: mode_table[node_type] = [pattern_info] elif node_type == Node.ELEMENT_NODE: # Elements are further keyed by expanded name type_list = type_table.get(expanded_name) if not type_list: type_table[expanded_name] = [pattern_info] else: type_list.append(pattern_info) else: # Every other node type gets lumped into a single list # for that node type type_table.append(pattern_info) #self._printMatchTemplates() return
def prepare(self, element, value): if value is None: return self.default and self.default == 'yes' elif value not in ['yes', 'no']: raise XsltException(Error.INVALID_ATTR_CHOICE, value, str(self)) return value == 'yes'
def applyTemplates(self, context, processor, params=None, maxImport=None): # Set the current node for this template application save_current = context.currentNode node = context.currentNode = context.node context.stylesheet = self #print #print "#" * 60 #print "finding template for node", repr(context.node) mode_table = self.matchTemplates.get(context.mode) if not mode_table: # No patterns defined in this mode return 0 patterns = [] node_type = node.nodeType if node_type == Node.ELEMENT_NODE: table = mode_table.get(node_type) if table: key = (node.namespaceURI, node.localName) # First use those template which could match this expanded name patterns.extend(table.get(key, [])) # Then add those that are wildcard tests ('*' and 'prefix:*') patterns.extend(table.get(None, [])) else: patterns.extend(mode_table.get(node_type, [])) # For any node type add those patterns that don't have a distinct type: # node(), id() and key() patterns patterns.extend(mode_table.get(None, [])) # Early exit for no matches if not patterns: return 0 # If this is called from apply-imports, remove those patterns # with a higher import precedence than what was specified. if maxImport is not None: patterns = filter(lambda x, m=maxImport: x[0][0] < m, patterns) # Since the patterns may come from different tables, resort them patterns.sort() patterns.reverse() # highest numbers first if 1: # recovery_method == Recovery.SILENT # (default until recovery behaviour is selectable) # Just use the first matching pattern since they are # already sorted in descending order. for sort_key, (pattern, axis_type, template) in patterns: context.processorNss = template.namespaces if pattern.match(context, context.node, axis_type): # let Python collect this list to reduce memory usage del patterns # Make sure the template starts with a clean slate current_variables = context.varBindings context.varBindings = self.globalVars try: template.instantiate(context, processor, params) finally: context.currentNode = save_current context.varBindings = current_variables return 1 else: # recovery_method in (Recovery.WARNING, Recovery.NONE) # Find all templates that match the context node # Use the import index, priority and position from the last # possible matching pattern as starting points. highest_import, highest_priority, last_position = patterns[-1][0] matches = [] for sort_key, (pattern, axis_type, template) in patterns: import_index, priority, position = sort_key if import_index < highest_import or \ (import_index == highest_import and priority < highest_priority): # Passed the point of possible conflicts, we can stop break context.processorNss = template.namespaces if pattern.match(context, context.node, axis_type): matches.append((template, pattern)) if len(matches) > 1: # Report the template conflicts locations = [] for template, pattern in matches: locations.append((template.baseUri, template.lineNumber, template.columnNumber, repr(pattern))) # Sort them based on position locations.sort() locations = [ MessageSource.TEMPLATE_CONFLICT_LOCATION % location for location in locations ] exception = XsltException(Error.MULTIPLE_MATCH_TEMPLATES, context.node, '\n'.join(locations)) if 1: # recovery_method == Recovery.WARNING processor.warning(str(exception)) else: raise exception if matches: template = matches[0][0] # let Python collect these list to reduce memory usage del patterns del matches # Since the patterns were sorted to start with, use the first context.processorNss = template.namespaces template.instantiate(context, processor, params) context.currentNode = save_current return 1 # Nothing matched return 0
def prepare(self, element, value): if value is None: return self.default if len(value) > 1: raise XsltException(Error.INVALID_CHAR_ATTR, value) return value