Changeset 125:a05226654d45
- 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:
-
Legend:
- Unmodified
- Added
- Removed
-
|
r124
|
r125
|
|
| 67 | 67 | |
| 68 | 68 | RELATORIO_URI = 'http://relatorio.openhex.org/' |
| | 69 | GENSHI_URI = 'http://genshi.edgewall.org/' |
| 69 | 70 | output_encode = genshi.output.encode |
| 70 | 71 | EtreeElement = 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. |
| 71 | 91 | |
| 72 | 92 | def guess_type(val): |
| … |
… |
|
| 195 | 215 | tree = lxml.etree.parse(StringIO(content)) |
| 196 | 216 | 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 |
| 199 | 234 | self.namespaces['relatorio'] = RELATORIO_URI |
| 200 | 235 | |
| … |
… |
|
| 287 | 322 | office_valuetype = '{%s}value-type' % self.namespaces['office'] |
| 288 | 323 | |
| 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 |
| 292 | 326 | |
| 293 | 327 | r_statements, closing_tags = self._relatorio_statements(tree) |
| … |
… |
|
| 337 | 371 | else: |
| 338 | 372 | attribs = {} |
| 339 | | genshi_node = EtreeElement('{%s}%s' % (py_namespace, |
| | 373 | genshi_node = EtreeElement('{%s}%s' % (GENSHI_URI, |
| 340 | 374 | directive), |
| 341 | 375 | attrib=attribs, |
| 342 | | nsmap=self.namespaces) |
| | 376 | nsmap={'py': GENSHI_URI}) |
| 343 | 377 | |
| 344 | 378 | # - we move all the nodes between the opening and closing |
| … |
… |
|
| 374 | 408 | table_num_col_attr = '{%s}number-columns-repeated' % table_namespace |
| 375 | 409 | |
| 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 |
| 380 | 412 | |
| 381 | 413 | # table node (it is not necessarily the direct parent of ancestor) |
| … |
… |
|
| 407 | 439 | attr_value = "__relatorio_store_col_count(%d, %r)" \ |
| 408 | 440 | % (loop_id, table_name) |
| 409 | | replace_node = EtreeElement('{%s}replace' % py_namespace, |
| | 441 | replace_node = EtreeElement('{%s}replace' % GENSHI_URI, |
| 410 | 442 | attrib={'value': attr_value}, |
| 411 | | nsmap=self.namespaces) |
| | 443 | nsmap={'py': GENSHI_URI}) |
| 412 | 444 | ancestor.append(replace_node) |
| 413 | 445 | |
| … |
… |
|
| 479 | 511 | } |
| 480 | 512 | repeat_node = EtreeElement(repeat_tag, attrib=attribs, |
| 481 | | nsmap=self.namespaces) |
| | 513 | nsmap={'relatorio': RELATORIO_URI}) |
| 482 | 514 | wrap_nodes_between(first, last, repeat_node) |
| 483 | 515 | return a_val |
| … |
… |
|
| 490 | 522 | |
| 491 | 523 | _, 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 |
| 494 | 526 | |
| 495 | 527 | # checks wether there is a (meaningful) rowspan |
| … |
… |
|
| 498 | 530 | return a_val |
| 499 | 531 | |
| 500 | | py_namespace = self.namespaces['py'] |
| 501 | | table_namespace = self.namespaces['table'] |
| 502 | 532 | table_row_tag = '{%s}table-row' % table_namespace |
| 503 | 533 | table_cov_cell_tag = '{%s}covered-table-cell' % table_namespace |
| … |
… |
|
| 510 | 540 | target, iterable = a_val.split(' in ', 1) |
| 511 | 541 | vars = "%s = list(%s)" % (temp_var, iterable.strip()) |
| 512 | | with_node = EtreeElement('{%s}with' % py_namespace, |
| | 542 | with_node = EtreeElement('{%s}with' % GENSHI_URI, |
| 513 | 543 | attrib={"vars": vars}, |
| 514 | | nsmap=self.namespaces) |
| | 544 | nsmap={'py': GENSHI_URI}) |
| 515 | 545 | |
| 516 | 546 | # 2) transform a_val to use that temporary variable |
| … |
… |
|
| 535 | 565 | assert last.tag == table_cov_cell_tag |
| 536 | 566 | # wrap them |
| 537 | | tag = '{%s}%s' % (py_namespace, directive) |
| | 567 | tag = '{%s}%s' % (GENSHI_URI, directive) |
| 538 | 568 | for_node = EtreeElement(tag, |
| 539 | 569 | attrib={attr: a_val}, |
| 540 | | nsmap=self.namespaces) |
| | 570 | nsmap={'py': GENSHI_URI}) |
| 541 | 571 | wrap_nodes_between(first, last, for_node) |
| 542 | 572 | |
| … |
… |
|
| 549 | 579 | def _handle_images(self, tree): |
| 550 | 580 | "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 |
| 553 | 584 | py_attrs = '{%s}attrs' % self.namespaces['py'] |
| 554 | 585 | xpath_expr = "//draw:frame[starts-with(@draw:name, 'image:')]" |
| … |
… |
|
| 558 | 589 | image_node = EtreeElement(draw_image, |
| 559 | 590 | attrib={py_attrs: attr_expr}, |
| 560 | | nsmap=self.namespaces) |
| | 591 | nsmap={'draw': draw_namespace, |
| | 592 | 'py': GENSHI_URI}) |
| 561 | 593 | draw.replace(draw[0], image_node) |
| 562 | 594 | |
| … |
… |
|
| 582 | 614 | stream = super(Template, self).generate(*args, **kwargs) |
| 583 | 615 | 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. |
| 584 | 619 | transformation = DuplicateColumnHeaders(counter) |
| 585 | 620 | col_filter = Transformer('//repeat[namespace-uri()="%s"]' |