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