diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 33cdaf50855..9e30ed55ada 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -656,8 +656,16 @@ static HRESULT WINAPI domdoc_getElementsByTagName( 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 fc693ed014c..220460cad3d 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -37,7 +37,7 @@ extern IUnknown *create_element( xmlNodePtr 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 58bdd9202aa..d7efe62ca26 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -314,11 +314,11 @@ static HRESULT WINAPI xmlnode_get_childNodes( 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_selectNodes( 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 806985c84db..407c5f76b33 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 *info ) 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 xslt_info *info, xmlNodePtr *node ) 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 xslt_info *info, xmlNodePtr node, const xm 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_item( 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_item( 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_length( 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_length( return S_OK; } - for(curr = This->node; curr; curr = curr->next) + if(This->enum_children) { - r = xslt_next_match( &This->xinfo, &curr ); + 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, top_level_node ); if(FAILED(r) || !curr) break; nodeCount++; } @@ -314,10 +354,14 @@ static HRESULT WINAPI xmlnodelist_nextNode( { 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_nextNode( 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( xmlNodePtr node ) 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( xmlNodePtr node ) 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 901afc51b75..c791a5e1bca 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(); }