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
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 _domselection
64 IXMLDOMSelection IXMLDOMSelection_iface
;
67 xmlXPathObjectPtr result
;
71 static inline domselection
*impl_from_IXMLDOMSelection( IXMLDOMSelection
*iface
)
73 return CONTAINING_RECORD(iface
, domselection
, IXMLDOMSelection_iface
);
76 static HRESULT WINAPI
domselection_QueryInterface(
77 IXMLDOMSelection
*iface
,
81 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
83 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
88 if ( IsEqualGUID( riid
, &IID_IUnknown
) ||
89 IsEqualGUID( riid
, &IID_IXMLDOMNodeList
) ||
90 IsEqualGUID( riid
, &IID_IXMLDOMSelection
))
92 *ppvObject
= &This
->IXMLDOMSelection_iface
;
94 else if(dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
96 return *ppvObject
? S_OK
: E_NOINTERFACE
;
100 TRACE("interface %s not implemented\n", debugstr_guid(riid
));
102 return E_NOINTERFACE
;
105 IXMLDOMSelection_AddRef( iface
);
110 static ULONG WINAPI
domselection_AddRef(
111 IXMLDOMSelection
*iface
)
113 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
114 ULONG ref
= InterlockedIncrement( &This
->ref
);
115 TRACE("(%p)->(%d)\n", This
, ref
);
119 static ULONG WINAPI
domselection_Release(
120 IXMLDOMSelection
*iface
)
122 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
123 ULONG ref
= InterlockedDecrement(&This
->ref
);
125 TRACE("(%p)->(%d)\n", This
, ref
);
128 xmlXPathFreeObject(This
->result
);
129 xmldoc_release(This
->node
->doc
);
136 static HRESULT WINAPI
domselection_GetTypeInfoCount(
137 IXMLDOMSelection
*iface
,
140 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
142 TRACE("(%p)->(%p)\n", This
, pctinfo
);
149 static HRESULT WINAPI
domselection_GetTypeInfo(
150 IXMLDOMSelection
*iface
,
153 ITypeInfo
** ppTInfo
)
155 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
158 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
160 hr
= get_typeinfo(IXMLDOMSelection_tid
, ppTInfo
);
165 static HRESULT WINAPI
domselection_GetIDsOfNames(
166 IXMLDOMSelection
*iface
,
173 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
177 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
180 if(!rgszNames
|| cNames
== 0 || !rgDispId
)
183 hr
= get_typeinfo(IXMLDOMSelection_tid
, &typeinfo
);
186 hr
= ITypeInfo_GetIDsOfNames(typeinfo
, rgszNames
, cNames
, rgDispId
);
187 ITypeInfo_Release(typeinfo
);
193 static HRESULT WINAPI
domselection_Invoke(
194 IXMLDOMSelection
*iface
,
199 DISPPARAMS
* pDispParams
,
201 EXCEPINFO
* pExcepInfo
,
204 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
208 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
209 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
211 hr
= get_typeinfo(IXMLDOMSelection_tid
, &typeinfo
);
214 hr
= ITypeInfo_Invoke(typeinfo
, &This
->IXMLDOMSelection_iface
, dispIdMember
, wFlags
, pDispParams
,
215 pVarResult
, pExcepInfo
, puArgErr
);
216 ITypeInfo_Release(typeinfo
);
222 static HRESULT WINAPI
domselection_get_item(
223 IXMLDOMSelection
* iface
,
225 IXMLDOMNode
** listItem
)
227 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
229 TRACE("(%p)->(%d %p)\n", This
, index
, listItem
);
236 if (index
< 0 || index
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
239 *listItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, index
));
240 This
->resultPos
= index
+ 1;
245 static HRESULT WINAPI
domselection_get_length(
246 IXMLDOMSelection
* iface
,
249 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
251 TRACE("(%p)->(%p)\n", This
, listLength
);
256 *listLength
= xmlXPathNodeSetGetLength(This
->result
->nodesetval
);
260 static HRESULT WINAPI
domselection_nextNode(
261 IXMLDOMSelection
* iface
,
262 IXMLDOMNode
** nextItem
)
264 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
266 TRACE("(%p)->(%p)\n", This
, nextItem
);
273 if (This
->resultPos
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
276 *nextItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, This
->resultPos
));
281 static HRESULT WINAPI
domselection_reset(
282 IXMLDOMSelection
* iface
)
284 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
291 static HRESULT WINAPI
domselection_get__newEnum(
292 IXMLDOMSelection
* iface
,
295 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
296 FIXME("(%p)->(%p)\n", This
, ppUnk
);
300 static HRESULT WINAPI
domselection_get_expr(
301 IXMLDOMSelection
* iface
,
304 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
305 FIXME("(%p)->(%p)\n", This
, p
);
309 static HRESULT WINAPI
domselection_put_expr(
310 IXMLDOMSelection
* iface
,
313 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
314 FIXME("(%p)->(%s)\n", This
, debugstr_w(p
));
318 static HRESULT WINAPI
domselection_get_context(
319 IXMLDOMSelection
* iface
,
322 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
323 FIXME("(%p)->(%p)\n", This
, node
);
327 static HRESULT WINAPI
domselection_putref_context(
328 IXMLDOMSelection
* iface
,
331 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
332 FIXME("(%p)->(%p)\n", This
, node
);
336 static HRESULT WINAPI
domselection_peekNode(
337 IXMLDOMSelection
* iface
,
340 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
341 FIXME("(%p)->(%p)\n", This
, node
);
345 static HRESULT WINAPI
domselection_matches(
346 IXMLDOMSelection
* iface
,
348 IXMLDOMNode
**out_node
)
350 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
351 FIXME("(%p)->(%p %p)\n", This
, node
, out_node
);
355 static HRESULT WINAPI
domselection_removeNext(
356 IXMLDOMSelection
* iface
,
359 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
360 FIXME("(%p)->(%p)\n", This
, node
);
364 static HRESULT WINAPI
domselection_removeAll(
365 IXMLDOMSelection
* iface
)
367 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
368 FIXME("(%p)\n", This
);
372 static HRESULT WINAPI
domselection_clone(
373 IXMLDOMSelection
* iface
,
374 IXMLDOMSelection
**node
)
376 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
377 FIXME("(%p)->(%p)\n", This
, node
);
381 static HRESULT WINAPI
domselection_getProperty(
382 IXMLDOMSelection
* iface
,
386 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
387 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(p
), var
);
391 static HRESULT WINAPI
domselection_setProperty(
392 IXMLDOMSelection
* iface
,
396 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
397 FIXME("(%p)->(%s %s)\n", This
, debugstr_w(p
), debugstr_variant(&var
));
401 static const struct IXMLDOMSelectionVtbl domselection_vtbl
=
403 domselection_QueryInterface
,
405 domselection_Release
,
406 domselection_GetTypeInfoCount
,
407 domselection_GetTypeInfo
,
408 domselection_GetIDsOfNames
,
410 domselection_get_item
,
411 domselection_get_length
,
412 domselection_nextNode
,
414 domselection_get__newEnum
,
415 domselection_get_expr
,
416 domselection_put_expr
,
417 domselection_get_context
,
418 domselection_putref_context
,
419 domselection_peekNode
,
420 domselection_matches
,
421 domselection_removeNext
,
422 domselection_removeAll
,
424 domselection_getProperty
,
425 domselection_setProperty
428 static HRESULT
domselection_get_dispid(IUnknown
*iface
, BSTR name
, DWORD flags
, DISPID
*dispid
)
430 domselection
*This
= impl_from_IXMLDOMSelection( (IXMLDOMSelection
*)iface
);
434 for(ptr
= name
; *ptr
&& isdigitW(*ptr
); ptr
++)
435 idx
= idx
*10 + (*ptr
-'0');
437 return DISP_E_UNKNOWNNAME
;
439 if(idx
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
440 return DISP_E_UNKNOWNNAME
;
442 *dispid
= MSXML_DISPID_CUSTOM_MIN
+ idx
;
443 TRACE("ret %x\n", *dispid
);
447 static HRESULT
domselection_invoke(IUnknown
*iface
, DISPID id
, LCID lcid
, WORD flags
, DISPPARAMS
*params
,
448 VARIANT
*res
, EXCEPINFO
*ei
)
450 domselection
*This
= impl_from_IXMLDOMSelection( (IXMLDOMSelection
*)iface
);
452 TRACE("(%p)->(%x %x %x %p %p %p)\n", This
, id
, lcid
, flags
, params
, res
, ei
);
454 V_VT(res
) = VT_DISPATCH
;
455 V_DISPATCH(res
) = NULL
;
459 case INVOKE_PROPERTYGET
:
461 IXMLDOMNode
*disp
= NULL
;
463 domselection_get_item(&This
->IXMLDOMSelection_iface
, id
- MSXML_DISPID_CUSTOM_MIN
, &disp
);
464 V_DISPATCH(res
) = (IDispatch
*)disp
;
469 FIXME("unimplemented flags %x\n", flags
);
474 TRACE("ret %p\n", V_DISPATCH(res
));
479 static const dispex_static_data_vtbl_t domselection_dispex_vtbl
= {
480 domselection_get_dispid
,
484 static const tid_t domselection_iface_tids
[] = {
485 IXMLDOMSelection_tid
,
488 static dispex_static_data_t domselection_dispex
= {
489 &domselection_dispex_vtbl
,
490 IXMLDOMSelection_tid
,
492 domselection_iface_tids
495 #define XSLPATTERN_CHECK_ARGS(n) \
497 FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
498 xmlXPathSetArityError(pctx); \
503 static void XSLPattern_index(xmlXPathParserContextPtr pctx
, int nargs
)
505 XSLPATTERN_CHECK_ARGS(0);
507 xmlXPathPositionFunction(pctx
, 0);
508 xmlXPathReturnNumber(pctx
, xmlXPathPopNumber(pctx
) - 1.0);
511 static void XSLPattern_end(xmlXPathParserContextPtr pctx
, int nargs
)
514 XSLPATTERN_CHECK_ARGS(0);
516 xmlXPathPositionFunction(pctx
, 0);
517 pos
= xmlXPathPopNumber(pctx
);
518 xmlXPathLastFunction(pctx
, 0);
519 last
= xmlXPathPopNumber(pctx
);
520 xmlXPathReturnBoolean(pctx
, pos
== last
);
523 static void XSLPattern_nodeType(xmlXPathParserContextPtr pctx
, int nargs
)
525 XSLPATTERN_CHECK_ARGS(0);
526 xmlXPathReturnNumber(pctx
, pctx
->context
->node
->type
);
529 static void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx
, int nargs
)
531 xmlChar
*arg1
, *arg2
;
532 XSLPATTERN_CHECK_ARGS(2);
534 arg2
= xmlXPathPopString(pctx
);
535 arg1
= xmlXPathPopString(pctx
);
536 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) == 0);
541 static void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx
, int nargs
)
543 xmlChar
*arg1
, *arg2
;
544 XSLPATTERN_CHECK_ARGS(2);
546 arg2
= xmlXPathPopString(pctx
);
547 arg1
= xmlXPathPopString(pctx
);
548 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) != 0);
553 static void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx
, int nargs
)
555 xmlChar
*arg1
, *arg2
;
556 XSLPATTERN_CHECK_ARGS(2);
558 arg2
= xmlXPathPopString(pctx
);
559 arg1
= xmlXPathPopString(pctx
);
560 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) < 0);
565 static void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx
, int nargs
)
567 xmlChar
*arg1
, *arg2
;
568 XSLPATTERN_CHECK_ARGS(2);
570 arg2
= xmlXPathPopString(pctx
);
571 arg1
= xmlXPathPopString(pctx
);
572 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) <= 0);
577 static void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx
, int nargs
)
579 xmlChar
*arg1
, *arg2
;
580 XSLPATTERN_CHECK_ARGS(2);
582 arg2
= xmlXPathPopString(pctx
);
583 arg1
= xmlXPathPopString(pctx
);
584 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) > 0);
589 static void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx
, int nargs
)
591 xmlChar
*arg1
, *arg2
;
592 XSLPATTERN_CHECK_ARGS(2);
594 arg2
= xmlXPathPopString(pctx
);
595 arg1
= xmlXPathPopString(pctx
);
596 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) >= 0);
601 static void query_serror(void* ctx
, xmlErrorPtr err
)
603 LIBXML2_CALLBACK_SERROR(domselection_create
, err
);
606 HRESULT
create_selection(xmlNodePtr node
, xmlChar
* query
, IXMLDOMNodeList
**out
)
608 domselection
*This
= heap_alloc(sizeof(domselection
));
609 xmlXPathContextPtr ctxt
= xmlXPathNewContext(node
->doc
);
612 TRACE("(%p, %s, %p)\n", node
, wine_dbgstr_a((char const*)query
), out
);
615 if (!This
|| !ctxt
|| !query
)
621 This
->IXMLDOMSelection_iface
.lpVtbl
= &domselection_vtbl
;
625 xmldoc_add_ref(This
->node
->doc
);
627 ctxt
->error
= query_serror
;
629 registerNamespaces(ctxt
);
631 if (is_xpathmode(This
->node
->doc
))
633 xmlXPathRegisterAllFunctions(ctxt
);
634 This
->result
= xmlXPathEvalExpression(query
, ctxt
);
638 xmlChar
* pattern_query
= XSLPattern_to_XPath(ctxt
, query
);
640 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"not", xmlXPathNotFunction
);
641 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"boolean", xmlXPathBooleanFunction
);
643 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"index", XSLPattern_index
);
644 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"end", XSLPattern_end
);
645 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"nodeType", XSLPattern_nodeType
);
647 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IEq", XSLPattern_OP_IEq
);
648 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_INEq", XSLPattern_OP_INEq
);
649 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILt", XSLPattern_OP_ILt
);
650 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILEq", XSLPattern_OP_ILEq
);
651 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGt", XSLPattern_OP_IGt
);
652 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGEq", XSLPattern_OP_IGEq
);
654 This
->result
= xmlXPathEvalExpression(pattern_query
, ctxt
);
655 xmlFree(pattern_query
);
658 if (!This
->result
|| This
->result
->type
!= XPATH_NODESET
)
664 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IXMLDOMSelection_iface
, &domselection_dispex
);
666 *out
= (IXMLDOMNodeList
*)&This
->IXMLDOMSelection_iface
;
668 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This
->result
->nodesetval
));
671 if (This
&& FAILED(hr
))
672 IXMLDOMSelection_Release( &This
->IXMLDOMSelection_iface
);
673 xmlXPathFreeContext(ctxt
);