The actual type of an element in Opera is uniquely determined by the tuple (T, N) where T is the numeric type code (or type) and N is the XML namespace (or namespace). The type is returned by HTML_Element::Type() and the namespace returned by HTML_Element::GetNsType(). The type of an element CAN NOT be uniquely be determined by looking at one of the components alone.
The numerical type is only unique within a namespace. That means that you can have two elements in different namespaces with the same numerical type. So unless a specific namespace is implied comparing two numerical types is ambigous.
The main reason for having two components for the actual type of an element is to have a logical separation of elements from different types of markup.
We could have done the segeregation by putting the different types from the different namespaces at different offsets, for instance let all the HTML types begin at 256 (like today) and all the WML types start at 1024. The two main reasons for not doing this is that we have limited room for the types (9 bits at the moment) and it would not be very scalable when adding new namespaces.
The namespace of an element is a numeric property indication which XML application (or markup type) the element belongs to. The namespace can be expressed in two ways, using the namespace enumerated type directly or using a namespace index.
The namespace index is an index into a global table of namespaces that contain a tag prefix, a namespace URI and a namespace type. For elements and attributes the namespace index is stored and not the namespace type.
When comparing namespaces it is not good enough just to compare the namespace indexes. Even though the namespaces must be equal if the namespace indexes are the same the reverse is not true. The namespace can be the same even though the namespace indexes are different. This because a namespace can be indicated using different tag prefixes that will get a different entry in the global table or the rare case where the same XML application has more than one namespace URI.
This means that we have to look up the correct namespace type in the global table when dealing with namespace indexes.
Here are some good tricks on how to handle the namespaces correctly and effectively.
If you have a function where most of the work done is different between the different namespaces a trick is to have an array with the handlers for the different namespaces and index that array by the namespace.
NS_Type ns = elm->GetNsType();
g_ns_handlers[ns]->doIt();
In this case you can assume that every Type() comparison withing the doIt() has the right namespace
If you have a function that only is supposed to work for one namespace type, for instance HTML, the first thing in the function should be to check the namespace of the element. If it doesn't match exit the function immediately.
void doIt(HTML_Element *elm)
{
if (elm->GetNsType() != NS_SVG)
return;
switch (elm->Type())
{
...
}
}
After the early exit (or an if-surrounding the entire function) you can safely compare just the numerical types in the rest of the function. In this case only elements with the NS_SVG namespace will be used in the switch
In a place where you handle several namespaces it can be a good thing to do a switch on the namespaces.
switch (elm->GetNsType())
{
case NS_WML:
{
if (elm->Type() == WE_CARD)
...
}
break;
...
}
If you only want to match the element agains one (or two or a few) specific type in one specific namespace the best trick is probably to use the HTML_Element::IsMatchingType() method.
if (elm->IsMatchingType(HE_OBJECT, NS_HTML))
...
In this case only the OBJECT elements in HTML will be matched.
An alternative to the IsMatchingType() trick is to do a comparison of both the namespace and type manually. This can be useful for instance if you want to check two types in the same namespace.
if ((elm->Type() == HE_DIV || elm->Type() == HE_SPAN) && elm->GetNsType() == NS_HTML)
...