msxml3: Fix domdoc_getElementsByTagName()/domelem_getElementsByTagName().

This commit is contained in:
Adam Martinson 2010-11-22 20:59:20 -06:00 committed by Alexandre Julliard
parent 6f537c4df1
commit f3678ec193
6 changed files with 87 additions and 83 deletions

View file

@ -198,6 +198,11 @@ BOOL is_xpathmode(const xmlDocPtr doc)
return properties_from_xmlDocPtr(doc)->XPath;
}
void set_xpathmode(xmlDocPtr doc, BOOL xpath)
{
properties_from_xmlDocPtr(doc)->XPath = xpath;
}
int registerNamespaces(xmlXPathContextPtr ctxt)
{
int n = 0;
@ -1766,6 +1771,47 @@ static HRESULT WINAPI domdoc_createEntityReference(
return hr;
}
xmlChar* tagName_to_XPath(const BSTR tagName)
{
xmlChar *query, *tmp;
static const xmlChar mod_pre[] = "*[local-name()='";
static const xmlChar mod_post[] = "']";
static const xmlChar prefix[] = "descendant::";
const WCHAR *tokBegin, *tokEnd;
int len;
query = xmlStrdup(prefix);
tokBegin = tagName;
while (tokBegin && *tokBegin)
{
switch (*tokBegin)
{
case '/':
query = xmlStrcat(query, BAD_CAST "/");
++tokBegin;
break;
case '*':
query = xmlStrcat(query, BAD_CAST "*");
++tokBegin;
break;
default:
query = xmlStrcat(query, mod_pre);
tokEnd = tokBegin;
while (*tokEnd && *tokEnd != '/')
++tokEnd;
len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
tmp = xmlMalloc(len);
WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
query = xmlStrncat(query, tmp, len);
xmlFree(tmp);
tokBegin = tokEnd;
query = xmlStrcat(query, mod_post);
}
}
return query;
}
static HRESULT WINAPI domdoc_getElementsByTagName(
IXMLDOMDocument3 *iface,
@ -1773,41 +1819,20 @@ static HRESULT WINAPI domdoc_getElementsByTagName(
IXMLDOMNodeList** resultList )
{
domdoc *This = impl_from_IXMLDOMDocument3( iface );
xmlChar *query;
HRESULT hr;
BOOL XPath;
TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagName), resultList);
TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
if (!tagName || !resultList) return E_INVALIDARG;
if (tagName[0] == '*' && tagName[1] == 0)
{
static const WCHAR formatallW[] = {'/','/','*',0};
hr = queryresult_create((xmlNodePtr)get_doc(This), formatallW, resultList);
}
else
{
static const WCHAR xpathformat[] =
{ '/','/','*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\'' };
static const WCHAR closeW[] = { '\'',']',0 };
LPWSTR pattern;
WCHAR *ptr;
INT length;
length = lstrlenW(tagName);
/* without two WCHARs from format specifier */
ptr = pattern = heap_alloc(sizeof(xpathformat) + length*sizeof(WCHAR) + sizeof(closeW));
memcpy(ptr, xpathformat, sizeof(xpathformat));
ptr += sizeof(xpathformat)/sizeof(WCHAR);
memcpy(ptr, tagName, length*sizeof(WCHAR));
ptr += length;
memcpy(ptr, closeW, sizeof(closeW));
hr = queryresult_create((xmlNodePtr)get_doc(This), pattern, resultList);
heap_free(pattern);
}
XPath = This->properties->XPath;
This->properties->XPath = TRUE;
query = tagName_to_XPath(tagName);
hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList);
xmlFree(query);
This->properties->XPath = XPath;
return hr;
}

View file

@ -1231,44 +1231,20 @@ static HRESULT WINAPI domelem_getElementsByTagName(
BSTR tagName, IXMLDOMNodeList** resultList)
{
domelem *This = impl_from_IXMLDOMElement( iface );
xmlNodePtr element;
xmlChar *query;
HRESULT hr;
BOOL XPath;
TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagName), resultList);
TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
if (!tagName || !resultList) return E_INVALIDARG;
if (!(element = get_element(This))) return E_FAIL;
if (tagName[0] == '*' && tagName[1] == 0)
{
static const WCHAR formatallW[] = {'/','/','*',0};
hr = queryresult_create(element, formatallW, resultList);
}
else
{
static const WCHAR xpathformat[] =
{ '/','/','*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\'' };
static const WCHAR closeW[] = { '\'',']',0 };
LPWSTR pattern;
WCHAR *ptr;
INT length;
length = lstrlenW(tagName);
/* without two WCHARs from format specifier */
ptr = pattern = heap_alloc(sizeof(xpathformat) + length*sizeof(WCHAR) + sizeof(closeW));
memcpy(ptr, xpathformat, sizeof(xpathformat));
ptr += sizeof(xpathformat)/sizeof(WCHAR);
memcpy(ptr, tagName, length*sizeof(WCHAR));
ptr += length;
memcpy(ptr, closeW, sizeof(closeW));
TRACE("%s\n", debugstr_w(pattern));
hr = queryresult_create(element, pattern, resultList);
heap_free(pattern);
}
XPath = is_xpathmode(get_element(This)->doc);
set_xpathmode(get_element(This)->doc, TRUE);
query = tagName_to_XPath(tagName);
hr = queryresult_create(get_element(This), query, resultList);
xmlFree(query);
set_xpathmode(get_element(This)->doc, XPath);
return hr;
}

View file

@ -190,7 +190,7 @@ extern IUnknown *create_doc_fragment( xmlNodePtr fragment );
extern IUnknown *create_doc_entity_ref( xmlNodePtr entity );
extern IUnknown *create_doc_type( xmlNodePtr doctype );
extern HRESULT queryresult_create( xmlNodePtr, LPCWSTR, IXMLDOMNodeList ** );
extern HRESULT queryresult_create( xmlNodePtr node, xmlChar* szQuery, IXMLDOMNodeList** out );
/* data accessors */
xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type );
@ -225,6 +225,8 @@ extern void wineXmlCallbackError(char const* caller, xmlErrorPtr err);
#define LIBXML2_CALLBACK_SERROR(caller, err) wineXmlCallbackError(#caller, err)
extern BOOL is_preserving_whitespace(xmlNodePtr node);
extern BOOL is_xpathmode(const xmlDocPtr doc);
extern void set_xpathmode(xmlDocPtr doc, BOOL xpath);
/* IXMLDOMNode Internal Structure */
typedef struct _xmlnode
@ -277,6 +279,8 @@ extern HRESULT dt_validate(XDR_DT dt, xmlChar const* content);
extern BSTR EnsureCorrectEOL(BSTR);
extern xmlChar* tagName_to_XPath(const BSTR tagName);
static inline BSTR bstr_from_xmlChar(const xmlChar *str)
{
BSTR ret = NULL;

View file

@ -1107,12 +1107,18 @@ static HRESULT WINAPI xmlnode_selectNodes(
IXMLDOMNodeList** resultList)
{
xmlnode *This = impl_from_IXMLDOMNode( iface );
xmlChar* str;
HRESULT hr;
TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
if (!queryString || !resultList) return E_INVALIDARG;
return queryresult_create( This->node, queryString, resultList );
str = xmlChar_from_wchar(queryString);
hr = queryresult_create(This->node, str, resultList);
heap_free(str);
return hr;
}
static HRESULT WINAPI xmlnode_selectSingleNode(

View file

@ -52,7 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
#include <libxml/xpathInternals.h>
int registerNamespaces(xmlXPathContextPtr ctxt);
BOOL is_xpathmode(const xmlDocPtr doc);
xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str);
typedef struct _queryresult
@ -488,17 +487,16 @@ static void query_serror(void* ctx, xmlErrorPtr err)
LIBXML2_CALLBACK_SERROR(queryresult_create, err);
}
HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **out)
HRESULT queryresult_create(xmlNodePtr node, xmlChar* szQuery, IXMLDOMNodeList **out)
{
queryresult *This = heap_alloc_zero(sizeof(queryresult));
xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
xmlChar *str = xmlChar_from_wchar(szQuery);
HRESULT hr;
TRACE("(%p, %s, %p)\n", node, wine_dbgstr_w(szQuery), out);
TRACE("(%p, %s, %p)\n", node, wine_dbgstr_a((char const*)szQuery), out);
*out = NULL;
if (This == NULL || ctxt == NULL || str == NULL)
if (This == NULL || ctxt == NULL || szQuery == NULL)
{
hr = E_OUTOFMEMORY;
goto cleanup;
@ -517,16 +515,11 @@ HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **o
if (is_xpathmode(This->node->doc))
{
xmlXPathRegisterAllFunctions(ctxt);
This->result = xmlXPathEvalExpression(szQuery, ctxt);
}
else
{
xmlChar* tmp;
int len;
tmp = XSLPattern_to_XPath(ctxt, str);
len = (xmlStrlen(tmp)+1)*sizeof(xmlChar);
str = heap_realloc(str, len);
memcpy(str, tmp, len);
xmlFree(tmp);
xmlChar* xslpQuery = XSLPattern_to_XPath(ctxt, szQuery);
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction);
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"boolean", xmlXPathBooleanFunction);
@ -541,9 +534,11 @@ HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **o
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILEq", XSLPattern_OP_ILEq);
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt);
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGEq", XSLPattern_OP_IGEq);
This->result = xmlXPathEvalExpression(xslpQuery, ctxt);
xmlFree(xslpQuery);
}
This->result = xmlXPathEvalExpression(str, ctxt);
if (!This->result || This->result->type != XPATH_NODESET)
{
hr = E_FAIL;
@ -560,7 +555,6 @@ cleanup:
if (This != NULL && FAILED(hr))
IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
xmlXPathFreeContext(ctxt);
heap_free(str);
return hr;
}

View file

@ -2962,9 +2962,8 @@ static void test_getElementsByTagName(void)
ok( r == S_OK, "ret %08x\n", r );
r = IXMLDOMNodeList_get_length( node_list, &len );
ok( r == S_OK, "ret %08x\n", r );
todo_wine ok( len == 5, "len %d\n", len );
IXMLDOMNodeList_Release( node_list );
ok( len == 5, "len %d\n", len );
expect_list_and_release(node_list, "E1.E2.D1 E2.E2.D1 E3.E2.D1 E4.E2.D1 E1.E4.E2.D1");
SysFreeString( str );
/* broken query BSTR */
@ -2975,7 +2974,7 @@ static void test_getElementsByTagName(void)
ok( r == S_OK, "ret %08x\n", r );
r = IXMLDOMNodeList_get_length( node_list, &len );
ok( r == S_OK, "ret %08x\n", r );
todo_wine ok( len == 5, "len %d\n", len );
ok( len == 5, "len %d\n", len );
IXMLDOMNodeList_Release( node_list );
IXMLDOMElement_Release(elem);