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;
|
return properties_from_xmlDocPtr(doc)->XPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_xpathmode(xmlDocPtr doc, BOOL xpath)
|
||||||
|
{
|
||||||
|
properties_from_xmlDocPtr(doc)->XPath = xpath;
|
||||||
|
}
|
||||||
|
|
||||||
int registerNamespaces(xmlXPathContextPtr ctxt)
|
int registerNamespaces(xmlXPathContextPtr ctxt)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
@ -1766,6 +1771,47 @@ static HRESULT WINAPI domdoc_createEntityReference(
|
||||||
return hr;
|
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(
|
static HRESULT WINAPI domdoc_getElementsByTagName(
|
||||||
IXMLDOMDocument3 *iface,
|
IXMLDOMDocument3 *iface,
|
||||||
|
@ -1773,41 +1819,20 @@ static HRESULT WINAPI domdoc_getElementsByTagName(
|
||||||
IXMLDOMNodeList** resultList )
|
IXMLDOMNodeList** resultList )
|
||||||
{
|
{
|
||||||
domdoc *This = impl_from_IXMLDOMDocument3( iface );
|
domdoc *This = impl_from_IXMLDOMDocument3( iface );
|
||||||
|
xmlChar *query;
|
||||||
HRESULT hr;
|
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 || !resultList) return E_INVALIDARG;
|
||||||
|
|
||||||
if (tagName[0] == '*' && tagName[1] == 0)
|
XPath = This->properties->XPath;
|
||||||
{
|
This->properties->XPath = TRUE;
|
||||||
static const WCHAR formatallW[] = {'/','/','*',0};
|
query = tagName_to_XPath(tagName);
|
||||||
hr = queryresult_create((xmlNodePtr)get_doc(This), formatallW, resultList);
|
hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList);
|
||||||
}
|
xmlFree(query);
|
||||||
else
|
This->properties->XPath = XPath;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1231,44 +1231,20 @@ static HRESULT WINAPI domelem_getElementsByTagName(
|
||||||
BSTR tagName, IXMLDOMNodeList** resultList)
|
BSTR tagName, IXMLDOMNodeList** resultList)
|
||||||
{
|
{
|
||||||
domelem *This = impl_from_IXMLDOMElement( iface );
|
domelem *This = impl_from_IXMLDOMElement( iface );
|
||||||
xmlNodePtr element;
|
xmlChar *query;
|
||||||
HRESULT hr;
|
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 || !resultList) return E_INVALIDARG;
|
||||||
if (!(element = get_element(This))) return E_FAIL;
|
|
||||||
|
|
||||||
if (tagName[0] == '*' && tagName[1] == 0)
|
XPath = is_xpathmode(get_element(This)->doc);
|
||||||
{
|
set_xpathmode(get_element(This)->doc, TRUE);
|
||||||
static const WCHAR formatallW[] = {'/','/','*',0};
|
query = tagName_to_XPath(tagName);
|
||||||
hr = queryresult_create(element, formatallW, resultList);
|
hr = queryresult_create(get_element(This), query, resultList);
|
||||||
}
|
xmlFree(query);
|
||||||
else
|
set_xpathmode(get_element(This)->doc, XPath);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
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_entity_ref( xmlNodePtr entity );
|
||||||
extern IUnknown *create_doc_type( xmlNodePtr doctype );
|
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 */
|
/* data accessors */
|
||||||
xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type );
|
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)
|
#define LIBXML2_CALLBACK_SERROR(caller, err) wineXmlCallbackError(#caller, err)
|
||||||
|
|
||||||
extern BOOL is_preserving_whitespace(xmlNodePtr node);
|
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 */
|
/* IXMLDOMNode Internal Structure */
|
||||||
typedef struct _xmlnode
|
typedef struct _xmlnode
|
||||||
|
@ -277,6 +279,8 @@ extern HRESULT dt_validate(XDR_DT dt, xmlChar const* content);
|
||||||
|
|
||||||
extern BSTR EnsureCorrectEOL(BSTR);
|
extern BSTR EnsureCorrectEOL(BSTR);
|
||||||
|
|
||||||
|
extern xmlChar* tagName_to_XPath(const BSTR tagName);
|
||||||
|
|
||||||
static inline BSTR bstr_from_xmlChar(const xmlChar *str)
|
static inline BSTR bstr_from_xmlChar(const xmlChar *str)
|
||||||
{
|
{
|
||||||
BSTR ret = NULL;
|
BSTR ret = NULL;
|
||||||
|
|
|
@ -1107,12 +1107,18 @@ static HRESULT WINAPI xmlnode_selectNodes(
|
||||||
IXMLDOMNodeList** resultList)
|
IXMLDOMNodeList** resultList)
|
||||||
{
|
{
|
||||||
xmlnode *This = impl_from_IXMLDOMNode( iface );
|
xmlnode *This = impl_from_IXMLDOMNode( iface );
|
||||||
|
xmlChar* str;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
|
TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
|
||||||
|
|
||||||
if (!queryString || !resultList) return E_INVALIDARG;
|
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(
|
static HRESULT WINAPI xmlnode_selectSingleNode(
|
||||||
|
|
|
@ -52,7 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
|
||||||
#include <libxml/xpathInternals.h>
|
#include <libxml/xpathInternals.h>
|
||||||
|
|
||||||
int registerNamespaces(xmlXPathContextPtr ctxt);
|
int registerNamespaces(xmlXPathContextPtr ctxt);
|
||||||
BOOL is_xpathmode(const xmlDocPtr doc);
|
|
||||||
xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str);
|
xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str);
|
||||||
|
|
||||||
typedef struct _queryresult
|
typedef struct _queryresult
|
||||||
|
@ -488,17 +487,16 @@ static void query_serror(void* ctx, xmlErrorPtr err)
|
||||||
LIBXML2_CALLBACK_SERROR(queryresult_create, 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));
|
queryresult *This = heap_alloc_zero(sizeof(queryresult));
|
||||||
xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
|
xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
|
||||||
xmlChar *str = xmlChar_from_wchar(szQuery);
|
|
||||||
HRESULT hr;
|
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;
|
*out = NULL;
|
||||||
if (This == NULL || ctxt == NULL || str == NULL)
|
if (This == NULL || ctxt == NULL || szQuery == NULL)
|
||||||
{
|
{
|
||||||
hr = E_OUTOFMEMORY;
|
hr = E_OUTOFMEMORY;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -517,16 +515,11 @@ HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **o
|
||||||
if (is_xpathmode(This->node->doc))
|
if (is_xpathmode(This->node->doc))
|
||||||
{
|
{
|
||||||
xmlXPathRegisterAllFunctions(ctxt);
|
xmlXPathRegisterAllFunctions(ctxt);
|
||||||
|
This->result = xmlXPathEvalExpression(szQuery, ctxt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xmlChar* tmp;
|
xmlChar* xslpQuery = XSLPattern_to_XPath(ctxt, szQuery);
|
||||||
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);
|
|
||||||
|
|
||||||
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction);
|
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction);
|
||||||
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"boolean", xmlXPathBooleanFunction);
|
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_ILEq", XSLPattern_OP_ILEq);
|
||||||
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt);
|
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt);
|
||||||
xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGEq", XSLPattern_OP_IGEq);
|
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)
|
if (!This->result || This->result->type != XPATH_NODESET)
|
||||||
{
|
{
|
||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
|
@ -560,7 +555,6 @@ cleanup:
|
||||||
if (This != NULL && FAILED(hr))
|
if (This != NULL && FAILED(hr))
|
||||||
IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
|
IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
|
||||||
xmlXPathFreeContext(ctxt);
|
xmlXPathFreeContext(ctxt);
|
||||||
heap_free(str);
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2962,9 +2962,8 @@ static void test_getElementsByTagName(void)
|
||||||
ok( r == S_OK, "ret %08x\n", r );
|
ok( r == S_OK, "ret %08x\n", r );
|
||||||
r = IXMLDOMNodeList_get_length( node_list, &len );
|
r = IXMLDOMNodeList_get_length( node_list, &len );
|
||||||
ok( r == S_OK, "ret %08x\n", r );
|
ok( r == S_OK, "ret %08x\n", r );
|
||||||
todo_wine ok( len == 5, "len %d\n", len );
|
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");
|
||||||
IXMLDOMNodeList_Release( node_list );
|
|
||||||
SysFreeString( str );
|
SysFreeString( str );
|
||||||
|
|
||||||
/* broken query BSTR */
|
/* broken query BSTR */
|
||||||
|
@ -2975,7 +2974,7 @@ static void test_getElementsByTagName(void)
|
||||||
ok( r == S_OK, "ret %08x\n", r );
|
ok( r == S_OK, "ret %08x\n", r );
|
||||||
r = IXMLDOMNodeList_get_length( node_list, &len );
|
r = IXMLDOMNodeList_get_length( node_list, &len );
|
||||||
ok( r == S_OK, "ret %08x\n", r );
|
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 );
|
IXMLDOMNodeList_Release( node_list );
|
||||||
|
|
||||||
IXMLDOMElement_Release(elem);
|
IXMLDOMElement_Release(elem);
|
||||||
|
|
Loading…
Reference in New Issue