Edgewall Software

Ticket #253: genshi-namespace-flattening.patch

File genshi-namespace-flattening.patch, 10.3 KB (added by cmlenz, 15 years ago)

Added patch by Marshall Vandegrift

  • genshi/tests/output.py

     
    185185          <x:p xmlns:x="http://example.org/"/>
    186186        </div>""", output)
    187187
     188    def test_rebound_namespace(self):
     189        stream = Stream([
     190            (Stream.START_NS, ('a', 'http://example.org/'), (None, -1, -1)),
     191            (Stream.START, (QName('http://example.org/}div'), Attrs()), (None, -1, -1)),
     192            (Stream.TEXT, '\n          ', (None, -1, -1)),
     193            (Stream.START_NS, ('b', 'http://example.org/'), (None, -1, -1)),
     194            (Stream.START, (QName('http://example.org/}p'), Attrs()), (None, -1, -1)),
     195            (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
     196            (Stream.END_NS, 'b', (None, -1, -1)),
     197            (Stream.TEXT, '\n        ', (None, -1, -1)),
     198            (Stream.END, QName('http://example.org/}div'), (None, -1, -1)),
     199            (Stream.END_NS, 'a', (None, -1, -1)),
     200        ])
     201        output = stream.render(XMLSerializer)
     202        self.assertEqual("""<a:div xmlns:a="http://example.org/">
     203          <a:p/>
     204        </a:div>""", output)
     205
     206    def test_rebound_namespace_prefix(self):
     207        stream = Stream([
     208            (Stream.START_NS, ('x', 'http://example.org/a'), (None, -1, -1)),
     209            (Stream.START, (QName('http://example.org/a}div'), Attrs()), (None, -1, -1)),
     210            (Stream.TEXT, '\n          ', (None, -1, -1)),
     211            (Stream.START_NS, ('x', 'http://example.org/b'), (None, -1, -1)),
     212            (Stream.START, (QName('http://example.org/b}p'), Attrs()), (None, -1, -1)),
     213            (Stream.END, QName('http://example.org/b}p'), (None, -1, -1)),
     214            (Stream.END_NS, 'x', (None, -1, -1)),
     215            (Stream.TEXT, '\n        ', (None, -1, -1)),
     216            (Stream.END, QName('http://example.org/a}div'), (None, -1, -1)),
     217            (Stream.END_NS, 'x', (None, -1, -1)),
     218        ])
     219        output = stream.render(XMLSerializer)
     220        self.assertEqual("""<x:div xmlns:x="http://example.org/a">
     221          <x:p xmlns:x="http://example.org/b"/>
     222        </x:div>""", output)
     223       
     224    def test_rebound_namespace_with_rebound_namespace_prefix(self):
     225        stream = Stream([
     226            (Stream.START_NS, ('x', 'http://example.org/a'), (None, -1, -1)),
     227            (Stream.START_NS, ('y', 'http://example.org/a'), (None, -1, -1)),
     228            (Stream.START, (QName('http://example.org/a}div'), Attrs()), (None, -1, -1)),
     229            (Stream.TEXT, '\n          ', (None, -1, -1)),
     230            (Stream.START_NS, ('x', 'http://example.org/b'), (None, -1, -1)),
     231            (Stream.START, (QName('http://example.org/b}p'), Attrs()), (None, -1, -1)),
     232            (Stream.TEXT, '\n            ', (None, -1, -1)),
     233            (Stream.START, (QName('http://example.org/a}span'), Attrs()), (None, -1, -1)),
     234            (Stream.END, QName('http://example.org/a}span'), (None, -1, -1)),
     235            (Stream.TEXT, '\n          ', (None, -1, -1)),
     236            (Stream.END, QName('http://example.org/b}p'), (None, -1, -1)),
     237            (Stream.END_NS, 'x', (None, -1, -1)),
     238            (Stream.TEXT, '\n        ', (None, -1, -1)),
     239            (Stream.END, QName('http://example.org/a}div'), (None, -1, -1)),
     240            (Stream.END_NS, 'y', (None, -1, -1)),
     241            (Stream.END_NS, 'x', (None, -1, -1)),
     242        ])
     243        output = stream.render(XMLSerializer)
     244        self.assertEqual("""<x:div xmlns:x="http://example.org/a">
     245          <x:p xmlns:x="http://example.org/b">
     246            <y:span xmlns:y="http://example.org/a"/>
     247          </x:p>
     248        </x:div>""", output)
     249       
     250    def test_multiple_bound_default_namespace_with_attribute(self):
     251        stream = Stream([
     252            (Stream.START_NS, ('', 'http://example.org/a'), (None, -1, -1)),
     253            (Stream.START, (QName('http://example.org/a}div'), Attrs()), (None, -1, -1)),
     254            (Stream.TEXT, '\n          ', (None, -1, -1)),
     255            (Stream.START_NS, ('a', 'http://example.org/a'), (None, -1, -1)),
     256            (Stream.START_NS, ('b', 'http://example.org/b'), (None, -1, -1)),
     257            (Stream.START, (QName('http://example.org/a}div'), Attrs()), (None, -1, -1)),
     258            (Stream.TEXT, '\n            ', (None, -1, -1)),
     259            (Stream.START, (QName('http://example.org/b}p'), Attrs([(QName('http://example.org/a}class'), 'name')])), (None, -1, -1)),
     260            (Stream.END, QName('http://example.org/b}p'), (None, -1, -1)),
     261            (Stream.TEXT, '\n          ', (None, -1, -1)),
     262            (Stream.END, QName('http://example.org/a}div'), (None, -1, -1)),
     263            (Stream.END_NS, 'b', (None, -1, -1)),
     264            (Stream.END_NS, 'a', (None, -1, -1)),           
     265            (Stream.TEXT, '\n        ', (None, -1, -1)),
     266            (Stream.END, QName('http://example.org/a}div'), (None, -1, -1)),
     267            (Stream.END_NS, '', (None, -1, -1)),
     268        ])
     269        output = stream.render(XMLSerializer)
     270        self.assertEqual("""<div xmlns="http://example.org/a">
     271          <div xmlns:a="http://example.org/a" xmlns:b="http://example.org/b">
     272            <b:p a:class="name"/>
     273          </div>
     274        </div>""", output)
     275   
     276    def test_prefer_default_namespace(self):
     277        stream = Stream([
     278            (Stream.START_NS, ('a', 'http://example.org/'), (None, -1, -1)),
     279            (Stream.START_NS, ('', 'http://example.org/'), (None, -1, -1)),
     280            (Stream.START, (QName('http://example.org/}div'), Attrs()), (None, -1, -1)),
     281            (Stream.TEXT, '\n          ', (None, -1, -1)),
     282            (Stream.START, (QName('http://example.org/}p'), Attrs()), (None, -1, -1)),
     283            (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
     284            (Stream.TEXT, '\n        ', (None, -1, -1)),
     285            (Stream.END, QName('http://example.org/}div'), (None, -1, -1)),
     286            (Stream.END_NS, '', (None, -1, -1)),
     287            (Stream.END_NS, 'a', (None, -1, -1)),
     288        ])
     289        output = stream.render(XMLSerializer)
     290        self.assertEqual("""<div xmlns:a="http://example.org/" xmlns="http://example.org/">
     291          <p/>
     292        </div>""", output)
     293   
    188294    def test_atom_with_xhtml(self):
    189295        text = """<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    190296            <id>urn:uuid:c60843aa-0da8-4fa6-bbe5-98007bc6774e</id>
  • genshi/output.py

     
    1717
    1818from itertools import chain
    1919import re
     20import copy
    2021
    2122from genshi.core import escape, Attrs, Markup, Namespace, QName, StreamEventKind
    2223from genshi.core import START, END, TEXT, XML_DECL, DOCTYPE, START_NS, END_NS, \
     
    573574            namespaces.setdefault(uri, []).append(prefix)
    574575            prefixes.setdefault(prefix, []).append(uri)
    575576
     577        active = [set(['xml'])]
    576578        ns_attrs = []
    577         _push_ns_attr = ns_attrs.append
    578579        def _make_ns_attr(prefix, uri):
    579580            return u'xmlns%s' % (prefix and ':%s' % prefix or ''), uri
     581        def _push_ns_attr(prefix, uri):
     582            ns_attrs.append(_make_ns_attr(prefix, uri))
     583            active[-1].add(prefix)
    580584
    581585        def _gen_prefix():
    582586            val = 0
     
    585589                yield 'ns%d' % val
    586590        _gen_prefix = _gen_prefix().next
    587591
     592        def _ns_prefix(uri, attr=False):
     593            for prefix in chain(('',), namespaces.get(uri, [])):
     594                if attr and prefix == '': continue
     595                if prefixes.get(prefix, [None])[-1] == uri:
     596                    if prefix not in active[-1]:
     597                        _push_ns_attr(prefix, uri)
     598                    return prefix
     599            return None
     600       
    588601        for kind, data, pos in stream:
    589602
    590603            if kind is START or kind is EMPTY:
     
    593606                tagname = tag.localname
    594607                tagns = tag.namespace
    595608                if tagns:
    596                     if tagns in namespaces:
    597                         prefix = namespaces[tagns][-1]
     609                    prefix = _ns_prefix(tagns)
     610                    if prefix is not None:
    598611                        if prefix:
    599612                            tagname = u'%s:%s' % (prefix, tagname)
    600613                    else:
    601                         _push_ns_attr((u'xmlns', tagns))
    602614                        _push_ns('', tagns)
     615                        _push_ns_attr('', tagns)
    603616
    604617                new_attrs = []
    605618                for attr, value in attrs:
    606619                    attrname = attr.localname
    607620                    attrns = attr.namespace
    608621                    if attrns:
    609                         if attrns not in namespaces:
     622                        prefix = _ns_prefix(attrns, attr=True)
     623                        if prefix is None:
    610624                            prefix = _gen_prefix()
    611625                            _push_ns(prefix, attrns)
    612                             _push_ns_attr(('xmlns:%s' % prefix, attrns))
    613                         else:
    614                             prefix = namespaces[attrns][-1]
     626                            _push_ns_attr(prefix, attrns)
    615627                        if prefix:
    616628                            attrname = u'%s:%s' % (prefix, attrname)
    617629                    new_attrs.append((attrname, value))
    618630
    619631                yield kind, (tagname, Attrs(ns_attrs + new_attrs)), pos
    620632                del ns_attrs[:]
     633                active.append(copy.copy(active[-1]))
    621634
    622635            elif kind is END:
    623636                tagname = data.localname
    624637                tagns = data.namespace
    625638                if tagns:
    626                     prefix = namespaces[tagns][-1]
     639                    prefix = _ns_prefix(tagns)
    627640                    if prefix:
    628641                        tagname = u'%s:%s' % (prefix, tagname)
    629642                yield kind, tagname, pos
    630 
     643                active.pop()
     644               
    631645            elif kind is START_NS:
    632646                prefix, uri = data
    633                 if uri not in namespaces:
    634                     prefix = prefixes.get(uri, [prefix])[-1]
    635                     _push_ns_attr(_make_ns_attr(prefix, uri))
     647                existing = _ns_prefix(uri)
     648                if existing is None or (existing == '' and prefix != ''):
     649                    _push_ns_attr(prefix, uri)
    636650                _push_ns(prefix, uri)
    637651
    638652            elif kind is END_NS: