2 * XPath/XSLPattern query result node list implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2007 Mikolaj Zalewski
6 * Copyright 2010 Adam Martinson for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "msxml_private.h"
36 #include "wine/debug.h"
38 /* This file implements the object returned by a XPath query. Note that this is
39 * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
40 * They are different because the list returned by XPath queries:
41 * - is static - gives the results for the XML tree as it existed during the
42 * execution of the query
43 * - supports IXMLDOMSelection (TODO)
47 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
51 #include <libxml/xpath.h>
52 #include <libxml/xpathInternals.h>
54 int registerNamespaces(xmlXPathContextPtr ctxt
);
55 BOOL
is_xpathmode(const xmlDocPtr doc
);
56 xmlChar
* XSLPattern_to_XPath(xmlChar
const* xslpat_str
);
58 typedef struct _queryresult
61 const struct IXMLDOMNodeListVtbl
*lpVtbl
;
64 xmlXPathObjectPtr result
;
68 static inline queryresult
*impl_from_IXMLDOMNodeList( IXMLDOMNodeList
*iface
)
70 return (queryresult
*)((char*)iface
- FIELD_OFFSET(queryresult
, lpVtbl
));
73 #define XMLQUERYRES(x) ((IXMLDOMNodeList*)&(x)->lpVtbl)
75 static HRESULT WINAPI
queryresult_QueryInterface(
76 IXMLDOMNodeList
*iface
,
80 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
82 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
87 if ( IsEqualGUID( riid
, &IID_IUnknown
) ||
88 IsEqualGUID( riid
, &IID_IXMLDOMNodeList
) )
92 else if(dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
94 return *ppvObject
? S_OK
: E_NOINTERFACE
;
98 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
100 return E_NOINTERFACE
;
103 IXMLDOMNodeList_AddRef( iface
);
108 static ULONG WINAPI
queryresult_AddRef(
109 IXMLDOMNodeList
*iface
)
111 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
112 return InterlockedIncrement( &This
->ref
);
115 static ULONG WINAPI
queryresult_Release(
116 IXMLDOMNodeList
*iface
)
118 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
121 ref
= InterlockedDecrement(&This
->ref
);
124 xmlXPathFreeObject(This
->result
);
125 xmldoc_release(This
->node
->doc
);
132 static HRESULT WINAPI
queryresult_GetTypeInfoCount(
133 IXMLDOMNodeList
*iface
,
136 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
138 TRACE("(%p)->(%p)\n", This
, pctinfo
);
145 static HRESULT WINAPI
queryresult_GetTypeInfo(
146 IXMLDOMNodeList
*iface
,
149 ITypeInfo
** ppTInfo
)
151 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
154 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
156 hr
= get_typeinfo(IXMLDOMNodeList_tid
, ppTInfo
);
161 static HRESULT WINAPI
queryresult_GetIDsOfNames(
162 IXMLDOMNodeList
*iface
,
169 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
173 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
176 if(!rgszNames
|| cNames
== 0 || !rgDispId
)
179 hr
= get_typeinfo(IXMLDOMNodeList_tid
, &typeinfo
);
182 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
183 ITypeInfo_Release(typeinfo
);
189 static HRESULT WINAPI
queryresult_Invoke(
190 IXMLDOMNodeList
*iface
,
195 DISPPARAMS
* pDispParams
,
197 EXCEPINFO
* pExcepInfo
,
200 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
204 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
205 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
207 hr
= get_typeinfo(IXMLDOMNodeList_tid
, &typeinfo
);
210 hr
= ITypeInfo_Invoke(typeinfo
, &(This
->lpVtbl
), dispIdMember
, wFlags
, pDispParams
,
211 pVarResult
, pExcepInfo
, puArgErr
);
212 ITypeInfo_Release(typeinfo
);
218 static HRESULT WINAPI
queryresult_get_item(
219 IXMLDOMNodeList
* iface
,
221 IXMLDOMNode
** listItem
)
223 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
225 TRACE("(%p)->(%d %p)\n", This
, index
, listItem
);
232 if (index
< 0 || index
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
235 *listItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, index
));
236 This
->resultPos
= index
+ 1;
241 static HRESULT WINAPI
queryresult_get_length(
242 IXMLDOMNodeList
* iface
,
245 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
247 TRACE("(%p)->(%p)\n", This
, listLength
);
252 *listLength
= xmlXPathNodeSetGetLength(This
->result
->nodesetval
);
256 static HRESULT WINAPI
queryresult_nextNode(
257 IXMLDOMNodeList
* iface
,
258 IXMLDOMNode
** nextItem
)
260 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
262 TRACE("(%p)->(%p)\n", This
, nextItem
);
269 if (This
->resultPos
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
272 *nextItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, This
->resultPos
));
277 static HRESULT WINAPI
queryresult_reset(
278 IXMLDOMNodeList
* iface
)
280 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
287 static HRESULT WINAPI
queryresult__newEnum(
288 IXMLDOMNodeList
* iface
,
291 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
292 FIXME("(%p)->(%p)\n", This
, ppUnk
);
297 static const struct IXMLDOMNodeListVtbl queryresult_vtbl
=
299 queryresult_QueryInterface
,
302 queryresult_GetTypeInfoCount
,
303 queryresult_GetTypeInfo
,
304 queryresult_GetIDsOfNames
,
306 queryresult_get_item
,
307 queryresult_get_length
,
308 queryresult_nextNode
,
310 queryresult__newEnum
,
313 static HRESULT
queryresult_get_dispid(IUnknown
*iface
, BSTR name
, DWORD flags
, DISPID
*dispid
)
315 queryresult
*This
= impl_from_IXMLDOMNodeList( (IXMLDOMNodeList
*)iface
);
319 for(ptr
= name
; *ptr
&& isdigitW(*ptr
); ptr
++)
320 idx
= idx
*10 + (*ptr
-'0');
322 return DISP_E_UNKNOWNNAME
;
324 if(idx
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
325 return DISP_E_UNKNOWNNAME
;
327 *dispid
= MSXML_DISPID_CUSTOM_MIN
+ idx
;
328 TRACE("ret %x\n", *dispid
);
332 static HRESULT
queryresult_invoke(IUnknown
*iface
, DISPID id
, LCID lcid
, WORD flags
, DISPPARAMS
*params
,
333 VARIANT
*res
, EXCEPINFO
*ei
)
335 queryresult
*This
= impl_from_IXMLDOMNodeList( (IXMLDOMNodeList
*)iface
);
337 TRACE("(%p)->(%x %x %x %p %p %p)\n", This
, id
, lcid
, flags
, params
, res
, ei
);
339 V_VT(res
) = VT_DISPATCH
;
340 V_DISPATCH(res
) = NULL
;
344 case INVOKE_PROPERTYGET
:
346 IXMLDOMNode
*disp
= NULL
;
348 queryresult_get_item(XMLQUERYRES(This
), id
- MSXML_DISPID_CUSTOM_MIN
, &disp
);
349 V_DISPATCH(res
) = (IDispatch
*)disp
;
354 FIXME("unimplemented flags %x\n", flags
);
359 TRACE("ret %p\n", V_DISPATCH(res
));
364 static const dispex_static_data_vtbl_t queryresult_dispex_vtbl
= {
365 queryresult_get_dispid
,
369 static const tid_t queryresult_iface_tids
[] = {
373 static dispex_static_data_t queryresult_dispex
= {
374 &queryresult_dispex_vtbl
,
375 IXMLDOMSelection_tid
,
377 queryresult_iface_tids
380 void XSLPattern_invalid(xmlXPathParserContextPtr pctx
, int nargs
)
382 xmlXPathObjectPtr obj
;
383 for (; nargs
> 0; --nargs
)
385 obj
= valuePop(pctx
);
386 xmlXPathFreeObject(obj
);
389 obj
= xmlMalloc(sizeof(xmlXPathObject
));
390 obj
->type
= XPATH_UNDEFINED
;
394 #define XSLPATTERN_CHECK_ARGS(n) \
396 FIXME("XSLPattern syntax error: Expected 0 arguments, got %i\n", nargs); \
397 XSLPattern_invalid(pctx, nargs); \
402 void XSLPattern_index(xmlXPathParserContextPtr pctx
, int nargs
)
404 XSLPATTERN_CHECK_ARGS(0);
406 xmlXPathPositionFunction(pctx
, 0);
407 valuePush(pctx
, xmlXPathNewFloat(xmlXPathPopNumber(pctx
) - 1.0));
410 void XSLPattern_end(xmlXPathParserContextPtr pctx
, int nargs
)
413 XSLPATTERN_CHECK_ARGS(0);
415 xmlXPathPositionFunction(pctx
, 0);
416 pos
= xmlXPathPopNumber(pctx
);
417 xmlXPathLastFunction(pctx
, 0);
418 last
= xmlXPathPopNumber(pctx
);
419 valuePush(pctx
, xmlXPathNewBoolean(pos
== last
));
422 void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx
, int nargs
)
424 xmlChar
*arg1
, *arg2
;
425 XSLPATTERN_CHECK_ARGS(2);
427 arg2
= xmlXPathPopString(pctx
);
428 arg1
= xmlXPathPopString(pctx
);
429 valuePush(pctx
, xmlXPathNewBoolean(xmlStrcasecmp(arg1
, arg2
) == 0));
434 void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx
, int nargs
)
436 xmlChar
*arg1
, *arg2
;
437 XSLPATTERN_CHECK_ARGS(2);
439 arg2
= xmlXPathPopString(pctx
);
440 arg1
= xmlXPathPopString(pctx
);
441 valuePush(pctx
, xmlXPathNewBoolean(xmlStrcasecmp(arg1
, arg2
) != 0));
446 void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx
, int nargs
)
448 xmlChar
*arg1
, *arg2
;
449 XSLPATTERN_CHECK_ARGS(2);
451 arg2
= xmlXPathPopString(pctx
);
452 arg1
= xmlXPathPopString(pctx
);
453 valuePush(pctx
, xmlXPathNewBoolean(xmlStrcasecmp(arg1
, arg2
) < 0));
458 void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx
, int nargs
)
460 xmlChar
*arg1
, *arg2
;
461 XSLPATTERN_CHECK_ARGS(2);
463 arg2
= xmlXPathPopString(pctx
);
464 arg1
= xmlXPathPopString(pctx
);
465 valuePush(pctx
, xmlXPathNewBoolean(xmlStrcasecmp(arg1
, arg2
) <= 0));
470 void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx
, int nargs
)
472 xmlChar
*arg1
, *arg2
;
473 XSLPATTERN_CHECK_ARGS(2);
475 arg2
= xmlXPathPopString(pctx
);
476 arg1
= xmlXPathPopString(pctx
);
477 valuePush(pctx
, xmlXPathNewBoolean(xmlStrcasecmp(arg1
, arg2
) > 0));
482 void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx
, int nargs
)
484 xmlChar
*arg1
, *arg2
;
485 XSLPATTERN_CHECK_ARGS(2);
487 arg2
= xmlXPathPopString(pctx
);
488 arg1
= xmlXPathPopString(pctx
);
489 valuePush(pctx
, xmlXPathNewBoolean(xmlStrcasecmp(arg1
, arg2
) >= 0));
494 HRESULT
queryresult_create(xmlNodePtr node
, LPCWSTR szQuery
, IXMLDOMNodeList
**out
)
496 queryresult
*This
= heap_alloc_zero(sizeof(queryresult
));
497 xmlXPathContextPtr ctxt
= xmlXPathNewContext(node
->doc
);
498 xmlChar
*str
= xmlChar_from_wchar(szQuery
);
501 TRACE("(%p, %s, %p)\n", node
, wine_dbgstr_w(szQuery
), out
);
504 if (This
== NULL
|| ctxt
== NULL
|| str
== NULL
)
510 This
->lpVtbl
= &queryresult_vtbl
;
514 xmldoc_add_ref(This
->node
->doc
);
517 registerNamespaces(ctxt
);
519 if (is_xpathmode(This
->node
->doc
))
521 xmlXPathRegisterAllFunctions(ctxt
);
527 WARN("Attempting XSLPattern emulation (experimental).\n");
528 tmp
= XSLPattern_to_XPath(str
);
529 len
= (xmlStrlen(tmp
)+1)*sizeof(xmlChar
);
530 str
= heap_realloc(str
, len
);
531 memcpy(str
, tmp
, len
);
534 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"not", xmlXPathNotFunction
);
535 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"boolean", xmlXPathBooleanFunction
);
537 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"index", XSLPattern_index
);
538 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"end", XSLPattern_end
);
540 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IEq", XSLPattern_OP_IEq
);
541 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_INEq", XSLPattern_OP_INEq
);
542 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILt", XSLPattern_OP_ILt
);
543 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILEq", XSLPattern_OP_ILEq
);
544 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGt", XSLPattern_OP_IGt
);
545 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGEq", XSLPattern_OP_IGEq
);
548 This
->result
= xmlXPathEval(str
, ctxt
);
549 if (!This
->result
|| This
->result
->type
!= XPATH_NODESET
)
555 init_dispex(&This
->dispex
, (IUnknown
*)&This
->lpVtbl
, &queryresult_dispex
);
557 *out
= (IXMLDOMNodeList
*) &This
->lpVtbl
;
559 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This
->result
->nodesetval
));
562 if (This
!= NULL
&& FAILED(hr
))
563 IXMLDOMNodeList_Release( (IXMLDOMNodeList
*) &This
->lpVtbl
);
564 xmlXPathFreeContext(ctxt
);