Changeset 125:a05226654d45

Show
Ignore:
Timestamp:
04/16/09 03:53:19 (11 months ago)
Author:
Ga?tan de Menten <ged@…>
Branch:
default
Message:

- use default/fallback namespaces so that documents do not need to define

namespaces they don't use.

- use explicit nsmap when creating new tags, so that we don't polute them with

unused namespaces.

- added notes about namespaces

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • relatorio/templates/opendocument.py

    r124 r125  
    6767 
    6868RELATORIO_URI = 'http://relatorio.openhex.org/' 
     69GENSHI_URI = 'http://genshi.edgewall.org/' 
    6970output_encode = genshi.output.encode 
    7071EtreeElement = lxml.etree.Element 
     72 
     73# A note regarding OpenDocument namespaces: 
     74# 
     75# The current code assumes the original OpenOffice document uses default 
     76# namespace prefix ("table", "xlink", "draw", ...). We derive the actual 
     77# namespaces URIs from their prefix, instead of the other way round. This has 
     78# the advantage that if a new version of the format use different namespaces 
     79# (this is not the case for ODF 1.1 but could be the case in the future since 
     80# there is a version number in those namespaces after all), Relatorio will 
     81# support those new formats out of the box. 
     82 
     83 
     84# A note about attribute namespaces: 
     85# 
     86# Ideally, we should update the namespace map of all the nodes we add 
     87# (Genshi) attributes to, so that the attributes use a nice "py" prefix instead 
     88# of a generated one (eg. "ns0", which is correct but ugly) in the case no 
     89# parent node defines it. Unfortunately, lxml doesn't support this: 
     90# the nsmap attribute of Element objects is (currently) readonly. 
    7191 
    7292def guess_type(val): 
     
    195215        tree = lxml.etree.parse(StringIO(content)) 
    196216        root = tree.getroot() 
    197         self.namespaces = root.nsmap.copy() 
    198         self.namespaces['py'] = 'http://genshi.edgewall.org/' 
     217 
     218        # assign default/fake namespaces so that documents do not need to 
     219        # define them if they don't use them 
     220        self.namespaces = { 
     221            "text": "urn:text", 
     222            "draw": "urn:draw", 
     223            "table": "urn:table", 
     224            "office": "urn:office", 
     225            "xlink": "urn:xlink" 
     226        } 
     227        # but override them with the real namespaces 
     228        self.namespaces.update(root.nsmap) 
     229 
     230        # remove any "root" namespace as lxml.xpath do not support them 
     231        self.namespaces.pop(None, None) 
     232 
     233        self.namespaces['py'] = GENSHI_URI 
    199234        self.namespaces['relatorio'] = RELATORIO_URI 
    200235 
     
    287322        office_valuetype = '{%s}value-type' % self.namespaces['office'] 
    288323 
    289         py_namespace = self.namespaces['py'] 
    290         py_attrs_attr = '{%s}attrs' % py_namespace 
    291         py_replace = '{%s}replace' % py_namespace 
     324        py_attrs_attr = '{%s}attrs' % GENSHI_URI 
     325        py_replace = '{%s}replace' % GENSHI_URI 
    292326 
    293327        r_statements, closing_tags = self._relatorio_statements(tree) 
     
    337371                else: 
    338372                    attribs = {} 
    339                 genshi_node = EtreeElement('{%s}%s' % (py_namespace, 
     373                genshi_node = EtreeElement('{%s}%s' % (GENSHI_URI, 
    340374                                                       directive), 
    341375                                           attrib=attribs, 
    342                                            nsmap=self.namespaces) 
     376                                           nsmap={'py': GENSHI_URI}) 
    343377 
    344378                # - we move all the nodes between the opening and closing 
     
    374408        table_num_col_attr = '{%s}number-columns-repeated' % table_namespace 
    375409 
    376         py_namespace = self.namespaces['py'] 
    377         py_attrs_attr = '{%s}attrs' % py_namespace 
    378  
    379         repeat_tag = '{%s}repeat' % self.namespaces['relatorio'] 
     410        py_attrs_attr = '{%s}attrs' % GENSHI_URI 
     411        repeat_tag = '{%s}repeat' % RELATORIO_URI 
    380412 
    381413        # table node (it is not necessarily the direct parent of ancestor) 
     
    407439        attr_value = "__relatorio_store_col_count(%d, %r)" \ 
    408440                     % (loop_id, table_name) 
    409         replace_node = EtreeElement('{%s}replace' % py_namespace, 
     441        replace_node = EtreeElement('{%s}replace' % GENSHI_URI, 
    410442                                    attrib={'value': attr_value}, 
    411                                     nsmap=self.namespaces) 
     443                                    nsmap={'py': GENSHI_URI}) 
    412444        ancestor.append(replace_node) 
    413445 
     
    479511            } 
    480512            repeat_node = EtreeElement(repeat_tag, attrib=attribs, 
    481                                        nsmap=self.namespaces) 
     513                                       nsmap={'relatorio': RELATORIO_URI}) 
    482514            wrap_nodes_between(first, last, repeat_node) 
    483515        return a_val 
     
    490522 
    491523        _, directive, attr, a_val = statement 
    492         table_rowspan_attr = '{%s}number-rows-spanned' \ 
    493                              % self.namespaces['table'] 
     524        table_namespace = self.namespaces['table'] 
     525        table_rowspan_attr = '{%s}number-rows-spanned' % table_namespace 
    494526 
    495527        # checks wether there is a (meaningful) rowspan 
     
    498530            return a_val 
    499531 
    500         py_namespace = self.namespaces['py'] 
    501         table_namespace = self.namespaces['table'] 
    502532        table_row_tag = '{%s}table-row' % table_namespace 
    503533        table_cov_cell_tag = '{%s}covered-table-cell' % table_namespace 
     
    510540        target, iterable = a_val.split(' in ', 1) 
    511541        vars = "%s = list(%s)" % (temp_var, iterable.strip()) 
    512         with_node = EtreeElement('{%s}with' % py_namespace, 
     542        with_node = EtreeElement('{%s}with' % GENSHI_URI, 
    513543                                 attrib={"vars": vars}, 
    514                                  nsmap=self.namespaces) 
     544                                 nsmap={'py': GENSHI_URI}) 
    515545 
    516546        # 2) transform a_val to use that temporary variable 
     
    535565            assert last.tag == table_cov_cell_tag 
    536566            # wrap them 
    537             tag = '{%s}%s' % (py_namespace, directive) 
     567            tag = '{%s}%s' % (GENSHI_URI, directive) 
    538568            for_node = EtreeElement(tag, 
    539569                                    attrib={attr: a_val}, 
    540                                     nsmap=self.namespaces) 
     570                                    nsmap={'py': GENSHI_URI}) 
    541571            wrap_nodes_between(first, last, for_node) 
    542572 
     
    549579    def _handle_images(self, tree): 
    550580        "replaces all draw:frame named 'image: ...' by draw:image nodes" 
    551         draw_name = '{%s}name' % self.namespaces['draw'] 
    552         draw_image = '{%s}image' % self.namespaces['draw'] 
     581        draw_namespace = self.namespaces['draw'] 
     582        draw_name = '{%s}name' % draw_namespace 
     583        draw_image = '{%s}image' % draw_namespace 
    553584        py_attrs = '{%s}attrs' % self.namespaces['py'] 
    554585        xpath_expr = "//draw:frame[starts-with(@draw:name, 'image:')]" 
     
    558589            image_node = EtreeElement(draw_image, 
    559590                                      attrib={py_attrs: attr_expr}, 
    560                                       nsmap=self.namespaces) 
     591                                      nsmap={'draw': draw_namespace, 
     592                                             'py': GENSHI_URI}) 
    561593            draw.replace(draw[0], image_node) 
    562594 
     
    582614        stream = super(Template, self).generate(*args, **kwargs) 
    583615        if self.has_col_loop: 
     616            # Note that we can't simply add a "number-columns-repeated" 
     617            # attribute and then fill it with the correct number of columns 
     618            # because that wouldn't work if more than one column is repeated. 
    584619            transformation = DuplicateColumnHeaders(counter) 
    585620            col_filter = Transformer('//repeat[namespace-uri()="%s"]'