Ejemplo n.º 1
0
    def characters(self, data):
        """
        Callback interface for SAX.
        """
        parent_state = self._element_state_stack[-1]
        # verify that the current element can have text children
        try:
            next = parent_state.validation[content_model.TEXT_NODE]
        except KeyError:
            # If the parent can have element children, but not text nodes,
            # ignore pure whitespace nodes. This clarification is from
            # XSLT 2.0 [3.4] Whitespace Stripping.
            # e.g. xsl:stylesheet, xsl:apply-templates, xsl:choose
            #self._debug_validation(content_model.TEXT_NODE)
            #if (content_model.EMPTY in parent_state.validation or
            #    not isspace(data)):
            if 1:
                if len(data) > 10:
                    data = data[:10] + '...'
                raise XsltStaticError(XsltError.ILLEGAL_TEXT_CHILD,
                                      parent_state.node,
                                      data=data,
                                      element=parent_state.node.nodeName)
            #self._debug_validation(content_model.TEXT_NODE)
        else:
            # update validation
            parent_state.validation = next

            node = xslt_text(self._root, data)
            parent_state.node.appendChild(node)
        return
Ejemplo n.º 2
0
    def _handle_standard_attr(self, state, instance, name, value):
        if name == 'extension-element-prefixes':
            # a whitespace separated list of prefixes
            ext = state.extensionNamespaces = state.extensionNamespaces.copy()
            out = state.outputNamespaces = state.outputNamespaces.copy()
            for prefix in value:
                # add the namespace URI to the set of extension namespaces
                try:
                    uri = instance.namespaces[prefix]
                except KeyError:
                    raise XsltStaticError(XsltError.UNDEFINED_PREFIX,
                                          instance,
                                          prefix=prefix or '#default')
                ext[uri] = True

                # remove all matching namespace URIs
                for output_prefix, output_uri in out.items():
                    if output_uri == uri:
                        del out[output_prefix]
        elif name == 'exclude-result-prefixes':
            # a whitespace separated list of prefixes
            out = state.outputNamespaces = state.outputNamespaces.copy()
            for prefix in value:
                try:
                    uri = instance.namespaces[prefix]
                except KeyError:
                    raise XsltStaticError(XsltError.UNDEFINED_PREFIX,
                                          instance,
                                          prefix=prefix or '#default')
                # remove all matching namespace URIs
                for output_prefix, output_uri in out.items():
                    if output_uri == uri:
                        del out[output_prefix]
        elif name == 'version':
            # XSLT Spec 2.5 - Forwards-Compatible Processing
            state.forwardsCompatible = (value != 1.0)
            instance._version = value
        else:
            if '-' in name:
                name = name.replace('-', '_')
            instance.__dict__['_' + name] = value
        return
Ejemplo n.º 3
0
 def _handle_result_element_attr(self, state, instance, elementName,
                                 attributeName, value):
     try:
         attr_info = _RESULT_ELEMENT_XSL_ATTRS[attributeName]
     except KeyError:
         raise XsltStaticError(XsltError.ILLEGAL_XSL_NAMESPACE_ATTR,
                               instance,
                               attribute=attributeName,
                               element=elementName)
     value = attr_info.prepare(instance, value)
     self._handle_standard_attr(state, instance, attributeName, value)
     return
Ejemplo n.º 4
0
    def _combine_stylesheet(self, element, is_import):
        href = element._href
        try:
            new_source = self._input_source.resolve(href,
                                                    self._input_source.uri)
        except (OSError, IriError):
            # FIXME: create special inputsource for 4xslt command-line
            #for uri in self._alt_base_uris:
            #    try:
            #        new_href = self._input_source.getUriResolver().normalize(href, uri)
            #        #Do we need to figure out a way to pass the hint here?
            #        new_source = self._input_source.factory.fromUri(new_href)
            #        break
            #    except (OSError, IriError):
            #        pass
            #else:
            raise XsltStaticError(XsltError.INCLUDE_NOT_FOUND,
                                  element,
                                  uri=href,
                                  base=self._locator.getSystemId())

        # XSLT Spec 2.6.1, Detect circular references in stylesheets
        # Note, it is NOT an error to include/import the same stylesheet
        # multiple times, rather that it may lead to duplicate definitions
        # which are handled regardless (variables, params, templates, ...)
        if new_source.uri in self._visited_stylesheet_uris:
            raise XsltStaticError(XsltError.CIRCULAR_INCLUDE,
                                  element,
                                  uri=new_source.uri)
        self.parse(new_source)

        self._import_index += is_import
        # Always update the precedence as the included stylesheet may have
        # contained imports thus increasing the import precedence.
        self._stylesheet.import_precedence = self._import_index
        return
Ejemplo n.º 5
0
    def instantiate(self, context):
        params = {}
        for param, name, select in self._params:
            context.instruction, context.namespaces = param, param.namespaces
            params[name] = select.evaluate(context)

        if self._select:
            context.instruction, context.namespaces = self, self.namespaces
            try:
                nodes = self._select.evaluate_as_nodeset(context)
            except TypeError:
                raise
                raise XsltStaticError(XsltError.INVALID_APPLY_TEMPLATES_SELECT,
                                      self)
        else:
            nodes = context.node.xml_children

        # Process the selected nodes using `self._mode`
        context.transform.apply_templates(context, nodes, self._mode, params)
        return
Ejemplo n.º 6
0
    def endElementNS(self,
                     expandedName,
                     qualifiedName,
                     _literal_element=literal_element.literal_element,
                     _variable_element=variable_elements.variable_element):
        """
        Callback interface for SAX.
        """
        stack = self._element_state_stack
        state = stack[-1]
        del stack[-1]
        parent_state = stack[-1]
        element = state.node

        # ----------------------------------------------------------
        # verify that this element has all required content
        try:
            state.validation[content_model.END_ELEMENT]
        except KeyError:
            if expandedName == (XSL_NAMESPACE, u'choose'):
                raise XsltStaticError(XsltError.MISSING_REQUIRED_ELEMENT,
                                      element,
                                      element=element.nodeName,
                                      child='xsl:when')
            raise

        # ----------------------------------------------------------
        # setup variable context
        if state.localVariables is not parent_state.localVariables:
            # add context save/restore nodes
            binding_stack = []
            node = push_variables_node(self._root, binding_stack)
            element.insertChild(0, node)
            node = pop_variables_node(self._root, binding_stack)
            element.appendChild(node)

        # ----------------------------------------------------------
        # finalize the children for this element
        #element.children = tuple(state.nodes)
        #for child in element.children:
        #    if child.doesSetup:
        #s        child.setup()
        del state

        # ----------------------------------------------------------
        # update parent state
        parent_node = parent_state.node
        if self._stylesheet is None and parent_node is element.root:
            # a literal result element as stylesheet
            assert isinstance(element, _literal_element), element
            try:
                version = element._version
            except AttributeError:
                raise XsltStaticError(XsltError.LITERAL_RESULT_MISSING_VERSION,
                                      element)

            # Reset the root's validation as it has already seen an element.
            parent_state.validation = _XSLT_ROOT_VALIDATION

            # FIXME: use the prefix from the document for the XSL namespace
            stylesheet = (XSL_NAMESPACE, u'stylesheet')
            self.startElementNS(stylesheet, u'xsl:stylesheet',
                                {(None, u'version'): version})

            template = (XSL_NAMESPACE, u'template')
            self.startElementNS(template, u'xsl:template',
                                {(None, u'match'): u'/'})

            # make this element the template's content
            # Note, this MUST index the stack as the stack has changed
            # due to the startElementNS() calls.
            stack[-1].node.appendChild(element)

            self.endElementNS(template, u'xsl:template')
            self.endElementNS(stylesheet, u'xsl:stylesheet')
            return

        parent_node.appendChild(element)

        if isinstance(element, _variable_element):
            name = element._name
            if parent_node is self._stylesheet:
                # global variables
                if name in self._global_vars:
                    existing = self._global_vars[name]
                    if self._import_index > existing:
                        self._global_vars[name] = self._import_index
                    elif self._import_index == existing:
                        raise XsltStaticError(
                            XsltError.DUPLICATE_TOP_LEVEL_VAR,
                            element,
                            variable=name)
                else:
                    self._global_vars[name] = self._import_index
            else:
                # local variables
                # it is safe to ignore import precedence here
                local_vars = parent_state.localVariables
                if name in local_vars:
                    raise XsltStaticError(XsltError.ILLEGAL_SHADOWING,
                                          element,
                                          variable=name)
                # Copy on use
                if local_vars is stack[-2].localVariables:
                    local_vars = local_vars.copy()
                    parent_state.localVariables = local_vars
                local_vars[name] = True
        return
Ejemplo n.º 7
0
    def startElementNS(
        self,
        expandedName,
        qualifiedName,
        attribs,
        _literal_element=literal_element.literal_element,
        _element_classes=ELEMENT_CLASSES,
        _element_cache={},
    ):
        """
        Callback interface for SAX.
        """
        parent_state = self._element_state_stack[-1]
        state = parse_state(**parent_state.__dict__)
        self._element_state_stack.append(state)

        # ----------------------------------------------------------
        # update in-scope namespaces
        if self._new_namespaces:
            d = state.currentNamespaces = state.currentNamespaces.copy()
            d.update(self._new_namespaces)

            d = state.outputNamespaces = state.outputNamespaces.copy()
            for prefix, uri in self._new_namespaces.iteritems():
                if uri not in (XML_NAMESPACE, XSL_NAMESPACE):
                    d[prefix] = uri

            # reset for next element
            self._new_namespaces = {}

        # ----------------------------------------------------------
        # get the class defining this element
        namespace, local = expandedName
        xsl_class = ext_class = None
        if namespace == XSL_NAMESPACE:
            try:
                xsl_class, validation, validation_token, legal_attrs = \
                    _element_cache[local]
            except KeyError:
                # We need to try to import (and cache) it
                try:
                    xsl_class = _element_classes[local]
                except KeyError:
                    if not state.forwardsCompatible:
                        raise XsltStaticError(XsltError.XSLT_ILLEGAL_ELEMENT,
                                              parent_state.node,
                                              element=local)
                    xsl_class = fallback_elements.undefined_xslt_element
                    validation_token = content_model.RESULT_ELEMENT
                else:
                    validation_token = expandedName
                validation = xsl_class.content_model.compile()
                legal_attrs = xsl_class.attribute_types.items()
                _element_cache[local] = (xsl_class, validation,
                                         validation_token, legal_attrs)
        elif namespace in state.extensionNamespaces:
            try:
                ext_class, validation, legal_attrs = \
                    self._extelement_cache[expandedName]
            except KeyError:
                try:
                    ext_class = self._extelements[expandedName]
                except KeyError:
                    ext_class = fallback_elements.undefined_extension_element
                validation = ext_class.content_model.compile()
                legal_attrs = ext_class.attribute_types
                if legal_attrs is not None:
                    legal_attrs = legal_attrs.items()
                self._extelement_cache[expandedName] = (ext_class, validation,
                                                        legal_attrs)
            validation_token = content_model.RESULT_ELEMENT
        else:
            validation = _LITERAL_ELEMENT_VALIDATION
            validation_token = content_model.RESULT_ELEMENT
        state.validation = validation

        # ----------------------------------------------------------
        # verify that this element can be declared here
        try:
            next = parent_state.validation[validation_token]
        except KeyError:
            #self._debug_validation(expandedName)
            # ignore whatever elements are defined within an undefined
            # element as an exception will occur when/if this element
            # is actually instantiated
            if not isinstance(parent_state.node,
                              fallback_elements.undefined_extension_element):
                raise XsltStaticError(XsltError.ILLEGAL_ELEMENT_CHILD,
                                      parent_state.node,
                                      element=qualifiedName)
        else:
            # save this state for next go round
            parent_state.validation = next

        # ----------------------------------------------------------
        # create the instance defining this element
        klass = (xsl_class or ext_class or _literal_element)
        state.node = instance = klass(self._root, expandedName, qualifiedName,
                                      state.currentNamespaces)
        instance.baseUri = self._locator.getSystemId()
        instance.lineNumber = self._locator.getLineNumber()
        instance.columnNumber = self._locator.getColumnNumber()
        instance.import_precedence = self._import_index

        if xsl_class:  # -- XSLT element --------------------------------
            # Handle attributes in the null-namespace
            standand_attributes = local in ('stylesheet', 'transform')
            inst_dict = instance.__dict__
            for attr_name, attr_info in legal_attrs:
                attr_expanded = (None, attr_name)
                if attr_expanded in attribs:
                    value = attribs[attr_expanded]
                    del attribs[attr_expanded]
                elif attr_info.required:
                    raise XsltStaticError(XsltError.MISSING_REQUIRED_ATTRIBUTE,
                                          instance,
                                          element=qualifiedName,
                                          attribute=attr_name)
                else:
                    value = None
                try:
                    value = attr_info.prepare(instance, value)
                except XsltError, e:
                    #raise self._mutate_exception(e, qualifiedName)
                    raise

                if standand_attributes:
                    self._stylesheet = instance
                    self._handle_standard_attr(state, instance, attr_name,
                                               value)
                else:
                    if '-' in attr_name:
                        attr_name = attr_name.replace('-', '_')
                    inst_dict['_' + attr_name] = value

            if attribs:
                # Process attributes with a namespace-uri and check for
                # any illegal attributes in the null-namespace
                for expanded in attribs:
                    attr_ns, attr_name = expanded
                    if attr_ns is None:
                        if not state.forwardsCompatible:
                            raise XsltStaticError(
                                XsltError.ILLEGAL_NULL_NAMESPACE_ATTR,
                                instance,
                                attribute=attr_name,
                                element=qualifiedName)
                    else:
                        instance.setAttribute(attr_ns, attr_name,
                                              attribs[expanded])

            # XSLT Spec 2.6 - Combining Stylesheets
            if local in ('import', 'include'):
                self._combine_stylesheet(instance, (local == 'import'))
Ejemplo n.º 8
0
class stylesheet_reader(object):
    """
    This class can be used to read, from a variety of sources, a
    stylesheet and all its included and imported stylesheets, building
    from them a single, compact representation of an XSLT stylesheet
    tree (an Ft.Xml.Xslt.Stylesheet.Stylesheet object).

    This is done with the most efficient parsing method available, and
    avoids creating a Domlette document for each document it reads.
    """

    # runtime instance variables
    _input_source = None
    _locator = None
    _stylesheet = None
    _root = None

    def __init__(self):
        self._import_index = 0
        self._global_vars = {}
        self._visited_stylesheet_uris = {}
        self._document_state_stack = []
        self._element_state_stack = []
        self._extelements = {}
        self._extelements.update(exslt.extension_elements)
        self._extelements.update(extensions.extension_elements)
        self._extelement_cache = {}
        return

    def reset(self):
        self._root = None
        self._import_index = 0
        self._global_vars = {}
        self._visited_stylesheet_uris = {}
        self._document_state_stack = []
        self._element_state_stack = []
        return

    def addExtensionElementMapping(self, elementMapping):
        """
        Add a mapping of extension element names to classes to the
        existing mapping of extension elements.

        This should only be used for standalone uses of this class.  The
        only known standalone use for this class is for creating compiled
        stylesheets.  The benefits of compiled stylesheets are now so minor
        that this use case may also disappear and then so will this function.
        You have been warned.
        """
        self._extelements.update(elementMapping)
        for name in elementMapping:
            if name in self._extelement_cache:
                del self._extelement_cache[name]
        return

    # -- ContentHandler interface --------------------------------------

    def setDocumentLocator(self, locator):
        """
        Callback interface for SAX.
        """
        # Save the current document state for nested parsing (inclusions)
        document_state = (self._locator, self._stylesheet)
        self._document_state_stack.append(document_state)
        self._locator = locator
        self._stylesheet = None
        return

    def startDocument(self):
        """
        Callback interface for SAX.
        """
        # Our root is always a document
        # We use a document for this because of error checking and
        # because we explicitly pass ownerDocument to the nodes as
        # they are created
        document_uri = self._locator.getSystemId()
        root = xslt_root(document_uri)
        if not self._root:
            self._root = root

        self._element_state_stack.append(
            parse_state(
                node=root,
                validation=_XSLT_ROOT_VALIDATION,
                localVariables={},
                forwardsCompatible=False,
                currentNamespaces={
                    'xml': XML_NAMESPACE,
                    None: None
                },
                extensionNamespaces={},
                outputNamespaces={},
            ))

        # for recursive include checks for xsl:include/xsl:import
        self._visited_stylesheet_uris[document_uri] = True

        # namespaces added for the next element
        self._new_namespaces = {}
        return

    def endDocument(self):
        """
        Callback interface for SAX.
        """
        stack = self._element_state_stack
        state = stack[-1]
        del stack[-1]
        root = state.node

        # ----------------------------------------------------------
        # remove URI from recursive inclusion checking
        del self._visited_stylesheet_uris[root.baseUri]

        # ----------------------------------------------------------
        # finalize the children for the document
        #root.children = tuple(state.nodes)

        # ----------------------------------------------------------
        # finalize the stylesheet AST
        if stack:
            # An xsl:import or xsl:include
            # Merge the top-level elements into the "parent" stylesheet
            # IMPLEMENTATION NOTE: stack[-1] is the import/include element,
            # stack[-2] is the "parent" stylesheet
            stack[-2].node._merge(self._stylesheet)
            #parent_node = stack[-2].node
            #for child in self._stylesheet.children:
            #    child.parent = parent_node
        else:
            # A top-most stylesheet
            stylesheet = self._root.stylesheet
            if stylesheet is not self._stylesheet:
                # An additional stylesheet (e.g., an <?xml-stylesheet ...?>);
                # treat it as an xsl:import into the "master" stylesheet.
                stylesheet.reset()

                # Always update the precedence from the included stylesheet
                # because it may have contained imports thus increasing its
                # import precedence.
                self._import_index += 1
                stylesheet.import_precedence = self._import_index

                # Merge the top-level elements into the "master" stylesheet
                stylesheet._merge(self._stylesheet)
                #stylesheet.children += self._stylesheet.children
                #for child in self._stylesheet.children:
                #    child.parent = stylesheet
            else:
                # Prepare for a possible subsequent parse.
                self._import_index += 1

            # Prepare the "master" stylesheet
            stylesheet.setup()

        document_state = self._document_state_stack[-1]
        del self._document_state_stack[-1]
        self._locator, self._stylesheet = document_state
        return

    def startPrefixMapping(self, prefix, uri):
        """
        Callback interface for SAX.
        """
        self._new_namespaces[prefix] = uri
        return

    def startElementNS(
        self,
        expandedName,
        qualifiedName,
        attribs,
        _literal_element=literal_element.literal_element,
        _element_classes=ELEMENT_CLASSES,
        _element_cache={},
    ):
        """
        Callback interface for SAX.
        """
        parent_state = self._element_state_stack[-1]
        state = parse_state(**parent_state.__dict__)
        self._element_state_stack.append(state)

        # ----------------------------------------------------------
        # update in-scope namespaces
        if self._new_namespaces:
            d = state.currentNamespaces = state.currentNamespaces.copy()
            d.update(self._new_namespaces)

            d = state.outputNamespaces = state.outputNamespaces.copy()
            for prefix, uri in self._new_namespaces.iteritems():
                if uri not in (XML_NAMESPACE, XSL_NAMESPACE):
                    d[prefix] = uri

            # reset for next element
            self._new_namespaces = {}

        # ----------------------------------------------------------
        # get the class defining this element
        namespace, local = expandedName
        xsl_class = ext_class = None
        if namespace == XSL_NAMESPACE:
            try:
                xsl_class, validation, validation_token, legal_attrs = \
                    _element_cache[local]
            except KeyError:
                # We need to try to import (and cache) it
                try:
                    xsl_class = _element_classes[local]
                except KeyError:
                    if not state.forwardsCompatible:
                        raise XsltStaticError(XsltError.XSLT_ILLEGAL_ELEMENT,
                                              parent_state.node,
                                              element=local)
                    xsl_class = fallback_elements.undefined_xslt_element
                    validation_token = content_model.RESULT_ELEMENT
                else:
                    validation_token = expandedName
                validation = xsl_class.content_model.compile()
                legal_attrs = xsl_class.attribute_types.items()
                _element_cache[local] = (xsl_class, validation,
                                         validation_token, legal_attrs)
        elif namespace in state.extensionNamespaces:
            try:
                ext_class, validation, legal_attrs = \
                    self._extelement_cache[expandedName]
            except KeyError:
                try:
                    ext_class = self._extelements[expandedName]
                except KeyError:
                    ext_class = fallback_elements.undefined_extension_element
                validation = ext_class.content_model.compile()
                legal_attrs = ext_class.attribute_types
                if legal_attrs is not None:
                    legal_attrs = legal_attrs.items()
                self._extelement_cache[expandedName] = (ext_class, validation,
                                                        legal_attrs)
            validation_token = content_model.RESULT_ELEMENT
        else:
            validation = _LITERAL_ELEMENT_VALIDATION
            validation_token = content_model.RESULT_ELEMENT
        state.validation = validation

        # ----------------------------------------------------------
        # verify that this element can be declared here
        try:
            next = parent_state.validation[validation_token]
        except KeyError:
            #self._debug_validation(expandedName)
            # ignore whatever elements are defined within an undefined
            # element as an exception will occur when/if this element
            # is actually instantiated
            if not isinstance(parent_state.node,
                              fallback_elements.undefined_extension_element):
                raise XsltStaticError(XsltError.ILLEGAL_ELEMENT_CHILD,
                                      parent_state.node,
                                      element=qualifiedName)
        else:
            # save this state for next go round
            parent_state.validation = next

        # ----------------------------------------------------------
        # create the instance defining this element
        klass = (xsl_class or ext_class or _literal_element)
        state.node = instance = klass(self._root, expandedName, qualifiedName,
                                      state.currentNamespaces)
        instance.baseUri = self._locator.getSystemId()
        instance.lineNumber = self._locator.getLineNumber()
        instance.columnNumber = self._locator.getColumnNumber()
        instance.import_precedence = self._import_index

        if xsl_class:  # -- XSLT element --------------------------------
            # Handle attributes in the null-namespace
            standand_attributes = local in ('stylesheet', 'transform')
            inst_dict = instance.__dict__
            for attr_name, attr_info in legal_attrs:
                attr_expanded = (None, attr_name)
                if attr_expanded in attribs:
                    value = attribs[attr_expanded]
                    del attribs[attr_expanded]
                elif attr_info.required:
                    raise XsltStaticError(XsltError.MISSING_REQUIRED_ATTRIBUTE,
                                          instance,
                                          element=qualifiedName,
                                          attribute=attr_name)
                else:
                    value = None
                try:
                    value = attr_info.prepare(instance, value)
                except XsltError, e:
                    #raise self._mutate_exception(e, qualifiedName)
                    raise

                if standand_attributes:
                    self._stylesheet = instance
                    self._handle_standard_attr(state, instance, attr_name,
                                               value)
                else:
                    if '-' in attr_name:
                        attr_name = attr_name.replace('-', '_')
                    inst_dict['_' + attr_name] = value

            if attribs:
                # Process attributes with a namespace-uri and check for
                # any illegal attributes in the null-namespace
                for expanded in attribs:
                    attr_ns, attr_name = expanded
                    if attr_ns is None:
                        if not state.forwardsCompatible:
                            raise XsltStaticError(
                                XsltError.ILLEGAL_NULL_NAMESPACE_ATTR,
                                instance,
                                attribute=attr_name,
                                element=qualifiedName)
                    else:
                        instance.setAttribute(attr_ns, attr_name,
                                              attribs[expanded])

            # XSLT Spec 2.6 - Combining Stylesheets
            if local in ('import', 'include'):
                self._combine_stylesheet(instance, (local == 'import'))
        elif ext_class:  # -- extension element -------------------------
            validate_attributes = (legal_attrs is not None)
            if validate_attributes:
                # Handle attributes in the null-namespace
                inst_dict = instance.__dict__
                for attr_name, attr_info in legal_attrs:
                    attr_expanded = (None, attr_name)
                    if attr_expanded in attribs:
                        value = attribs[attr_expanded]
                        del attribs[attr_expanded]
                    elif attr_info.required:
                        raise XsltStaticError(
                            XsltError.MISSING_REQUIRED_ATTRIBUTE,
                            instance,
                            element=qualifiedName,
                            attribute=attr_name)
                    else:
                        value = None
                    try:
                        value = attr_info.prepare(instance, value)
                    except XsltError, e:
                        #raise self._mutate_exception(e, qualifiedName)
                        raise
                    if '-' in attr_name:
                        attr_name = attr_name.replace('-', '_')
                    inst_dict['_' + attr_name] = value
Ejemplo n.º 9
0
                        #raise self._mutate_exception(e, qualifiedName)
                        raise
                    if '-' in attr_name:
                        attr_name = attr_name.replace('-', '_')
                    inst_dict['_' + attr_name] = value

            # Process attributes with a namespace-uri and check for
            # any illegal attributes in the null-namespace
            if attribs:
                for expanded in attribs:
                    attr_ns, attr_name = expanded
                    value = attribs[expanded]
                    if validate_attributes and attr_ns is None:
                        raise XsltStaticError(
                            XsltError.ILLEGAL_NULL_NAMESPACE_ATTR,
                            instance,
                            attribute=attr_name,
                            element=qualifiedName)
                    elif attr_ns == XSL_NAMESPACE:
                        self._handle_result_element_attr(
                            state, instance, qualifiedName, attr_name, value)
                    else:
                        instance.setAttribute(attr_ns, attr_name, value)
        else:  # -- literal result element ------------------------------
            output_attrs = []
            for expanded in attribs:
                attr_ns, attr_local = expanded
                value = attribs[expanded]
                if attr_ns == XSL_NAMESPACE:
                    self._handle_result_element_attr(state, instance,
                                                     qualifiedName, attr_local,