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(xmlXPathContextPtr ctxt
, 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 #define XSLPATTERN_CHECK_ARGS(n) \
382 FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
383 xmlXPathSetArityError(pctx); \
388 void XSLPattern_index(xmlXPathParserContextPtr pctx
, int nargs
)
390 XSLPATTERN_CHECK_ARGS(0);
392 xmlXPathPositionFunction(pctx
, 0);
393 xmlXPathReturnNumber(pctx
, xmlXPathPopNumber(pctx
) - 1.0);
396 void XSLPattern_end(xmlXPathParserContextPtr pctx
, int nargs
)
399 XSLPATTERN_CHECK_ARGS(0);
401 xmlXPathPositionFunction(pctx
, 0);
402 pos
= xmlXPathPopNumber(pctx
);
403 xmlXPathLastFunction(pctx
, 0);
404 last
= xmlXPathPopNumber(pctx
);
405 xmlXPathReturnBoolean(pctx
, pos
== last
);
408 void XSLPattern_nodeType(xmlXPathParserContextPtr pctx
, int nargs
)
410 XSLPATTERN_CHECK_ARGS(0);
411 xmlXPathReturnNumber(pctx
, pctx
->context
->node
->type
);
414 void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx
, int nargs
)
416 xmlChar
*arg1
, *arg2
;
417 XSLPATTERN_CHECK_ARGS(2);
419 arg2
= xmlXPathPopString(pctx
);
420 arg1
= xmlXPathPopString(pctx
);
421 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) == 0);
426 void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx
, int nargs
)
428 xmlChar
*arg1
, *arg2
;
429 XSLPATTERN_CHECK_ARGS(2);
431 arg2
= xmlXPathPopString(pctx
);
432 arg1
= xmlXPathPopString(pctx
);
433 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) != 0);
438 void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx
, int nargs
)
440 xmlChar
*arg1
, *arg2
;
441 XSLPATTERN_CHECK_ARGS(2);
443 arg2
= xmlXPathPopString(pctx
);
444 arg1
= xmlXPathPopString(pctx
);
445 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) < 0);
450 void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx
, int nargs
)
452 xmlChar
*arg1
, *arg2
;
453 XSLPATTERN_CHECK_ARGS(2);
455 arg2
= xmlXPathPopString(pctx
);
456 arg1
= xmlXPathPopString(pctx
);
457 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) <= 0);
462 void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx
, int nargs
)
464 xmlChar
*arg1
, *arg2
;
465 XSLPATTERN_CHECK_ARGS(2);
467 arg2
= xmlXPathPopString(pctx
);
468 arg1
= xmlXPathPopString(pctx
);
469 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) > 0);
474 void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx
, int nargs
)
476 xmlChar
*arg1
, *arg2
;
477 XSLPATTERN_CHECK_ARGS(2);
479 arg2
= xmlXPathPopString(pctx
);
480 arg1
= xmlXPathPopString(pctx
);
481 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) >= 0);
486 static void query_serror(void* ctx
, xmlErrorPtr err
)
488 LIBXML2_CALLBACK_SERROR(queryresult_create
, err
);
491 HRESULT
queryresult_create(xmlNodePtr node
, LPCWSTR szQuery
, IXMLDOMNodeList
**out
)
493 queryresult
*This
= heap_alloc_zero(sizeof(queryresult
));
494 xmlXPathContextPtr ctxt
= xmlXPathNewContext(node
->doc
);
495 xmlChar
*str
= xmlChar_from_wchar(szQuery
);
498 TRACE("(%p, %s, %p)\n", node
, wine_dbgstr_w(szQuery
), out
);
501 if (This
== NULL
|| ctxt
== NULL
|| str
== NULL
)
507 This
->lpVtbl
= &queryresult_vtbl
;
511 xmldoc_add_ref(This
->node
->doc
);
513 ctxt
->error
= query_serror
;
515 registerNamespaces(ctxt
);
517 if (is_xpathmode(This
->node
->doc
))
519 xmlXPathRegisterAllFunctions(ctxt
);
525 WARN("Attempting XSLPattern emulation (experimental).\n");
526 tmp
= XSLPattern_to_XPath(ctxt
, str
);
527 len
= (xmlStrlen(tmp
)+1)*sizeof(xmlChar
);
528 str
= heap_realloc(str
, len
);
529 memcpy(str
, tmp
, len
);
532 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"not", xmlXPathNotFunction
);
533 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"boolean", xmlXPathBooleanFunction
);
535 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"index", XSLPattern_index
);
536 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"end", XSLPattern_end
);
537 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"nodeType", XSLPattern_nodeType
);
539 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IEq", XSLPattern_OP_IEq
);
540 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_INEq", XSLPattern_OP_INEq
);
541 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILt", XSLPattern_OP_ILt
);
542 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILEq", XSLPattern_OP_ILEq
);
543 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGt", XSLPattern_OP_IGt
);
544 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGEq", XSLPattern_OP_IGEq
);
547 This
->result
= xmlXPathEvalExpression(str
, ctxt
);
548 if (!This
->result
|| This
->result
->type
!= XPATH_NODESET
)
554 init_dispex(&This
->dispex
, (IUnknown
*)&This
->lpVtbl
, &queryresult_dispex
);
556 *out
= (IXMLDOMNodeList
*) &This
->lpVtbl
;
558 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This
->result
->nodesetval
));
561 if (This
!= NULL
&& FAILED(hr
))
562 IXMLDOMNodeList_Release( (IXMLDOMNodeList
*) &This
->lpVtbl
);
563 xmlXPathFreeContext(ctxt
);