Commit 1c3daceb authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

msxml: Implement getElementsByTagName.

parent 964ef89f
......@@ -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)
......
......@@ -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 );
......
......@@ -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;
}
......
......@@ -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)
{
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_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;
......
......@@ -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();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment