3

I found out, that document.getElementById doesn't see ids of these elements, that are placed in some namespace. At least in FF30.0 and IE11 (don't know about other browsers); Consider this JSP snippet (to force Content-Type; probably it would work with meta http-equiv also):

HTML:

<!DOCTYPE html>
<%@ page language="java" contentType="application/xhtml+xml; charset=UTF-8" pageEncoding="UTF-8" %>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:t="urn:test">
<head>
    <meta charset="UTF-8"/>
    <title>Test</title>
    <style type="text/css">
@namespace "http://www.w3.org/1999/xhtml";
@namespace t "urn:test";
html {
    font-family: 'Open Sans', 'Calibri', 'Arial', sans-serif;
    font-size: 11px;
}
t|foo {
    display: inline-block;
    border: solid 1px #AAA;
    border-radius: 2px;
    background-color: #EEE;
    padding: 0px 3px;
}
</style>

JS:

function init() {
    var NS_TEST = 'urn:test';
    var NS_HTML = 'http://www.w3.org/1999/xhtml';
    var foo = document.getElementById('foo');
    console.log('foo!=null?' + (foo !== null));
    var foos = document.getElementsByTagNameNS(NS_TEST, 'foo');
    console.log('foos.length=' + foos.length);
    // assert foos.length == 1;
    foo = foos[0];
    console.log('foo.id                  : ' + foo.id);
    console.log('foo.getAttribute()      : ' + foo.getAttribute('id'));
    console.log('foo.getAttributeNS(TEST): ' + foo.getAttributeNS(NS_TEST, 'id'));
    console.log('foo.getAttributeNS(HTML): ' + foo.getAttributeNS(NS_HTML, 'id'));
}
window.onload = init;

HTML:

<body>
    <div>
        <t:foo id="foo">Foo indeed</t:foo>
    </div>
</body>
</html>

In both mentioned browsers t:foo element gets styled according to CSS rules, but note console output:

FF:

foo!=null?false
foos.length=1
foo.id                  : foo
foo.getAttribute()      : foo
foo.getAttributeNS(TEST): null
foo.getAttributeNS(HTML): null

IE:

foo!=null?false
foos.length=1
foo.id                  : undefined
foo.getAttribute()      : foo
foo.getAttributeNS(TEST): 
foo.getAttributeNS(HTML): 

Both browsers return false on foo != null, but getting the element with document.getElementsByTagNameNS actually finds it in DOM and in both cases foo.getAttribute('id') returns valid id. Note, that it does not exists in http://www.w3.org/1999/xhtml namespace thou default namespace is specified in html element. Does anyone have any idea how to get elements with defined id for elements placed in some namespace like in the example above? Or maybe I need to add some extra declaration (<?xml ...?> didn't help).

1 Answer 1

1

OK. First of all Chrome reports "true" for the foo!=null? test. (Other results are the same as Firefox for the next three tests and same as IE for the last two.)

The spec for getElementById() in DOM Level 3 says

Returns the Element that has an ID attribute with the given value. If no such element exists, this returns null. If more than one element has an ID attribute with that value, what is returned is undefined. The DOM implementation is expected to use the attribute Attr.isId to determine if an attribute is of type ID.

Note: Attributes with the name "ID" or "id" are not of type ID unless so defined.

Since there is nothing in your document to define the foo element in the urn:test namespace as being of type ID, browsers that comply with DOM Level 3 on this point will return null.

DOM4, on the other hand, says

The getElementById(elementId) method must return the first element, in tree order, within context object's descendants, whose ID is elementId, and null if there is no such element otherwise.

and on ID says

Historically elements could have multiple identifiers e.g. by using the HTML id attribute and a DTD. This specification makes ID a concept of the DOM and allows for only one per element, given by an id attribute.

and

An A attribute is an attribute whose local name is A and whose namespace and namespace prefix are null.

So browsers that comply in DOM4 on this point will return the foo element.

The id attribute is in the null namespace in DOM Level 3 and DOM4, and all browser behave in accordance with that.

So your elements and attributes are all already in the correct namespaces, it's just that getElementById doesn't necessarily apply to elements in custom namespaces.

As far as I can tell, there is no way that the id attribute on elements in the urn:test namespace can be defined as being of type ID such that getElementById will match the element in Firefox or IE.

I would suggest that you use a different way of finding elements in custom namespaces that have an id attribute with a specific value.

For example, var foo = document.querySelector('[id=foo]'); will match the element in all three browsers.

Sign up to request clarification or add additional context in comments.

7 Comments

+1 for working solution. As to declaring attribute id as of type ID --- I just created simple XSD with definition of foo element with single attribute id of type xsd:ID, included it in head (via xsi:schemaLocation), but both IE and FF seem to ignore it. So there is actually a way to tell that the id attribute should be considered as ID, but those browsers lack support of XSD. On the other hand it seems to be some inconsistence, as default namespace is http://www.w3.org/1999/xhtml where t:foo's id attribute belongs to. Getting it via getAttributeNS returns null thou.
The bit about the id attribute belonging to the http://www.w3.org/1999/xhtml is incorrect. As I say in my answer, the id attribute will be in the null namespace. If you want an attribute to be in the http://www.w3.org/1999/xhtml namespace, you have to say so explicitly with a prefix. i.e. <t:foo h:id="foo" xmlns:h="http://www.w3.org/1999/xhtml">
Are you 100% positive about that? It's XML, not HTML (and its tag soup) and default namespace has been declared in html tag. At least I used to think about that this way. Can you clarify, please? (Thanks in advance)
Yes, I'm sure. Default namespaces just don't apply to attributes in XML, only to elements. See Namespaces in XML, section 6.2. - "A default namespace declaration applies to all unprefixed element names within its scope. Default namespace declarations do not apply directly to attribute names; the interpretation of unprefixed attributes is determined by the element on which they appear."
Sadly, still no. The type of each attribute is defined on a per element basis in the DTD or schema, not on the basis of the namespace (which in any case is the null namespace in HTML as well as XML). For example, looking at w3.org/TR/html4/index/attributes.html, the type of the "width" attribute is variously %Length, %MultiLength or NUMBER depending on the element.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.