def writer(stream=sys.stdout, **kwargs): from amara.writers.outputparameters import outputparameters oparams = outputparameters(**kwargs) if kwargs.get("method", "xml") == "xml": from amara.writers.xmlwriter import _xmluserwriter writer_class = _xmluserwriter else: from amara.writers.htmlwriter import _htmluserwriter writer_class = _htmluserwriter return writer_class(oparams, stream)
def instantiate(self, context): output_parameters = outputparameters.outputparameters( method='xml', encoding=context.output_parameters.encoding, omit_xml_declaration=True) writer = xmlwriter.xmlwriter(output_parameters, StringIO()) context.push_writer(writer) try: self.process_children(context) finally: writer = context.pop_writer() msg = writer.stream.getvalue() if self._terminate: raise XsltError(XsltError.STYLESHEET_REQUESTED_TERMINATION, msg=msg) else: context.message(msg) return
def instantiate(self, context): output_parameters = outputparameters.outputparameters( method='xml', encoding=context.output_parameters.encoding, omit_xml_declaration=True) writer = xmlwriter.xmlwriter(output_parameters, StringIO()) context.push_writer(writer) try: self.process_children(context) finally: writer = context.pop_writer() msg = writer.stream.getvalue() if self._terminate: raise XsltError(XsltError.STYLESHEET_REQUESTED_TERMINATION, msg=msg) else: context.message(msg) return
def setup(self, _param_element=variable_elements.param_element): """ Called only once, at the first initialization """ self.output_parameters = outputparameters.outputparameters() # Sort the top-level elements in decreasing import precedence to ease # processing later. precedence_key = operator.attrgetter('import_precedence') elements = sorted(self.children, key=precedence_key, reverse=True) # Merge the top-level stylesheet elements into their respective # lists. Any element name not in the mapping is discarded. # Note, by sharing the same list no merging is required later. whitespace_elements, variable_elements = [], [] top_level_elements = { 'strip-space' : whitespace_elements, 'preserve-space' : whitespace_elements, 'output' : [], 'key' : [], 'decimal-format' : [], 'namespace-alias' : [], 'attribute-set': [], 'variable' : variable_elements, 'param' : variable_elements, 'template' : [], } # Using `groupby` takes advantage of series of same-named elements # appearing adjacent to each other. key = operator.attrgetter('expanded_name') for (namespace, name), nodes in itertools.groupby(self.children, key): if namespace == XSL_NAMESPACE and name in top_level_elements: top_level_elements[name].extend(nodes) # - process the `xsl:preserve-space` and `xsl:strip-space` elements # RECOVERY: Multiple matching patterns use the last occurance space_rules = {} for element in whitespace_elements: strip = element._strip_whitespace for token in element._elements: namespace, name = token space_rules[token] = (namespace, name, strip) self.space_rules = space_rules.values() # sort in decreasing priority, where `*` is lowest, followed by # `prefix:*`, then all others. self.space_rules.sort(reverse=True) # - process the `xsl:output` elements # Sort in increasing import precedence, so the last one added # will have the highest import precedence elements = top_level_elements['output'] getter = operator.attrgetter( '_method', '_version', '_encoding', '_omit_xml_declaration', '_standalone', '_doctype_system', '_doctype_public', '_cdata_section_elements', '_indent', '_media_type', '_byte_order_mark', '_canonical_form') for element in elements: (method, version, encoding, omit_xmldecl, standalone, doctype_system, doctype_public, cdata_elements, indent, media_type, byte_order_mark, canonical_form) = getter(element) if method is not None: self.output_parameters.method = method if version is not None: self.output_parameters.version = version if encoding is not None: self.output_parameters.encoding = encoding if omit_xmldecl is not None: self.output_parameters.omit_xml_declaration = omit_xmldecl if standalone is not None: self.output_parameters.standalone = standalone if doctype_system is not None: self.output_parameters.doctype_system = doctype_system if doctype_public is not None: self.output_parameters.doctype_public = doctype_public if cdata_elements: self.output_parameters.cdata_section_elements += cdata_elements if indent is not None: self.output_parameters.indent = indent if media_type is not None: self.output_parameters.media_type = media_type if byte_order_mark is not None: self.output_parameters.byte_order_mark = byte_order_mark if canonical_form is not None: self.output_parameters.canonical_form = canonical_form # - process the `xsl:key` elements # Group the keys by name elements = top_level_elements['key'] name_key = operator.attrgetter('_name') elements.sort(key=name_key) keys = self._keys = {} for name, elements in itertools.groupby(elements, name_key): keys[name] = tuple(elements) # - process the `xsl:decimal-format` elements formats = self.decimal_formats = {} getter = operator.attrgetter( '_decimal_separator', '_grouping_separator', '_infinity', '_minus_sign', '_NaN', '_percent', '_per_mille', '_zero_digit', '_digit', '_pattern_separator') for element in top_level_elements['decimal-format']: name = element._name format = getter(element) # It is an error to declare a decimal-format more than once # (even with different import precedence) with different values. if name in formats and formats[name] != format: # Construct a useful name for the error message. if name: namespace, name = name if namespace: name = element.namespaces[namespace] + ':' + name else: name = '#default' raise XsltError(XsltError.DUPLICATE_DECIMAL_FORMAT, name) else: formats[name] = format # Add the default decimal format, if not declared. if None not in formats: formats[None] = ('.', ',', 'Infinity', '-', 'NaN', '%', unichr(0x2030), '0', '#', ';') # - process the `xsl:namespace-alias` elements elements = top_level_elements['namespace-alias'] elements.reverse() aliases = self.namespace_aliases = {} for precedence, group in itertools.groupby(elements, precedence_key): mapped = {} for element in group: namespace = element.namespaces[element._stylesheet_prefix] if namespace not in aliases: mapped[namespace] = True result_prefix = element._result_prefix result_namespace = element.namespaces[result_prefix] aliases[namespace] = (result_namespace, result_prefix) # It is an error for a namespace URI to be mapped to multiple # different namespace URIs (with the same import precedence). elif namespace in mapped: raise XsltError(XsltError.DUPLICATE_NAMESPACE_ALIAS, element._stylesheet_prefix) if aliases: # apply namespace fixup for the literal elements _fixup_aliases(self, aliases) # - process the `xsl:attribute-set` elements sets = self.attribute_sets = {} for element in top_level_elements['attribute-set']: sets[element._name] = element # - process the `xsl:param` and `xsl:variable` elements index, self._variables = {}, variable_elements[:] variable_elements.reverse() for element in variable_elements: name = element._name if name not in index: # unique (or first) variable binding index[name] = 1 else: # shadowed variable binding, remove from processing list self._variables.remove(element) self.parameters = frozenset(element._name for element in self._variables if isinstance(element, _param_element)) # - process the `xsl:template` elements match_templates = collections.defaultdict(_type_dispatch_table) named_templates = self.named_templates = {} elements = top_level_elements['template'] elements.reverse() getter = operator.attrgetter('node_test', 'axis_type', 'node_type') for position, element in enumerate(elements): match, name = element._match, element._name precedence = element.import_precedence if match: namespaces = element.namespaces template_priority = element._priority mode_table = match_templates[element._mode] for pattern in match: node_test, axis_type, node_type = getter(pattern) if template_priority is None: priority = node_test.priority else: priority = template_priority sort_key = (precedence, priority, position) info = (sort_key, node_test, axis_type, element) # Add the template rule to the dispatch table type_key = node_type.xml_typecode if type_key == tree.element.xml_typecode: # Element types are further keyed by the name test. name_key = node_test.name_key if name_key: prefix, local = name_key # Unprefixed names are in the null-namespace try: namespace = prefix and namespaces[prefix] except KeyError: raise XPathError(XPathError.UNDEFINED_PREFIX, prefix=prefix) else: name_key = namespace, local mode_table[type_key][name_key].append(info) else: # Every other node type gets lumped into a single list # for that node type mode_table[type_key].append(info) if name: # XSLT 1.0, Section 6, Paragraph 3: # It is an error if a stylesheet contains more than one # template with the same name and same import precedence. if name not in named_templates: named_templates[name] = element elif named_templates[name].import_precedence == precedence: # Construct a useful name for the error message. namespace, name = name if namespace: name = element.namespaces[namespace] + ':' + name raise XsltError(XsltError.DUPLICATE_NAMED_TEMPLATE, name) # Now expanded the tables and convert to regular dictionaries to # prevent inadvertant growth when non-existant keys are used. match_templates = self.match_templates = dict(match_templates) for mode, type_table in match_templates.iteritems(): # Add those patterns that don't have a distinct type: # node(), id() and key() patterns any_patterns = type_table[tree.node.xml_typecode] type_table = match_templates[mode] = dict(type_table) for type_key, patterns in type_table.iteritems(): if type_key == tree.element.xml_typecode: # Add those that are wildcard tests ('*' and 'prefix:*') wildcard_names = patterns[None] name_table = type_table[type_key] = dict(patterns) for name_key, patterns in name_table.iteritems(): if name_key is not None: patterns.extend(wildcard_names) patterns.extend(any_patterns) patterns.sort(reverse=True) name_table[name_key] = tuple(patterns) else: patterns.extend(any_patterns) patterns.sort(reverse=True) type_table[type_key] = tuple(patterns) #self._dump_match_templates(match_templates) return
def setup(self, _param_element=variable_elements.param_element): """ Called only once, at the first initialization """ self.output_parameters = outputparameters.outputparameters() # Sort the top-level elements in decreasing import precedence to ease # processing later. precedence_key = operator.attrgetter('import_precedence') elements = sorted(self.children, key=precedence_key, reverse=True) # Merge the top-level stylesheet elements into their respective # lists. Any element name not in the mapping is discarded. # Note, by sharing the same list no merging is required later. whitespace_elements, variable_elements = [], [] top_level_elements = { 'strip-space': whitespace_elements, 'preserve-space': whitespace_elements, 'output': [], 'key': [], 'decimal-format': [], 'namespace-alias': [], 'attribute-set': [], 'variable': variable_elements, 'param': variable_elements, 'template': [], } # Using `groupby` takes advantage of series of same-named elements # appearing adjacent to each other. key = operator.attrgetter('expanded_name') for (namespace, name), nodes in itertools.groupby(self.children, key): if namespace == XSL_NAMESPACE and name in top_level_elements: top_level_elements[name].extend(nodes) # - process the `xsl:preserve-space` and `xsl:strip-space` elements # RECOVERY: Multiple matching patterns use the last occurance space_rules = {} for element in whitespace_elements: strip = element._strip_whitespace for token in element._elements: namespace, name = token space_rules[token] = (namespace, name, strip) self.space_rules = space_rules.values() # sort in decreasing priority, where `*` is lowest, followed by # `prefix:*`, then all others. self.space_rules.sort(reverse=True) # - process the `xsl:output` elements # Sort in increasing import precedence, so the last one added # will have the highest import precedence elements = top_level_elements['output'] getter = operator.attrgetter('_method', '_version', '_encoding', '_omit_xml_declaration', '_standalone', '_doctype_system', '_doctype_public', '_cdata_section_elements', '_indent', '_media_type', '_byte_order_mark', '_canonical_form') for element in elements: (method, version, encoding, omit_xmldecl, standalone, doctype_system, doctype_public, cdata_elements, indent, media_type, byte_order_mark, canonical_form) = getter(element) if method is not None: self.output_parameters.method = method if version is not None: self.output_parameters.version = version if encoding is not None: self.output_parameters.encoding = encoding if omit_xmldecl is not None: self.output_parameters.omit_xml_declaration = omit_xmldecl if standalone is not None: self.output_parameters.standalone = standalone if doctype_system is not None: self.output_parameters.doctype_system = doctype_system if doctype_public is not None: self.output_parameters.doctype_public = doctype_public if cdata_elements: self.output_parameters.cdata_section_elements += cdata_elements if indent is not None: self.output_parameters.indent = indent if media_type is not None: self.output_parameters.media_type = media_type if byte_order_mark is not None: self.output_parameters.byte_order_mark = byte_order_mark if canonical_form is not None: self.output_parameters.canonical_form = canonical_form # - process the `xsl:key` elements # Group the keys by name elements = top_level_elements['key'] name_key = operator.attrgetter('_name') elements.sort(key=name_key) keys = self._keys = {} for name, elements in itertools.groupby(elements, name_key): keys[name] = tuple(elements) # - process the `xsl:decimal-format` elements formats = self.decimal_formats = {} getter = operator.attrgetter('_decimal_separator', '_grouping_separator', '_infinity', '_minus_sign', '_NaN', '_percent', '_per_mille', '_zero_digit', '_digit', '_pattern_separator') for element in top_level_elements['decimal-format']: name = element._name format = getter(element) # It is an error to declare a decimal-format more than once # (even with different import precedence) with different values. if name in formats and formats[name] != format: # Construct a useful name for the error message. if name: namespace, name = name if namespace: name = element.namespaces[namespace] + ':' + name else: name = '#default' raise XsltError(XsltError.DUPLICATE_DECIMAL_FORMAT, name) else: formats[name] = format # Add the default decimal format, if not declared. if None not in formats: formats[None] = ('.', ',', 'Infinity', '-', 'NaN', '%', unichr(0x2030), '0', '#', ';') # - process the `xsl:namespace-alias` elements elements = top_level_elements['namespace-alias'] elements.reverse() aliases = self.namespace_aliases = {} for precedence, group in itertools.groupby(elements, precedence_key): mapped = {} for element in group: namespace = element.namespaces[element._stylesheet_prefix] if namespace not in aliases: mapped[namespace] = True result_prefix = element._result_prefix result_namespace = element.namespaces[result_prefix] aliases[namespace] = (result_namespace, result_prefix) # It is an error for a namespace URI to be mapped to multiple # different namespace URIs (with the same import precedence). elif namespace in mapped: raise XsltError(XsltError.DUPLICATE_NAMESPACE_ALIAS, element._stylesheet_prefix) if aliases: # apply namespace fixup for the literal elements _fixup_aliases(self, aliases) # - process the `xsl:attribute-set` elements sets = self.attribute_sets = {} for element in top_level_elements['attribute-set']: sets[element._name] = element # - process the `xsl:param` and `xsl:variable` elements index, self._variables = {}, variable_elements[:] variable_elements.reverse() for element in variable_elements: name = element._name if name not in index: # unique (or first) variable binding index[name] = 1 else: # shadowed variable binding, remove from processing list self._variables.remove(element) self.parameters = frozenset(element._name for element in self._variables if isinstance(element, _param_element)) # - process the `xsl:template` elements match_templates = collections.defaultdict(_type_dispatch_table) named_templates = self.named_templates = {} elements = top_level_elements['template'] elements.reverse() getter = operator.attrgetter('node_test', 'axis_type', 'node_type') for position, element in enumerate(elements): match, name = element._match, element._name precedence = element.import_precedence if match: namespaces = element.namespaces template_priority = element._priority mode_table = match_templates[element._mode] for pattern in match: node_test, axis_type, node_type = getter(pattern) if template_priority is None: priority = node_test.priority else: priority = template_priority sort_key = (precedence, priority, position) info = (sort_key, node_test, axis_type, element) # Add the template rule to the dispatch table type_key = node_type.xml_typecode if type_key == tree.element.xml_typecode: # Element types are further keyed by the name test. name_key = node_test.name_key if name_key: prefix, local = name_key # Unprefixed names are in the null-namespace try: namespace = prefix and namespaces[prefix] except KeyError: raise XPathError(XPathError.UNDEFINED_PREFIX, prefix=prefix) else: name_key = namespace, local mode_table[type_key][name_key].append(info) else: # Every other node type gets lumped into a single list # for that node type mode_table[type_key].append(info) if name: # XSLT 1.0, Section 6, Paragraph 3: # It is an error if a stylesheet contains more than one # template with the same name and same import precedence. if name not in named_templates: named_templates[name] = element elif named_templates[name].import_precedence == precedence: # Construct a useful name for the error message. namespace, name = name if namespace: name = element.namespaces[namespace] + ':' + name raise XsltError(XsltError.DUPLICATE_NAMED_TEMPLATE, name) # Now expanded the tables and convert to regular dictionaries to # prevent inadvertant growth when non-existant keys are used. match_templates = self.match_templates = dict(match_templates) for mode, type_table in match_templates.iteritems(): # Add those patterns that don't have a distinct type: # node(), id() and key() patterns any_patterns = type_table[tree.node.xml_typecode] type_table = match_templates[mode] = dict(type_table) for type_key, patterns in type_table.iteritems(): if type_key == tree.element.xml_typecode: # Add those that are wildcard tests ('*' and 'prefix:*') wildcard_names = patterns[None] name_table = type_table[type_key] = dict(patterns) for name_key, patterns in name_table.iteritems(): if name_key is not None: patterns.extend(wildcard_names) patterns.extend(any_patterns) patterns.sort(reverse=True) name_table[name_key] = tuple(patterns) else: patterns.extend(any_patterns) patterns.sort(reverse=True) type_table[type_key] = tuple(patterns) #self._dump_match_templates(match_templates) return
def setup(self): self._output_parameters = outputparameters.outputparameters() return
def setup(self): self._output_parameters = outputparameters.outputparameters() return