summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--beautifulsoup/element.py51
-rw-r--r--tests/test_tree.py8
2 files changed, 18 insertions, 41 deletions
diff --git a/beautifulsoup/element.py b/beautifulsoup/element.py
index d37124f..6af27a8 100644
--- a/beautifulsoup/element.py
+++ b/beautifulsoup/element.py
@@ -420,19 +420,14 @@ class Tag(PageElement):
self.parserClass = parser.__class__
self.name = name
if attrs == None:
- attrs = []
- if isinstance(attrs, types.DictType):
- self.attrMap = attrs
+ attrs = {}
+ else:
+ attrs = dict(attrs)
self.attrs = attrs
self.contents = []
self.setup(parent, previous)
self.hidden = False
- if isinstance(attrs, types.DictType):
- self.attrs = [kv for kv in attrs.items()]
- else:
- self.attrs = list(attrs)
-
# Set up any substitutions, such as the charset in a META tag.
self.contains_substitutions = builder.set_up_substitutions(self)
@@ -478,15 +473,15 @@ class Tag(PageElement):
"""Returns the value of the 'key' attribute for the tag, or
the value given for 'default' if it doesn't have that
attribute."""
- return self._getAttrMap().get(key, default)
+ return self.attrs.get(key, default)
def has_key(self, key):
- return self._getAttrMap().has_key(key)
+ return self.attrs.has_key(key)
def __getitem__(self, key):
"""tag[key] returns the value of the 'key' attribute for the tag,
and throws an exception if it's not there."""
- return self._getAttrMap()[key]
+ return self.attrs[key]
def __iter__(self):
"Iterating over a tag iterates over its contents."
@@ -506,27 +501,12 @@ class Tag(PageElement):
def __setitem__(self, key, value):
"""Setting tag[key] sets the value of the 'key' attribute for the
tag."""
- self._getAttrMap()
- self.attrMap[key] = value
- found = False
- for i in range(0, len(self.attrs)):
- if self.attrs[i][0] == key:
- self.attrs[i] = (key, value)
- found = True
- if not found:
- self.attrs.append((key, value))
- self._getAttrMap()[key] = value
+ self.attrs[key] = value
def __delitem__(self, key):
"Deleting tag[key] deletes all 'key' attributes for the tag."
- for item in self.attrs:
- if item[0] == key:
- self.attrs.remove(item)
- #We don't break because bad HTML can define the same
- #attribute multiple times.
- self._getAttrMap()
- if self.attrMap.has_key(key):
- del self.attrMap[key]
+ if self.attrs.has_key(key):
+ del self.attrs[key]
def __call__(self, *args, **kwargs):
"""Calling a tag like a function is the same as calling its
@@ -589,7 +569,7 @@ class Tag(PageElement):
"""
attrs = []
if self.attrs:
- for key, val in self.attrs:
+ for key, val in sorted(self.attrs.items()):
if val is None:
decoded = key
else:
@@ -718,17 +698,6 @@ class Tag(PageElement):
findAll = find_all # BS3
findChildren = find_all # BS2
- #Private methods
-
- def _getAttrMap(self):
- """Initializes a map representation of this tag's attributes,
- if not already initialized."""
- if not getattr(self, 'attrMap'):
- self.attrMap = {}
- for (key, value) in self.attrs:
- self.attrMap[key] = value
- return self.attrMap
-
#Generator methods
@property
def children(self):
diff --git a/tests/test_tree.py b/tests/test_tree.py
index f9163f1..ea10367 100644
--- a/tests/test_tree.py
+++ b/tests/test_tree.py
@@ -741,6 +741,14 @@ class TestElementObjects(SoupTest):
self.assertTrue(soup.foo.has_key('attr'))
self.assertFalse(soup.foo.has_key('attr2'))
+ def test_attributes_come_out_in_alphabetical_order(self):
+ markup = '<b a="1" z="5" m="3" f="2" y="4"></b>'
+ self.assertSoupEquals(markup, '<b a="1" f="2" m="3" y="4" z="5"></b>')
+
+ def test_multiple_values_for_the_same_attribute_are_collapsed(self):
+ markup = '<b b="20" a="1" b="10" a="2" a="3" a="4"></b>'
+ self.assertSoupEquals(markup, '<b a="1" b="20"></b>')
+
def test_string(self):
# A tag that contains only a text node makes that node
# available as .string.