getAttribute question

R

RobG

I have always accessed attributes such as disabled using the DOM
element property, however I was wondering about implementing a more
generic function to get the values of attributes - which of course
leads to the DOM Element Interface's getAttribute method:

<URL: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-666EE0F9 >

The DOM 2 Core specification says that getAttribute should return the
value of an attribute as a string, however attributes such as
disabled, checked, readonly, etc. don't have values specified in the
HTML specification, it just specifies a behaviour if the attribute is
present or not. The DOM HTML spec says that such attributes should
return true or false, e.g. Inteface HTMLInputElement:

<URL: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-50886781 >

My interpretation is that if the attribute is accessed as a property
of a DOM element (e.g. someElement.disabled), it should return:

1. boolean true if the element has the attribute set in the markup
or
it has been set to true by script
2. boolean false only if the attribute value has been set to false
by script
3. null if the attribute is not in the markup and hasn't been set by
script,
or if the element doesn't support the attribute

That way the value of the DOM property can be easily converted to an
equivalent string simply by using the returned object's toString
method ('true', 'false' and '' respectively) which seems to fit the
specification for getAttribute.

I don't know of a browser that behaves as described above, they all
have foibles. If I were to write a generic getAttributeValue
function, should it behave as described above, or should it instead
return 'disabled', '' and '' respectively? The logic could then be
applied to other "no value" attributes such as checked, readonly and
selected. Condition statements could be:

if (el.getAttributeValue('disabled') == 'true') { ... }

which is reasonably consistent with:

if (el.disabled) { ... }

What do others think?
 
J

Janwillem Borleffs

RobG schreef:
The DOM 2 Core specification says that getAttribute should return the
value of an attribute as a string, however attributes such as
disabled, checked, readonly, etc. don't have values specified in the
HTML specification, it just specifies a behaviour if the attribute is
present or not. The DOM HTML spec says that such attributes should
return true or false, e.g. Inteface HTMLInputElement:

The common way to specify this according to the current standards is:

<... disabled="disabled"/>

Browsers will parse this the same way as the old notation.


JW
 
T

Thomas 'PointedEars' Lahn

RobG said:
I have always accessed attributes such as disabled using the DOM
element property, however I was wondering about implementing a more
generic function to get the values of attributes - which of course
leads to the DOM Element Interface's getAttribute method:

<URL: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-666EE0F9 >

Not necessarily. ECMAScript implementations provide the bracket property
accessor to use variable string values as property names, and the number of
element properties that do not match the lowercase versions of their
attribute name is limited.

See also http://pointedears.de/scripts/dhtml.js:setAttr()
The DOM 2 Core specification says that getAttribute should return the
value of an attribute as a string, however attributes such as
disabled, checked, readonly, etc. don't have values specified in the
HTML specification,

Yes, they have.
it just specifies a behaviour if the attribute is present or not.

Not true:

http://www.w3.org/TR/html401/intro/sgmltut.html#h-3.3.4.2
The DOM HTML spec says that such attributes should
return true or false, e.g. Inteface HTMLInputElement:

<URL: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-50886781 >

My interpretation is that if the attribute is accessed as a property
of a DOM element (e.g. someElement.disabled), it should return:

1. boolean true if the element has the attribute set in the markup
or
it has been set to true by script
2. boolean false only if the attribute value has been set to false
by script
3. null if the attribute is not in the markup and hasn't been set by
script,
or if the element doesn't support the attribute
Correct.

That way the value of the DOM property can be easily converted to an
equivalent string simply by using the returned object's toString
method ('true', 'false' and '' respectively) which seems to fit the
specification for getAttribute.

Yes, you could. However, this is what setAttribute() is for.
I don't know of a browser that behaves as described above, they all
have foibles. If I were to write a generic getAttributeValue
function, should it behave as described above,

It should not return boolean values as content of string values.
or should it instead return 'disabled', '' and '' respectively? The
logic could then be applied to other "no value" attributes such as
checked, readonly and selected. Condition statements could be:

if (el.getAttributeValue('disabled') == 'true') { ... }

which is reasonably consistent with:

if (el.disabled) { ... }

What do others think?

You should implement

if (_getAttributeValue(el, 'disabled'))

if you don't like

if (el.getAttribute('disabled').toLowerCase() == 'disabled')

already. As you should know by now, host objects should not be tried
to be augmented, and they cannot be prototyped universally.


PointedEars
 
R

RobG

Not necessarily. ECMAScript implementations provide the bracket property
accessor to use variable string values as property names, and the number of
element properties that do not match the lowercase versions of their
attribute name is limited.

See alsohttp://pointedears.de/scripts/dhtml.js:setAttr()

I'm interested in your mapping of char to ch, why is that? I noted an
oddity with IE that getAttribute('ch') returns an empty string if the
attribute isn't present when it should return null.

Also you have:

colSpan: "colSpan",

should the property name have a lower case 's'?


Thanks, it would have been nice if a reference to that was included in
appropriate places in the HTML 4 and DOM HTML specifications.

Yes, you could. However, this is what setAttribute() is for.


It should not return boolean values as content of string values.

It could return the object's toString value rather than the object.
You should implement

if (_getAttributeValue(el, 'disabled'))

if you don't like

if (el.getAttribute('disabled').toLowerCase() == 'disabled')

already. As you should know by now, host objects should not be tried
to be augmented, and they cannot be prototyped universally.

I wasn't suggesting augmenting host objects, I was just looking for a
consistent way to get attribute values. The following function seems
to do the trick, I haven't tested it widely yet. It has an issue with
IE and attributes named 'ch', I await your response from the question
above.


function getAttributeValue(element, attribute)
{
var v, lowerAtt,
htmlFlags = {
checked: 'checked',
compact: 'compact', // deprecated HTML 4
declare: 'declare',
defer: 'defer',
disabled: 'disabled',
ismap: 'ismap',
multiple: 'multiple',
nohref: 'nohref',
noresize: 'noresize',
noshade: 'noshade',
nowrap: 'nowrap', // deprecated HTML 4
readonly: 'readonly',
selected: 'selected'
},
mapFwd = {
alink: 'aLink',
accesskey: 'accessKey',
bgcolor: 'bgColor',
cellpadding: 'cellPadding',
cellspacing: 'cellSpacing',
'char': 'ch',
charoff: 'chOff',
'class': 'className',
codebase: 'codeBase',
codetype: 'codeType',
colspan: 'colSpan',
datetime: 'dateTime',
frameborder: 'frameBorder',
'for': 'htmlFor',
ismap: 'isMap',
longdesc: 'longDesc',
maxlength: 'maxLength',
marginheight:'marginHeight',
marginwidth: 'marginWidth',
nohref: 'noHref',
noresize: 'noResize',
noshade: 'noShade',
nowrap: 'noWrap',
readonly: 'readOnly',
rowspan: 'rowSpan',
tabindex: 'tabIndex',
usemap: 'useMap',
valuetype: 'valueType',
vlink: 'vLink'
},
mapRev = {
classname: 'class',
// ch: 'char',
htmlfor: 'for'
};

if (typeof attribute == 'string') {
lowerAtt = attribute.toLowerCase();

if (lowerAtt in htmlFlags) {
return !!element[attribute]? htmlFlags[lowerAtt] : '';
}

v = element.getAttribute(attribute);

if (v === null) {
v = element.getAttribute(mapFwd[lowerAtt]);
}

if (v === null) {
v = element.getAttribute(mapRev[lowerAtt]);
}

return v;
}
}
 
T

Thomas 'PointedEars' Lahn


(Eeek, Google Groups posting.)
I'm interested in your mapping of char to ch, why is that?

The `char' attribute of HTML 4.01 `COL', `COLGROUP', `TBODY', `TD', `TFOOT',
`TH', `THEAD', and `TR' elements, and their lowercase XHTML 1.0 correlates,
is represented by the `ch' attribute of the HTMLTableColElement,
HTMLTableSectionElement, HTMLTableCellElement, and HTMLTableRowElement
interfaces of W3C DOM Level 2 HTML, and the `ch' property of the objects
implementing these, respectively.

http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-84150186
http://www.w3.org/TR/DOM-Level-2-HTML/ecma-script-binding.html
I noted an oddity with IE that getAttribute('ch') returns an empty string if the
attribute isn't present when it should return null.

However, this is unsurprising, as it should have been getAttribute('char').
Also you have:

colSpan: "colSpan",

should the property name have a lower case 's'?

Yes, it should. It had been fixed already in the local version (currently
0.9.4.2008042321), but thanks anyway.
It could return the object's toString value rather than the object.

Which object are you talking about? We are dealing with *primitive values*
here. So if a method is to return the value of a boolean HTML attribute,
there are two implementations I would consider reasonable: Either a) return
the *boolean* values `true' or `false', or b) return the proper attribute
values as strings, i.e. e.g. "disabled" if set and "" if not set. Either
way, it should be easy to use the return value in a conditional expression,
which both proposed implementations would accomplish.
I wasn't suggesting augmenting host objects, I was just looking for a
consistent way to get attribute values.

But el.getAttributeValue() is suggesting host object augmentation, is it not?
[...]
function getAttributeValue(element, attribute)
{
var v, lowerAtt,
htmlFlags = {
checked: 'checked',
compact: 'compact', // deprecated HTML 4
declare: 'declare',
defer: 'defer',
disabled: 'disabled',
ismap: 'ismap',
multiple: 'multiple',
nohref: 'nohref',
noresize: 'noresize',
noshade: 'noshade',
nowrap: 'nowrap', // deprecated HTML 4
readonly: 'readonly',
selected: 'selected'
},

There really is no need for `htmlFlags'.
mapFwd = {
[...]
},

ACK. This is also what I have.
mapRev = {
classname: 'class',
// ch: 'char',
htmlfor: 'for'
};

Why do you consider this necessary? Are we talking HTML attributes or not?
if (typeof attribute == 'string') {

This is not required, and unnecessarily limits the ways this method may be
applied.
lowerAtt = attribute.toLowerCase();

I understand you test for the string type above because of this assignment,
however any value can be converted to string easily:

lowerAtt = String(attribute).toLowerCase();

(attribute.toString() is not always feasible.)
if (lowerAtt in htmlFlags) {

For reasons I mentioned before, the `in' operator should be avoided outside
`for..in' statements for the time being.
return !!element[attribute]? htmlFlags[lowerAtt] : '';

While written more conveniently, the test accesses a property of a host
object without testing for it first which is considered error-prone.
}

v = element.getAttribute(attribute);

Much the same here.
if (v === null) {
v = element.getAttribute(mapFwd[lowerAtt]);
}

if (v === null) {
v = element.getAttribute(mapRev[lowerAtt]);
}

Your assertions are not supported by the W3C DOM Level 2 and 3 Core
Specifications. According to these, Element::getAttribute() never returns
`null'. Faulty implementations do not justify your deliberately violating
the standard yourself. So the least you have to consider instead is

if (!v)
{
return v;
}
}


Regards,

PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top