2 * XPath query result node list implementation (TODO: XSLPattern support)
4 * Copyright 2005 Mike McCormack
5 * Copyright 2007 Mikolaj Zalewski
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "msxml_private.h"
35 #include "wine/debug.h"
37 /* This file implements the object returned by a XPath query. Note that this is
38 * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
39 * They are different because the list returned by XPath queries:
40 * - is static - gives the results for the XML tree as it existed during the
41 * execution of the query
42 * - supports IXMLDOMSelection (TODO)
44 * TODO: XSLPattern support
47 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
51 #include <libxml/xpath.h>
53 int registerNamespaces(xmlXPathContextPtr ctxt);
55 typedef struct _queryresult
58 const struct IXMLDOMNodeListVtbl *lpVtbl;
61 xmlXPathObjectPtr result;
65 static inline queryresult *impl_from_IXMLDOMNodeList( IXMLDOMNodeList *iface )
67 return (queryresult *)((char*)iface - FIELD_OFFSET(queryresult, lpVtbl));
70 #define XMLQUERYRES(x) ((IXMLDOMNodeList*)&(x)->lpVtbl)
72 static HRESULT WINAPI queryresult_QueryInterface(
73 IXMLDOMNodeList *iface,
77 queryresult *This = impl_from_IXMLDOMNodeList( iface );
79 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
84 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
85 IsEqualGUID( riid, &IID_IXMLDOMNodeList ) )
89 else if(dispex_query_interface(&This->dispex, riid, ppvObject))
91 return *ppvObject ? S_OK : E_NOINTERFACE;
95 FIXME("interface %s not implemented\n", debugstr_guid(riid));
100 IXMLDOMNodeList_AddRef( iface );
105 static ULONG WINAPI queryresult_AddRef(
106 IXMLDOMNodeList *iface )
108 queryresult *This = impl_from_IXMLDOMNodeList( iface );
109 return InterlockedIncrement( &This->ref );
112 static ULONG WINAPI queryresult_Release(
113 IXMLDOMNodeList *iface )
115 queryresult *This = impl_from_IXMLDOMNodeList( iface );
118 ref = InterlockedDecrement(&This->ref);
121 xmlXPathFreeObject(This->result);
122 xmldoc_release(This->node->doc);
129 static HRESULT WINAPI queryresult_GetTypeInfoCount(
130 IXMLDOMNodeList *iface,
133 queryresult *This = impl_from_IXMLDOMNodeList( iface );
135 TRACE("(%p)->(%p)\n", This, pctinfo);
142 static HRESULT WINAPI queryresult_GetTypeInfo(
143 IXMLDOMNodeList *iface,
146 ITypeInfo** ppTInfo )
148 queryresult *This = impl_from_IXMLDOMNodeList( iface );
151 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
153 hr = get_typeinfo(IXMLDOMNodeList_tid, ppTInfo);
158 static HRESULT WINAPI queryresult_GetIDsOfNames(
159 IXMLDOMNodeList *iface,
166 queryresult *This = impl_from_IXMLDOMNodeList( iface );
170 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
173 if(!rgszNames || cNames == 0 || !rgDispId)
176 hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
179 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
180 ITypeInfo_Release(typeinfo);
186 static HRESULT WINAPI queryresult_Invoke(
187 IXMLDOMNodeList *iface,
192 DISPPARAMS* pDispParams,
194 EXCEPINFO* pExcepInfo,
197 queryresult *This = impl_from_IXMLDOMNodeList( iface );
201 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
202 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
204 hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
207 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
208 pVarResult, pExcepInfo, puArgErr);
209 ITypeInfo_Release(typeinfo);
215 static HRESULT WINAPI queryresult_get_item(
216 IXMLDOMNodeList* iface,
218 IXMLDOMNode** listItem)
220 queryresult *This = impl_from_IXMLDOMNodeList( iface );
222 TRACE("(%p)->(%d %p)\n", This, index, listItem);
229 if (index < 0 || index >= xmlXPathNodeSetGetLength(This->result->nodesetval))
232 *listItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, index));
233 This->resultPos = index + 1;
238 static HRESULT WINAPI queryresult_get_length(
239 IXMLDOMNodeList* iface,
242 queryresult *This = impl_from_IXMLDOMNodeList( iface );
244 TRACE("(%p)->(%p)\n", This, listLength);
249 *listLength = xmlXPathNodeSetGetLength(This->result->nodesetval);
253 static HRESULT WINAPI queryresult_nextNode(
254 IXMLDOMNodeList* iface,
255 IXMLDOMNode** nextItem)
257 queryresult *This = impl_from_IXMLDOMNodeList( iface );
259 TRACE("(%p)->(%p)\n", This, nextItem );
266 if (This->resultPos >= xmlXPathNodeSetGetLength(This->result->nodesetval))
269 *nextItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, This->resultPos));
274 static HRESULT WINAPI queryresult_reset(
275 IXMLDOMNodeList* iface)
277 queryresult *This = impl_from_IXMLDOMNodeList( iface );
284 static HRESULT WINAPI queryresult__newEnum(
285 IXMLDOMNodeList* iface,
288 queryresult *This = impl_from_IXMLDOMNodeList( iface );
289 FIXME("(%p)->(%p)\n", This, ppUnk);
294 static const struct IXMLDOMNodeListVtbl queryresult_vtbl =
296 queryresult_QueryInterface,
299 queryresult_GetTypeInfoCount,
300 queryresult_GetTypeInfo,
301 queryresult_GetIDsOfNames,
303 queryresult_get_item,
304 queryresult_get_length,
305 queryresult_nextNode,
307 queryresult__newEnum,
310 static HRESULT queryresult_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
312 queryresult *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
316 for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
317 idx = idx*10 + (*ptr-'0');
319 return DISP_E_UNKNOWNNAME;
321 if(idx >= xmlXPathNodeSetGetLength(This->result->nodesetval))
322 return DISP_E_UNKNOWNNAME;
324 *dispid = MSXML_DISPID_CUSTOM_MIN + idx;
325 TRACE("ret %x\n", *dispid);
329 static HRESULT queryresult_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
330 VARIANT *res, EXCEPINFO *ei)
332 queryresult *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
334 TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
336 V_VT(res) = VT_DISPATCH;
337 V_DISPATCH(res) = NULL;
341 case INVOKE_PROPERTYGET:
343 IXMLDOMNode *disp = NULL;
345 queryresult_get_item(XMLQUERYRES(This), id - MSXML_DISPID_CUSTOM_MIN, &disp);
346 V_DISPATCH(res) = (IDispatch*)disp;
351 FIXME("unimplemented flags %x\n", flags);
356 TRACE("ret %p\n", V_DISPATCH(res));
361 static const dispex_static_data_vtbl_t queryresult_dispex_vtbl = {
362 queryresult_get_dispid,
366 static const tid_t queryresult_iface_tids[] = {
370 static dispex_static_data_t queryresult_dispex = {
371 &queryresult_dispex_vtbl,
372 IXMLDOMSelection_tid,
374 queryresult_iface_tids
377 HRESULT queryresult_create(xmlNodePtr node, LPCWSTR szQuery, IXMLDOMNodeList **out)
379 queryresult *This = heap_alloc_zero(sizeof(queryresult));
380 xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
381 xmlChar *str = xmlChar_from_wchar(szQuery);
384 TRACE("(%p, %s, %p)\n", node, wine_dbgstr_w(szQuery), out);
387 if (This == NULL || ctxt == NULL || str == NULL)
393 This->lpVtbl = &queryresult_vtbl;
397 xmldoc_add_ref(This->node->doc);
400 registerNamespaces(ctxt);
402 This->result = xmlXPathEval(str, ctxt);
403 if (!This->result || This->result->type != XPATH_NODESET)
409 init_dispex(&This->dispex, (IUnknown*)&This->lpVtbl, &queryresult_dispex);
411 *out = (IXMLDOMNodeList *) &This->lpVtbl;
413 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This->result->nodesetval));
416 if (This != NULL && FAILED(hr))
417 IXMLDOMNodeList_Release( (IXMLDOMNodeList*) &This->lpVtbl );
418 xmlXPathFreeContext(ctxt);