msxml3: Fix domdoc_getElementsByTagName()/domelem_getElementsByTagName().
This commit is contained in:
parent
6f537c4df1
commit
f3678ec193
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue