diff --git a/mwparserfromhell/nodes/extras/attribute.py b/mwparserfromhell/nodes/extras/attribute.py
index 33ad851..5888dba 100644
--- a/mwparserfromhell/nodes/extras/attribute.py
+++ b/mwparserfromhell/nodes/extras/attribute.py
@@ -36,19 +36,22 @@ class Attribute(StringMixIn):
whose value is ``"foo"``.
"""
- def __init__(self, name, value=None, quoted=True, padding=""):
+ def __init__(self, name, value=None, quoted=True, pad_first="",
+ pad_before_eq="", pad_after_eq=""):
super(Attribute, self).__init__()
self._name = name
self._value = value
self._quoted = quoted
- self._padding = padding
+ self._pad_first = pad_first
+ self._pad_before_eq = pad_before_eq
+ self._pad_after_eq = pad_after_eq
def __unicode__(self):
- base = self.padding + str(self.name)
+ base = self.pad_first + str(self.name) + self.pad_before_eq
if self.value:
if self.quoted:
- return base + '="' + str(self.value) + '"'
- return base + "=" + str(self.value)
+ return base + '="' + self.pad_after_eq + str(self.value) + '"'
+ return base + "=" + self.pad_after_eq + str(self.value)
return base
@property
@@ -67,9 +70,19 @@ class Attribute(StringMixIn):
return self._quoted
@property
- def padding(self):
+ def pad_first(self):
"""Spacing to insert right before the attribute."""
- return self._padding
+ return self._pad_first
+
+ @property
+ def pad_before_eq(self):
+ """Spacing to insert right before the equal sign."""
+ return self._pad_before_eq
+
+ @property
+ def pad_after_eq(self):
+ """Spacing to insert right after the equal sign."""
+ return self._pad_after_eq
@name.setter
def name(self, value):
@@ -83,6 +96,14 @@ class Attribute(StringMixIn):
def quoted(self, value):
self._quoted = bool(value)
- @padding.setter
- def padding(self, value):
- self._padding = str(value)
+ @pad_first.setter
+ def pad_first(self, value):
+ self._pad_first = str(value)
+
+ @pad_before_eq.setter
+ def pad_before_eq(self, value):
+ self._pad_before_eq = str(value)
+
+ @pad_after_eq.setter
+ def pad_after_eq(self, value):
+ self._pad_after_eq = str(value)
diff --git a/mwparserfromhell/nodes/tag.py b/mwparserfromhell/nodes/tag.py
index cd5d0a2..76b412c 100644
--- a/mwparserfromhell/nodes/tag.py
+++ b/mwparserfromhell/nodes/tag.py
@@ -59,7 +59,7 @@ class Tag(Node):
result = "<" + str(self.tag)
if self.attributes:
- result += " " + " ".join([str(attr) for attr in self.attributes])
+ result += "".join([str(attr) for attr in self.attributes])
if self.self_closing:
result += self.padding + "/>"
else:
diff --git a/mwparserfromhell/parser/builder.py b/mwparserfromhell/parser/builder.py
index 53abe91..d92b845 100644
--- a/mwparserfromhell/parser/builder.py
+++ b/mwparserfromhell/parser/builder.py
@@ -180,9 +180,9 @@ class Builder(object):
else:
self._write(self._handle_token(token))
- def _handle_attribute(self, token):
+ def _handle_attribute(self, start):
"""Handle a case where a tag attribute is at the head of the tokens."""
- name, quoted, padding = None, False, token.padding
+ name, quoted = None, False
self._push()
while self._tokens:
token = self._tokens.pop()
@@ -194,9 +194,12 @@ class Builder(object):
elif isinstance(token, (tokens.TagAttrStart, tokens.TagCloseOpen,
tokens.TagCloseSelfclose)):
self._tokens.append(token)
- if name is not None:
- return Attribute(name, self._pop(), quoted, padding)
- return Attribute(self._pop(), quoted=quoted, padding=padding)
+ if name:
+ value = self._pop()
+ else:
+ name, value = self._pop(), None
+ return Attribute(name, value, quoted, start.pad_first,
+ start.pad_before_eq, start.pad_after_eq)
else:
self._write(self._handle_token(token))
diff --git a/tests/tokenizer/tags.mwtest b/tests/tokenizer/tags.mwtest
index 849a4fd..1dfc1b1 100644
--- a/tests/tokenizer/tags.mwtest
+++ b/tests/tokenizer/tags.mwtest
@@ -43,56 +43,56 @@ output: [TagOpenOpen(showtag=True), Text(text="ref"), TagCloseSelfclose(padding=
name: attribute
label: a tag with a single attribute
input: ""
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
---
name: attribute_value
label: a tag with a single attribute with a value
input: ""
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagAttrEquals(), Text(text="foo"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagAttrEquals(), Text(text="foo"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
---
name: attribute_quoted
label: a tag with a single quoted attribute
input: ""
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagAttrEquals(), TagAttrQuote(), Text(text="foo"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagAttrEquals(), TagAttrQuote(), Text(text="foo"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
---
name: attribute_hyphen
label: a tag with a single attribute, containing a hyphen
input: ""
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagAttrEquals(), Text(text="foo-bar"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagAttrEquals(), Text(text="foo-bar"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
---
name: attribute_quoted_hyphen
label: a tag with a single quoted attribute, containing a hyphen
input: ""
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagAttrEquals(), TagAttrQuote(), Text(text="foo-bar"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagAttrEquals(), TagAttrQuote(), Text(text="foo-bar"), TagCloseOpen(padding=""), TagOpenClose(), Text(text="ref"), TagCloseClose()]
---
name: attribute_selfclosing
label: a self-closing tag with a single attribute
input: ""
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagCloseSelfclose(padding="")]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagCloseSelfclose(padding="")]
---
name: attribute_selfclosing_value
label: a self-closing tag with a single attribute with a value
input: "["
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagAttrEquals(), Text(text="foo"), TagCloseSelfclose(padding="")]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagAttrEquals(), Text(text="foo"), TagCloseSelfclose(padding="")]
---
name: attribute_selfclosing_value_quoted
label: a self-closing tag with a single quoted attribute
input: "]"
-output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(padding=""), Text(text="name"), TagAttrEquals(), TagAttrQuote(), Text(text="foo"), TagCloseSelfclose(padding="")]
+output: [TagOpenOpen(showtag=True), Text(text="ref"), TagAttrStart(pad_first=" ", pad_before_eq="", pad_after_eq=""), Text(text="name"), TagAttrEquals(), TagAttrQuote(), Text(text="foo"), TagCloseSelfclose(padding="")]
---