Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VBS GetElementByClassName custom function

1,229 views
Skip to first unread message

mrique

unread,
Oct 8, 2007, 4:12:47 AM10/8/07
to
Hi

I'm driving ie from vbs scripts, and i'd like to finalize a custom
"get element by class name" function to operate on the dom of web page
i grab.

I found nice javascripts function (http://ejohn.org/blog/
getelementsbyclassname-speed-comparison/) like this one

1. function getElementsByClass(searchClass,node,tag) {
2. var classElements = new Array();
3. if ( node == null )
4. node = document;
5. if ( tag == null )
6. tag = '*';
7. var els = node.getElementsByTagName(tag);
8. var elsLen = els.length;
9. var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|
$)");
10. for (i = 0, j = 0; i < elsLen; i++) {
11. if ( pattern.test(els[i].className) ) {
12. classElements[j] = els[i];
13. j++;
14. }
15. }
16. return classElements;
17. }

I'm trying to translate it into vbs but.. can not figure how to
please look at my snippet
'-----------------------------------------------------
function getelementsbyclassname(domnode, sclass)
'-----------------------------------------------------
set my_xml = createobject("Msxml2.DOMDocument.3.0")
Set rootNode = my_xml.documentElement
set els = domnode.getElementsByTagName("*")
for i = 0 to els.length-1
set mnode = els.item(i)
if mnode.nodeType=1 then
for each at in mnode.attributes
if at.name = "class" and at.value = sclass then
rootNode.appendChild(mnode)
end if
next
end if
next
getelementsbyclassname = my_xml
end function

Anthony Jones

unread,
Oct 8, 2007, 6:25:40 AM10/8/07
to
"mrique" <mriqu...@gmail.com> wrote in message
news:1191831167....@r29g2000hsg.googlegroups.com...

rootNode is nothing at this point since the DOM you've created contains no
XML.

> set els = domnode.getElementsByTagName("*")
> for i = 0 to els.length-1
> set mnode = els.item(i)

why not simply:-

For Each mnode in domnode.getElementsByTagName("*")


> if mnode.nodeType=1 then

I don't think getElementsByTagName can return anything but Elements so the
nodeType will always be 1 hence the above test may well be redundant.

> for each at in mnode.attributes
> if at.name = "class" and at.value = sclass then

If your happy to be case sensitive (IE you know the attribute class name
will be all lower case):

atClass = mnode.attributes.getNamedItem("class")
If atClass.value = sclass Then

The code assumes the element will only have one class name (HTML allows
mutliple class names to be attachment to element by using a space delimited
set of class names in this attribute. If you want to selectnodes that have
this class name whilst also having others you need a RegEx:-

Dim rgx : Set rgx = New RegExp
rgx.Pattern = "\b" & sclass & "\b"

atClass = mnode.attributes.getNamedItem("class")
If rgx.Test(atClass.value) Then

If you can't be sure of the case the class attribute will be in then you
need to use the loop you were using but you need LCase(at.name) = "class"
when finding the attribute.

> rootNode.appendChild(mnode)

Your code appears to assume that the domnode passed in is an XML DOM node
not a HTML DOM node from IE, is that actually true? If not you can't
appendChild from a HTML Node into an XML Node.

The JScript code is merely returning an array could you do that instead?

Note if you are receiving an XML Node you should note that the appendChild
will be removing the mnode form the source document. This isn't a good idea
when enumerating the document since that results in undefined behaviour
typically manifested as elements being skipped by the enumerator.

In that case use:-

rootNode.appendChild(mnode.cloneNode(true))

Another issue you may not be aware of is that with above code inplace an
element with the specified class name may well contain a child node also
specifing the class which means a copy of the child node appears twice in
the output, once as a child of the parent and once as child of the root
element.

> end if
> next
> end if
> next
> getelementsbyclassname = my_xml

You must use set to return an object:-

Set getelementsbyclassname = my_xml

> end function


--
Anthony Jones - MVP ASP/ASP.NET


mrique

unread,
Oct 8, 2007, 11:49:25 AM10/8/07
to
thks alot for your contribution, really helpfull
just one question about dom type :

"Your code appears to assume that the domnode passed in is an XML DOM
node
not a HTML DOM node from IE, is that actually true? If not you can't
appendChild from a HTML Node into an XML Node. "

I agree with your proposition, but could you help me in creating an
html dom handler ?

could i make sg like this :
set my_html_dom = createobject("htmlfile")


mayayana

unread,
Oct 8, 2007, 2:15:58 PM10/8/07
to
I may be misunderstanding what you want to
do, but if you want all elements of a certain class,
can't you just use Document.All and check the className
attribute of each Item in All?

Anthony Jones

unread,
Oct 9, 2007, 6:14:16 AM10/9/07
to
"mrique" <mriqu...@gmail.com> wrote in message
news:1191858565.6...@r29g2000hsg.googlegroups.com...

I've never tried that so I can't say whether that'll work. I guess it
depends on whether MSHTML use the same memory management approach that MSXML
does. My gut feeling is that it doesn't in which case you won't be able to
append a node from document into another (even a cloned one). However I
could be wrong, you'll just have to try it.

Anthony Jones

unread,
Oct 9, 2007, 6:16:04 AM10/9/07
to
"mayayana" <mayaXX...@mindXXspring.com> wrote in message
news:%23HKdKed...@TK2MSFTNGP04.phx.gbl...

> I may be misunderstanding what you want to
> do, but if you want all elements of a certain class,
> can't you just use Document.All and check the className
> attribute of each Item in All?
>

document.all would be equivalent to doing document.getElementsByTagName("*")
so the OP is still left with all the original problems with the port.

mayayana

unread,
Oct 9, 2007, 9:23:39 AM10/9/07
to
> > I may be misunderstanding what you want to
> > do, but if you want all elements of a certain class,
> > can't you just use Document.All and check the className
> > attribute of each Item in All?
> >
>
> document.all would be equivalent to doing
document.getElementsByTagName("*")
> so the OP is still left with all the original problems with the port.
>

Yes, but it's easy enough to filter those by tagName
and then className, or vice versa. I'm confused as to why
there would be any reason to even consider bringing XML
or RegExp into it when simple DOM does the job.


Anthony Jones

unread,
Oct 9, 2007, 9:45:21 AM10/9/07
to
"mayayana" <mayaXX...@mindXXspring.com> wrote in message
news:%23vuKffn...@TK2MSFTNGP03.phx.gbl...

The XML came in to it because the OP wants to output a new DOM containing
the selected nodes. Unfortunately it isn't possible to insert nodes from a
HTML document into an XML document.

The RegExp comes into it from the source JScript to determine whether a
specific node has a specific class name in its class attribute. Whether the
node is retrieved by looping 'getElementsByTagName("*")' or by 'all' this
test needs to be done. As I explained in an earlier post the class
attribute may contain multiple class names.

0 new messages