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
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/xpath.h>
32 # include <libxml/xpathInternals.h>
41 #include "msxml_private.h"
43 #include "wine/debug.h"
45 /* This file implements the object returned by a XPath query. Note that this is
46 * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
47 * They are different because the list returned by XPath queries:
48 * - is static - gives the results for the XML tree as it existed during the
49 * execution of the query
50 * - supports IXMLDOMSelection (TODO)
54 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
58 int registerNamespaces(xmlXPathContextPtr ctxt
);
59 xmlChar
* XSLPattern_to_XPath(xmlXPathContextPtr ctxt
, xmlChar
const* xslpat_str
);
61 typedef struct _queryresult
64 const struct IXMLDOMNodeListVtbl
*lpVtbl
;
67 xmlXPathObjectPtr result
;
71 static inline queryresult
*impl_from_IXMLDOMNodeList( IXMLDOMNodeList
*iface
)
73 return (queryresult
*)((char*)iface
- FIELD_OFFSET(queryresult
, lpVtbl
));
76 #define XMLQUERYRES(x) ((IXMLDOMNodeList*)&(x)->lpVtbl)
78 static HRESULT WINAPI
queryresult_QueryInterface(
79 IXMLDOMNodeList
*iface
,
83 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
85 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
90 if ( IsEqualGUID( riid
, &IID_IUnknown
) ||
91 IsEqualGUID( riid
, &IID_IXMLDOMNodeList
) )
95 else if(dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
97 return *ppvObject
? S_OK
: E_NOINTERFACE
;
101 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
103 return E_NOINTERFACE
;
106 IXMLDOMNodeList_AddRef( iface
);
111 static ULONG WINAPI
queryresult_AddRef(
112 IXMLDOMNodeList
*iface
)
114 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
115 return InterlockedIncrement( &This
->ref
);
118 static ULONG WINAPI
queryresult_Release(
119 IXMLDOMNodeList
*iface
)
121 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
124 ref
= InterlockedDecrement(&This
->ref
);
127 xmlXPathFreeObject(This
->result
);
128 xmldoc_release(This
->node
->doc
);
135 static HRESULT WINAPI
queryresult_GetTypeInfoCount(
136 IXMLDOMNodeList
*iface
,
139 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
141 TRACE("(%p)->(%p)\n", This
, pctinfo
);
148 static HRESULT WINAPI
queryresult_GetTypeInfo(
149 IXMLDOMNodeList
*iface
,
152 ITypeInfo
** ppTInfo
)
154 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
157 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
159 hr
= get_typeinfo(IXMLDOMNodeList_tid
, ppTInfo
);
164 static HRESULT WINAPI
queryresult_GetIDsOfNames(
165 IXMLDOMNodeList
*iface
,
172 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
176 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
179 if(!rgszNames
|| cNames
== 0 || !rgDispId
)
182 hr
= get_typeinfo(IXMLDOMNodeList_tid
, &typeinfo
);
185 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
186 ITypeInfo_Release(typeinfo
);
192 static HRESULT WINAPI
queryresult_Invoke(
193 IXMLDOMNodeList
*iface
,
198 DISPPARAMS
* pDispParams
,
200 EXCEPINFO
* pExcepInfo
,
203 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
207 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
208 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
210 hr
= get_typeinfo(IXMLDOMNodeList_tid
, &typeinfo
);
213 hr
= ITypeInfo_Invoke(typeinfo
, &(This
->lpVtbl
), dispIdMember
, wFlags
, pDispParams
,
214 pVarResult
, pExcepInfo
, puArgErr
);
215 ITypeInfo_Release(typeinfo
);
221 static HRESULT WINAPI
queryresult_get_item(
222 IXMLDOMNodeList
* iface
,
224 IXMLDOMNode
** listItem
)
226 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
228 TRACE("(%p)->(%d %p)\n", This
, index
, listItem
);
235 if (index
< 0 || index
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
238 *listItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, index
));
239 This
->resultPos
= index
+ 1;
244 static HRESULT WINAPI
queryresult_get_length(
245 IXMLDOMNodeList
* iface
,
248 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
250 TRACE("(%p)->(%p)\n", This
, listLength
);
255 *listLength
= xmlXPathNodeSetGetLength(This
->result
->nodesetval
);
259 static HRESULT WINAPI
queryresult_nextNode(
260 IXMLDOMNodeList
* iface
,
261 IXMLDOMNode
** nextItem
)
263 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
265 TRACE("(%p)->(%p)\n", This
, nextItem
);
272 if (This
->resultPos
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
275 *nextItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, This
->resultPos
));
280 static HRESULT WINAPI
queryresult_reset(
281 IXMLDOMNodeList
* iface
)
283 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
290 static HRESULT WINAPI
queryresult__newEnum(
291 IXMLDOMNodeList
* iface
,
294 queryresult
*This
= impl_from_IXMLDOMNodeList( iface
);
295 FIXME("(%p)->(%p)\n", This
, ppUnk
);
300 static const struct IXMLDOMNodeListVtbl queryresult_vtbl
=
302 queryresult_QueryInterface
,
305 queryresult_GetTypeInfoCount
,
306 queryresult_GetTypeInfo
,
307 queryresult_GetIDsOfNames
,
309 queryresult_get_item
,
310 queryresult_get_length
,
311 queryresult_nextNode
,
313 queryresult__newEnum
,
316 static HRESULT
queryresult_get_dispid(IUnknown
*iface
, BSTR name
, DWORD flags
, DISPID
*dispid
)
318 queryresult
*This
= impl_from_IXMLDOMNodeList( (IXMLDOMNodeList
*)iface
);
322 for(ptr
= name
; *ptr
&& isdigitW(*ptr
); ptr
++)
323 idx
= idx
*10 + (*ptr
-'0');
325 return DISP_E_UNKNOWNNAME
;
327 if(idx
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
328 return DISP_E_UNKNOWNNAME
;
330 *dispid
= MSXML_DISPID_CUSTOM_MIN
+ idx
;
331 TRACE("ret %x\n", *dispid
);
335 static HRESULT
queryresult_invoke(IUnknown
*iface
, DISPID id
, LCID lcid
, WORD flags
, DISPPARAMS
*params
,
336 VARIANT
*res
, EXCEPINFO
*ei
)
338 queryresult
*This
= impl_from_IXMLDOMNodeList( (IXMLDOMNodeList
*)iface
);
340 TRACE("(%p)->(%x %x %x %p %p %p)\n", This
, id
, lcid
, flags
, params
, res
, ei
);
342 V_VT(res
) = VT_DISPATCH
;
343 V_DISPATCH(res
) = NULL
;
347 case INVOKE_PROPERTYGET
:
349 IXMLDOMNode
*disp
= NULL
;
351 queryresult_get_item(XMLQUERYRES(This
), id
- MSXML_DISPID_CUSTOM_MIN
, &disp
);
352 V_DISPATCH(res
) = (IDispatch
*)disp
;
357 FIXME("unimplemented flags %x\n", flags
);
362 TRACE("ret %p\n", V_DISPATCH(res
));
367 static const dispex_static_data_vtbl_t queryresult_dispex_vtbl
= {
368 queryresult_get_dispid
,
372 static const tid_t queryresult_iface_tids
[] = {
376 static dispex_static_data_t queryresult_dispex
= {
377 &queryresult_dispex_vtbl
,
378 IXMLDOMSelection_tid
,
380 queryresult_iface_tids
383 #define XSLPATTERN_CHECK_ARGS(n) \
385 FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
386 xmlXPathSetArityError(pctx); \
391 void XSLPattern_index(xmlXPathParserContextPtr pctx
, int nargs
)
393 XSLPATTERN_CHECK_ARGS(0);
395 xmlXPathPositionFunction(pctx
, 0);
396 xmlXPathReturnNumber(pctx
, xmlXPathPopNumber(pctx
) - 1.0);
399 void XSLPattern_end(xmlXPathParserContextPtr pctx
, int nargs
)
402 XSLPATTERN_CHECK_ARGS(0);
404 xmlXPathPositionFunction(pctx
, 0);
405 pos
= xmlXPathPopNumber(pctx
);
406 xmlXPathLastFunction(pctx
, 0);
407 last
= xmlXPathPopNumber(pctx
);
408 xmlXPathReturnBoolean(pctx
, pos
== last
);
411 void XSLPattern_nodeType(xmlXPathParserContextPtr pctx
, int nargs
)
413 XSLPATTERN_CHECK_ARGS(0);
414 xmlXPathReturnNumber(pctx
, pctx
->context
->node
->type
);
417 void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx
, int nargs
)
419 xmlChar
*arg1
, *arg2
;
420 XSLPATTERN_CHECK_ARGS(2);
422 arg2
= xmlXPathPopString(pctx
);
423 arg1
= xmlXPathPopString(pctx
);
424 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) == 0);
429 void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx
, int nargs
)
431 xmlChar
*arg1
, *arg2
;
432 XSLPATTERN_CHECK_ARGS(2);
434 arg2
= xmlXPathPopString(pctx
);
435 arg1
= xmlXPathPopString(pctx
);
436 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) != 0);
441 void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx
, int nargs
)
443 xmlChar
*arg1
, *arg2
;
444 XSLPATTERN_CHECK_ARGS(2);
446 arg2
= xmlXPathPopString(pctx
);
447 arg1
= xmlXPathPopString(pctx
);
448 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) < 0);
453 void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx
, int nargs
)
455 xmlChar
*arg1
, *arg2
;
456 XSLPATTERN_CHECK_ARGS(2);
458 arg2
= xmlXPathPopString(pctx
);
459 arg1
= xmlXPathPopString(pctx
);
460 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) <= 0);
465 void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx
, int nargs
)
467 xmlChar
*arg1
, *arg2
;
468 XSLPATTERN_CHECK_ARGS(2);
470 arg2
= xmlXPathPopString(pctx
);
471 arg1
= xmlXPathPopString(pctx
);
472 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) > 0);
477 void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx
, int nargs
)
479 xmlChar
*arg1
, *arg2
;
480 XSLPATTERN_CHECK_ARGS(2);
482 arg2
= xmlXPathPopString(pctx
);
483 arg1
= xmlXPathPopString(pctx
);
484 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) >= 0);
489 static void query_serror(void* ctx
, xmlErrorPtr err
)
491 LIBXML2_CALLBACK_SERROR(queryresult_create
, err
);
494 HRESULT
queryresult_create(xmlNodePtr node
, xmlChar
* szQuery
, IXMLDOMNodeList
**out
)
496 queryresult
*This
= heap_alloc_zero(sizeof(queryresult
));
497 xmlXPathContextPtr ctxt
= xmlXPathNewContext(node
->doc
);
500 TRACE("(%p, %s, %p)\n", node
, wine_dbgstr_a((char const*)szQuery
), out
);
503 if (This
== NULL
|| ctxt
== NULL
|| szQuery
== NULL
)
509 This
->lpVtbl
= &queryresult_vtbl
;
513 xmldoc_add_ref(This
->node
->doc
);
515 ctxt
->error
= query_serror
;
517 registerNamespaces(ctxt
);
519 if (is_xpathmode(This
->node
->doc
))
521 xmlXPathRegisterAllFunctions(ctxt
);
522 This
->result
= xmlXPathEvalExpression(szQuery
, ctxt
);
526 xmlChar
* xslpQuery
= XSLPattern_to_XPath(ctxt
, szQuery
);
528 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"not", xmlXPathNotFunction
);
529 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"boolean", xmlXPathBooleanFunction
);
531 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"index", XSLPattern_index
);
532 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"end", XSLPattern_end
);
533 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"nodeType", XSLPattern_nodeType
);
535 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IEq", XSLPattern_OP_IEq
);
536 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_INEq", XSLPattern_OP_INEq
);
537 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILt", XSLPattern_OP_ILt
);
538 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILEq", XSLPattern_OP_ILEq
);
539 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGt", XSLPattern_OP_IGt
);
540 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGEq", XSLPattern_OP_IGEq
);
542 This
->result
= xmlXPathEvalExpression(xslpQuery
, ctxt
);
546 if (!This
->result
|| This
->result
->type
!= XPATH_NODESET
)
552 init_dispex(&This
->dispex
, (IUnknown
*)&This
->lpVtbl
, &queryresult_dispex
);
554 *out
= (IXMLDOMNodeList
*) &This
->lpVtbl
;
556 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This
->result
->nodesetval
));
559 if (This
!= NULL
&& FAILED(hr
))
560 IXMLDOMNodeList_Release( (IXMLDOMNodeList
*) &This
->lpVtbl
);
561 xmlXPathFreeContext(ctxt
);