msxml: Implement getElementsByTagName

Huw D M Davies h.davies1 at physics.ox.ac.uk
Mon Feb 13 10:51:56 CST 2006


        Huw Davies <huw at codeweavers.com>
        msxml: Implement getElementsByTagName
-- 
Huw Davies
huw at codeweavers.com
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c
index 33cdaf5..9e30ed5 100644
--- a/dlls/msxml3/domdoc.c
+++ b/dlls/msxml3/domdoc.c
@@ -656,8 +656,16 @@ static HRESULT WINAPI domdoc_getElements
     BSTR tagName,
     IXMLDOMNodeList** resultList )
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    domdoc *This = impl_from_IXMLDOMDocument( iface );
+    xmlChar *name;
+    TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
+
+    name = xmlChar_from_wchar((WCHAR*)tagName);
+    *resultList = create_filtered_nodelist((xmlNodePtr)get_doc(This), name, TRUE);
+    HeapFree(GetProcessHeap(), 0, name);
+
+    if(!*resultList) return S_FALSE;
+    return S_OK;
 }
 
 static DOMNodeType get_node_type(VARIANT Type)
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index fc693ed..220460c 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -37,7 +37,7 @@ extern IUnknown         *create_element(
 extern IUnknown         *create_text( xmlNodePtr text );
 extern IXMLDOMNodeList  *create_nodelist( xmlNodePtr node );
 extern IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node );
-extern IXMLDOMNodeList  *create_filtered_nodelist( xmlNodePtr, const xmlChar * );
+extern IXMLDOMNodeList  *create_filtered_nodelist( xmlNodePtr, const xmlChar *, BOOL );
 
 extern void attach_xmlnode( IXMLDOMNode *node, xmlNodePtr xmlnode );
 
diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c
index 58bdd92..d7efe62 100644
--- a/dlls/msxml3/node.c
+++ b/dlls/msxml3/node.c
@@ -314,11 +314,11 @@ static HRESULT WINAPI xmlnode_get_childN
     switch(This->node->type)
     {
     case XML_ELEMENT_NODE:
-        *childList = create_filtered_nodelist( This->node->children, (const xmlChar *)"*" );
+        *childList = create_filtered_nodelist( This->node->children, (const xmlChar *)"*", FALSE );
         break;
 
     case XML_ATTRIBUTE_NODE:
-        *childList = create_filtered_nodelist( This->node->children, (const xmlChar *)"node()" );
+        *childList = create_filtered_nodelist( This->node->children, (const xmlChar *)"node()", FALSE );
         break;
 
     default:
@@ -620,7 +620,7 @@ static HRESULT WINAPI xmlnode_selectNode
     if( !This->node->children )
         return S_FALSE;
 
-    *resultList = create_filtered_nodelist( This->node->children, str );
+    *resultList = create_filtered_nodelist( This->node->children, str, FALSE );
     HeapFree( GetProcessHeap(), 0, str );
     return S_OK;
 }
diff --git a/dlls/msxml3/nodelist.c b/dlls/msxml3/nodelist.c
index 806985c..407c5f7 100644
--- a/dlls/msxml3/nodelist.c
+++ b/dlls/msxml3/nodelist.c
@@ -52,7 +52,7 @@ struct xslt_info {
     xsltStylesheetPtr sheet;
 };
 
-static void xlst_info_init( struct xslt_info *info )
+static void xslt_info_init( struct xslt_info *info )
 {
     info->ctxt = NULL;
     info->pattern = NULL;
@@ -86,7 +86,10 @@ void free_xslt_info( struct xslt_info *i
         xsltFreeTransformContext( info->ctxt );
 }
 
-static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node )
+
+static xmlNodePtr get_next_node( struct xslt_info *info, xmlNodePtr node, xmlNodePtr *top_level_node );
+
+static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node, xmlNodePtr *top_level_node )
 {
     if (!info->ctxt)
         return S_FALSE;
@@ -107,7 +110,7 @@ static HRESULT xslt_next_match( struct x
             ERR("Pattern match failed\n");
             return E_FAIL;
         }
-        *node = (*node)->next;
+        *node = get_next_node(info, *node, top_level_node);
     }
     return S_OK;
 }
@@ -118,7 +121,7 @@ struct xslt_info {
     /* empty */
 };
 
-static void xlst_info_init( struct xslt_info *info )
+static void xslt_info_init( struct xslt_info *info )
 {
 }
 
@@ -132,19 +135,42 @@ static int create_xslt_parser( struct xs
     return 0;
 }
 
-static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node )
+static HRESULT xslt_next_match( struct xslt_info *info, xmlNodePtr *node, xmlNodePtr *top_level_node )
 {
     return S_FALSE;
 }
 
 #endif
 
+static xmlNodePtr get_next_node( struct xslt_info *info, xmlNodePtr node, xmlNodePtr *top_level_node )
+{
+    if(!top_level_node) return node->next;
+
+    if(node->children) return node->children;
+    if(node->next)
+    {
+        if(node == *top_level_node)
+            *top_level_node = node->next;
+        return node->next;
+    }
+
+    if(node != *top_level_node && node->parent)
+    {
+        if(node->parent == *top_level_node)
+            *top_level_node = node->parent->next;
+        return node->parent->next;
+    }
+    return NULL;
+}
+
 typedef struct _xmlnodelist
 {
     const struct IXMLDOMNodeListVtbl *lpVtbl;
     LONG ref;
     xmlNodePtr node;
     xmlNodePtr current;
+    xmlNodePtr top_level_node;
+    BOOL enum_children;
     struct xslt_info xinfo;
 } xmlnodelist;
 
@@ -252,7 +278,8 @@ static HRESULT WINAPI xmlnodelist_get_it
         IXMLDOMNode** listItem)
 {
     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
-    xmlNodePtr curr;
+    xmlNodePtr curr, tmp;
+    xmlNodePtr *top_level_node = NULL;
     long nodeIndex = 0;
     HRESULT r;
 
@@ -265,12 +292,18 @@ static HRESULT WINAPI xmlnodelist_get_it
 
     curr = This->node;
 
+    if(This->enum_children)
+    {
+        tmp = curr;
+        top_level_node = &tmp;
+    }
+
     while(curr)
     {
-        r = xslt_next_match( &This->xinfo, &curr );
+        r = xslt_next_match( &This->xinfo, &curr, top_level_node);
         if(FAILED(r) || !curr) return S_FALSE;
         if(nodeIndex++ == index) break;
-        curr = curr->next;
+        curr = get_next_node(&This->xinfo, curr, top_level_node);
     }
     if(!curr) return S_FALSE;
 
@@ -284,7 +317,8 @@ static HRESULT WINAPI xmlnodelist_get_le
         long* listLength)
 {
 
-    xmlNodePtr curr;
+    xmlNodePtr curr, tmp;
+    xmlNodePtr *top_level_node = NULL;
     long nodeCount = 0;
     HRESULT r;
 
@@ -297,9 +331,15 @@ static HRESULT WINAPI xmlnodelist_get_le
 	return S_OK;
     }
         
-    for(curr = This->node; curr; curr = curr->next)
+    if(This->enum_children)
+    {
+        tmp = curr;
+        top_level_node = &tmp;
+    }
+
+    for(curr = This->node; curr; curr = get_next_node(&This->xinfo, curr, top_level_node))
     {
-        r = xslt_next_match( &This->xinfo, &curr );
+        r = xslt_next_match( &This->xinfo, &curr, top_level_node );
         if(FAILED(r) || !curr) break;
         nodeCount++;
     }
@@ -314,10 +354,14 @@ static HRESULT WINAPI xmlnodelist_nextNo
 {
     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
     HRESULT r;
+    xmlNodePtr *top_level_node = NULL;
 
     TRACE("%p %p\n", This, nextItem );
 
-    r = xslt_next_match( &This->xinfo, &This->current );
+    if(This->enum_children)
+        top_level_node = &This->top_level_node;
+
+    r = xslt_next_match( &This->xinfo, &This->current, top_level_node );
     if (FAILED(r) )
         return r;
 
@@ -325,7 +369,7 @@ static HRESULT WINAPI xmlnodelist_nextNo
         return S_FALSE;
 
     *nextItem = create_node( This->current );
-    This->current = This->current->next;
+    This->current = get_next_node(&This->xinfo, This->current, top_level_node);
     return S_OK;
 }
 
@@ -375,8 +419,10 @@ static xmlnodelist *new_nodelist( xmlNod
     nodelist->lpVtbl = &xmlnodelist_vtbl;
     nodelist->ref = 1;
     nodelist->node = node;
-    nodelist->current = node;
-    xlst_info_init( &nodelist->xinfo );
+    nodelist->current = node; 
+    nodelist->top_level_node = node;
+    nodelist->enum_children = FALSE;
+    xslt_info_init( &nodelist->xinfo );
 
     xmldoc_add_ref( node->doc );
 
@@ -391,12 +437,15 @@ IXMLDOMNodeList* create_nodelist( xmlNod
     return (IXMLDOMNodeList*) &nodelist->lpVtbl;
 }
 
-IXMLDOMNodeList* create_filtered_nodelist( xmlNodePtr node, const xmlChar *str )
+IXMLDOMNodeList* create_filtered_nodelist( xmlNodePtr node, const xmlChar *str, BOOL enum_children )
 {
     xmlnodelist *This = new_nodelist( node );
 
     if (create_xslt_parser( &This->xinfo, node, str ))
+    {
+        This->enum_children = enum_children;
         return (IXMLDOMNodeList*) &This->lpVtbl;
+    }
 
     IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
     return NULL;
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 901afc5..c791a5e 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -73,6 +73,7 @@ static const WCHAR szlc[] = { 'l','c',0 
 static const WCHAR szbs[] = { 'b','s',0 };
 static const WCHAR szstr1[] = { 's','t','r','1',0 };
 static const WCHAR szstr2[] = { 's','t','r','2',0 };
+static const WCHAR szstar[] = { '*',0 };
 
 void test_domdoc( void )
 {
@@ -775,6 +776,64 @@ static void test_create(void)
     IXMLDOMDocument_Release( doc );
 }
 
+static void test_getElementsByTagName(void)
+{
+    HRESULT r;
+    BSTR str;
+    VARIANT_BOOL b;
+    IXMLDOMDocument *doc;
+    IXMLDOMNodeList *node_list;
+    LONG len;
+
+    r = CoCreateInstance( &CLSID_DOMDocument, NULL, 
+        CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc );
+    if( r != S_OK )
+        return;
+
+    str = SysAllocString( szComplete4 );
+    r = IXMLDOMDocument_loadXML( doc, str, &b );
+    ok( r == S_OK, "loadXML failed\n");
+    ok( b == VARIANT_TRUE, "failed to load XML string\n");
+    SysFreeString( str );
+
+    str = SysAllocString( szstar );
+    r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list);
+    ok( r == S_OK, "ret %08lx\n", r );
+    r = IXMLDOMNodeList_get_length( node_list, &len );
+    ok( r == S_OK, "ret %08lx\n", r );
+    ok( len == 3, "len %ld\n", len );
+    IXMLDOMNodeList_Release( node_list );
+    SysFreeString( str );
+
+    str = SysAllocString( szbs );
+    r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list);
+    ok( r == S_OK, "ret %08lx\n", r );
+    r = IXMLDOMNodeList_get_length( node_list, &len );
+    ok( r == S_OK, "ret %08lx\n", r );
+    ok( len == 1, "len %ld\n", len );
+    IXMLDOMNodeList_Release( node_list );
+    SysFreeString( str );
+
+    str = SysAllocString( szdl );
+    r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list);
+    ok( r == S_OK, "ret %08lx\n", r );
+    r = IXMLDOMNodeList_get_length( node_list, &len );
+    ok( r == S_OK, "ret %08lx\n", r );
+    ok( len == 0, "len %ld\n", len );
+    IXMLDOMNodeList_Release( node_list );
+    SysFreeString( str );
+
+    str = SysAllocString( szstr1 );
+    r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list);
+    ok( r == S_OK, "ret %08lx\n", r );
+    r = IXMLDOMNodeList_get_length( node_list, &len );
+    ok( r == S_OK, "ret %08lx\n", r );
+    ok( len == 0, "len %ld\n", len );
+    IXMLDOMNodeList_Release( node_list );
+    SysFreeString( str );
+
+    IXMLDOMDocument_Release( doc );
+}
 
 START_TEST(domdoc)
 {
@@ -787,6 +846,7 @@ START_TEST(domdoc)
     test_domnode();
     test_refs();
     test_create();
+    test_getElementsByTagName();
 
     CoUninitialize();
 }



More information about the wine-patches mailing list