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
26 # include <libxml/xpathInternals.h>
29 #include <msxml2did.h>
31 /* This file implements the object returned by a XPath query. Note that this is
32 * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
33 * They are different because the list returned by XPath queries:
34 * - is static - gives the results for the XML tree as it existed during the
35 * execution of the query
36 * - supports IXMLDOMSelection
42 int registerNamespaces(xmlXPathContextPtr ctxt
);
43 xmlChar
* XSLPattern_to_XPath(xmlXPathContextPtr ctxt
, xmlChar
const* xslpat_str
);
47 IEnumVARIANT IEnumVARIANT_iface
;
55 const struct enumvariant_funcs
*funcs
;
61 IXMLDOMSelection IXMLDOMSelection_iface
;
64 xmlXPathObjectPtr result
;
66 IEnumVARIANT
*enumvariant
;
69 static HRESULT
selection_get_item(IUnknown
*iface
, LONG index
, VARIANT
* item
)
71 V_VT(item
) = VT_DISPATCH
;
72 return IXMLDOMSelection_get_item((IXMLDOMSelection
*)iface
, index
, (IXMLDOMNode
**)&V_DISPATCH(item
));
75 static HRESULT
selection_next(IUnknown
*iface
)
78 HRESULT hr
= IXMLDOMSelection_nextNode((IXMLDOMSelection
*)iface
, &node
);
79 if (hr
== S_OK
) IXMLDOMNode_Release(node
);
83 static const struct enumvariant_funcs selection_enumvariant
= {
88 static inline domselection
*impl_from_IXMLDOMSelection( IXMLDOMSelection
*iface
)
90 return CONTAINING_RECORD(iface
, domselection
, IXMLDOMSelection_iface
);
93 static inline enumvariant
*impl_from_IEnumVARIANT( IEnumVARIANT
*iface
)
95 return CONTAINING_RECORD(iface
, enumvariant
, IEnumVARIANT_iface
);
98 static HRESULT WINAPI
domselection_QueryInterface(
99 IXMLDOMSelection
*iface
,
103 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
105 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
110 if ( IsEqualGUID( riid
, &IID_IUnknown
) ||
111 IsEqualGUID( riid
, &IID_IXMLDOMNodeList
) ||
112 IsEqualGUID( riid
, &IID_IXMLDOMSelection
))
114 *ppvObject
= &This
->IXMLDOMSelection_iface
;
116 else if (IsEqualGUID( riid
, &IID_IEnumVARIANT
))
118 if (!This
->enumvariant
)
120 HRESULT hr
= create_enumvariant((IUnknown
*)iface
, FALSE
, &selection_enumvariant
, &This
->enumvariant
);
121 if (FAILED(hr
)) return hr
;
124 return IEnumVARIANT_QueryInterface(This
->enumvariant
, &IID_IEnumVARIANT
, ppvObject
);
126 else if (dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
128 return *ppvObject
? S_OK
: E_NOINTERFACE
;
132 TRACE("interface %s not implemented\n", debugstr_guid(riid
));
134 return E_NOINTERFACE
;
137 IXMLDOMSelection_AddRef( iface
);
142 static ULONG WINAPI
domselection_AddRef(
143 IXMLDOMSelection
*iface
)
145 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
146 ULONG ref
= InterlockedIncrement( &This
->ref
);
147 TRACE("(%p)->(%d)\n", This
, ref
);
151 static ULONG WINAPI
domselection_Release(
152 IXMLDOMSelection
*iface
)
154 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
155 ULONG ref
= InterlockedDecrement(&This
->ref
);
157 TRACE("(%p)->(%d)\n", This
, ref
);
160 xmlXPathFreeObject(This
->result
);
161 xmldoc_release(This
->node
->doc
);
162 if (This
->enumvariant
) IEnumVARIANT_Release(This
->enumvariant
);
169 static HRESULT WINAPI
domselection_GetTypeInfoCount(
170 IXMLDOMSelection
*iface
,
173 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
174 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
177 static HRESULT WINAPI
domselection_GetTypeInfo(
178 IXMLDOMSelection
*iface
,
181 ITypeInfo
** ppTInfo
)
183 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
184 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
185 iTInfo
, lcid
, ppTInfo
);
188 static HRESULT WINAPI
domselection_GetIDsOfNames(
189 IXMLDOMSelection
*iface
,
196 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
197 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
198 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
201 static HRESULT WINAPI
domselection_Invoke(
202 IXMLDOMSelection
*iface
,
207 DISPPARAMS
* pDispParams
,
209 EXCEPINFO
* pExcepInfo
,
212 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
213 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
214 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
217 static HRESULT WINAPI
domselection_get_item(
218 IXMLDOMSelection
* iface
,
220 IXMLDOMNode
** listItem
)
222 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
224 TRACE("(%p)->(%d %p)\n", This
, index
, listItem
);
231 if (index
< 0 || index
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
234 *listItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, index
));
235 This
->resultPos
= index
+ 1;
240 static HRESULT WINAPI
domselection_get_length(
241 IXMLDOMSelection
* iface
,
244 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
246 TRACE("(%p)->(%p)\n", This
, listLength
);
251 *listLength
= xmlXPathNodeSetGetLength(This
->result
->nodesetval
);
255 static HRESULT WINAPI
domselection_nextNode(
256 IXMLDOMSelection
* iface
,
257 IXMLDOMNode
** nextItem
)
259 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
261 TRACE("(%p)->(%p)\n", This
, nextItem
);
268 if (This
->resultPos
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
271 *nextItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, This
->resultPos
));
276 static HRESULT WINAPI
domselection_reset(
277 IXMLDOMSelection
* iface
)
279 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
286 static HRESULT WINAPI
domselection_get__newEnum(
287 IXMLDOMSelection
* iface
,
290 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
292 TRACE("(%p)->(%p)\n", This
, enumv
);
294 return create_enumvariant((IUnknown
*)iface
, TRUE
, &selection_enumvariant
, (IEnumVARIANT
**)enumv
);
297 static HRESULT WINAPI
domselection_get_expr(
298 IXMLDOMSelection
* iface
,
301 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
302 FIXME("(%p)->(%p)\n", This
, p
);
306 static HRESULT WINAPI
domselection_put_expr(
307 IXMLDOMSelection
* iface
,
310 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
311 FIXME("(%p)->(%s)\n", This
, debugstr_w(p
));
315 static HRESULT WINAPI
domselection_get_context(
316 IXMLDOMSelection
* iface
,
319 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
320 FIXME("(%p)->(%p)\n", This
, node
);
324 static HRESULT WINAPI
domselection_putref_context(
325 IXMLDOMSelection
* iface
,
328 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
329 FIXME("(%p)->(%p)\n", This
, node
);
333 static HRESULT WINAPI
domselection_peekNode(
334 IXMLDOMSelection
* iface
,
337 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
338 FIXME("(%p)->(%p)\n", This
, node
);
342 static HRESULT WINAPI
domselection_matches(
343 IXMLDOMSelection
* iface
,
345 IXMLDOMNode
**out_node
)
347 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
348 FIXME("(%p)->(%p %p)\n", This
, node
, out_node
);
352 static HRESULT WINAPI
domselection_removeNext(
353 IXMLDOMSelection
* iface
,
356 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
357 FIXME("(%p)->(%p)\n", This
, node
);
361 static HRESULT WINAPI
domselection_removeAll(
362 IXMLDOMSelection
* iface
)
364 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
365 FIXME("(%p)\n", This
);
369 static HRESULT WINAPI
domselection_clone(
370 IXMLDOMSelection
* iface
,
371 IXMLDOMSelection
**node
)
373 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
374 FIXME("(%p)->(%p)\n", This
, node
);
378 static HRESULT WINAPI
domselection_getProperty(
379 IXMLDOMSelection
* iface
,
383 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
384 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(p
), var
);
388 static HRESULT WINAPI
domselection_setProperty(
389 IXMLDOMSelection
* iface
,
393 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
394 FIXME("(%p)->(%s %s)\n", This
, debugstr_w(p
), debugstr_variant(&var
));
398 static const struct IXMLDOMSelectionVtbl domselection_vtbl
=
400 domselection_QueryInterface
,
402 domselection_Release
,
403 domselection_GetTypeInfoCount
,
404 domselection_GetTypeInfo
,
405 domselection_GetIDsOfNames
,
407 domselection_get_item
,
408 domselection_get_length
,
409 domselection_nextNode
,
411 domselection_get__newEnum
,
412 domselection_get_expr
,
413 domselection_put_expr
,
414 domselection_get_context
,
415 domselection_putref_context
,
416 domselection_peekNode
,
417 domselection_matches
,
418 domselection_removeNext
,
419 domselection_removeAll
,
421 domselection_getProperty
,
422 domselection_setProperty
425 /* IEnumVARIANT support */
426 static HRESULT WINAPI
enumvariant_QueryInterface(
431 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
433 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
437 if (IsEqualGUID( riid
, &IID_IUnknown
))
440 *ppvObject
= &This
->IEnumVARIANT_iface
;
442 return IUnknown_QueryInterface(This
->outer
, riid
, ppvObject
);
444 else if (IsEqualGUID( riid
, &IID_IEnumVARIANT
))
446 *ppvObject
= &This
->IEnumVARIANT_iface
;
449 return IUnknown_QueryInterface(This
->outer
, riid
, ppvObject
);
451 IEnumVARIANT_AddRef( iface
);
456 static ULONG WINAPI
enumvariant_AddRef(IEnumVARIANT
*iface
)
458 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
459 ULONG ref
= InterlockedIncrement( &This
->ref
);
460 TRACE("(%p)->(%d)\n", This
, ref
);
464 static ULONG WINAPI
enumvariant_Release(IEnumVARIANT
*iface
)
466 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
467 ULONG ref
= InterlockedDecrement(&This
->ref
);
469 TRACE("(%p)->(%d)\n", This
, ref
);
472 if (This
->own
) IUnknown_Release(This
->outer
);
479 static HRESULT WINAPI
enumvariant_Next(
485 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
488 TRACE("(%p)->(%u %p %p)\n", This
, celt
, var
, fetched
);
490 if (fetched
) *fetched
= 0;
492 if (celt
&& !var
) return E_INVALIDARG
;
494 for (; celt
> 0; celt
--, var
++, This
->pos
++)
496 HRESULT hr
= This
->funcs
->get_item(This
->outer
, This
->pos
, var
);
499 V_VT(var
) = VT_EMPTY
;
505 if (fetched
) (*fetched
)++;
507 /* we need to advance one step more for some reason */
510 if (This
->funcs
->next
)
511 This
->funcs
->next(This
->outer
);
514 return celt
== 0 ? S_OK
: S_FALSE
;
517 static HRESULT WINAPI
enumvariant_Skip(
521 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
522 FIXME("(%p)->(%u): stub\n", This
, celt
);
526 static HRESULT WINAPI
enumvariant_Reset(IEnumVARIANT
*iface
)
528 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
529 FIXME("(%p): stub\n", This
);
533 static HRESULT WINAPI
enumvariant_Clone(
534 IEnumVARIANT
*iface
, IEnumVARIANT
**ppenum
)
536 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
537 FIXME("(%p)->(%p): stub\n", This
, ppenum
);
541 static const struct IEnumVARIANTVtbl EnumVARIANTVtbl
=
543 enumvariant_QueryInterface
,
552 HRESULT
create_enumvariant(IUnknown
*outer
, BOOL own
, const struct enumvariant_funcs
*funcs
, IEnumVARIANT
**penum
)
556 This
= heap_alloc(sizeof(enumvariant
));
557 if (!This
) return E_OUTOFMEMORY
;
559 This
->IEnumVARIANT_iface
.lpVtbl
= &EnumVARIANTVtbl
;
567 IUnknown_AddRef(This
->outer
);
569 *penum
= &This
->IEnumVARIANT_iface
;
570 IEnumVARIANT_AddRef(*penum
);
574 static HRESULT
domselection_get_dispid(IUnknown
*iface
, BSTR name
, DWORD flags
, DISPID
*dispid
)
579 for(ptr
= name
; *ptr
&& isdigitW(*ptr
); ptr
++)
580 idx
= idx
*10 + (*ptr
-'0');
582 return DISP_E_UNKNOWNNAME
;
584 *dispid
= DISPID_DOM_COLLECTION_BASE
+ idx
;
585 TRACE("ret %x\n", *dispid
);
589 static HRESULT
domselection_invoke(IUnknown
*iface
, DISPID id
, LCID lcid
, WORD flags
, DISPPARAMS
*params
,
590 VARIANT
*res
, EXCEPINFO
*ei
)
592 domselection
*This
= impl_from_IXMLDOMSelection( (IXMLDOMSelection
*)iface
);
594 TRACE("(%p)->(%x %x %x %p %p %p)\n", This
, id
, lcid
, flags
, params
, res
, ei
);
596 V_VT(res
) = VT_DISPATCH
;
597 V_DISPATCH(res
) = NULL
;
599 if (id
< DISPID_DOM_COLLECTION_BASE
|| id
> DISPID_DOM_COLLECTION_MAX
)
600 return DISP_E_UNKNOWNNAME
;
604 case INVOKE_PROPERTYGET
:
606 IXMLDOMNode
*disp
= NULL
;
608 IXMLDOMSelection_get_item(&This
->IXMLDOMSelection_iface
, id
- DISPID_DOM_COLLECTION_BASE
, &disp
);
609 V_DISPATCH(res
) = (IDispatch
*)disp
;
614 FIXME("unimplemented flags %x\n", flags
);
619 TRACE("ret %p\n", V_DISPATCH(res
));
624 static const dispex_static_data_vtbl_t domselection_dispex_vtbl
= {
625 domselection_get_dispid
,
629 static const tid_t domselection_iface_tids
[] = {
630 IXMLDOMSelection_tid
,
633 static dispex_static_data_t domselection_dispex
= {
634 &domselection_dispex_vtbl
,
635 IXMLDOMSelection_tid
,
637 domselection_iface_tids
640 #define XSLPATTERN_CHECK_ARGS(n) \
642 FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
643 xmlXPathSetArityError(pctx); \
648 static void XSLPattern_index(xmlXPathParserContextPtr pctx
, int nargs
)
650 XSLPATTERN_CHECK_ARGS(0);
652 xmlXPathPositionFunction(pctx
, 0);
653 xmlXPathReturnNumber(pctx
, xmlXPathPopNumber(pctx
) - 1.0);
656 static void XSLPattern_end(xmlXPathParserContextPtr pctx
, int nargs
)
659 XSLPATTERN_CHECK_ARGS(0);
661 xmlXPathPositionFunction(pctx
, 0);
662 pos
= xmlXPathPopNumber(pctx
);
663 xmlXPathLastFunction(pctx
, 0);
664 last
= xmlXPathPopNumber(pctx
);
665 xmlXPathReturnBoolean(pctx
, pos
== last
);
668 static void XSLPattern_nodeType(xmlXPathParserContextPtr pctx
, int nargs
)
670 XSLPATTERN_CHECK_ARGS(0);
671 xmlXPathReturnNumber(pctx
, pctx
->context
->node
->type
);
674 static void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx
, int nargs
)
676 xmlChar
*arg1
, *arg2
;
677 XSLPATTERN_CHECK_ARGS(2);
679 arg2
= xmlXPathPopString(pctx
);
680 arg1
= xmlXPathPopString(pctx
);
681 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) == 0);
686 static void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx
, int nargs
)
688 xmlChar
*arg1
, *arg2
;
689 XSLPATTERN_CHECK_ARGS(2);
691 arg2
= xmlXPathPopString(pctx
);
692 arg1
= xmlXPathPopString(pctx
);
693 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) != 0);
698 static void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx
, int nargs
)
700 xmlChar
*arg1
, *arg2
;
701 XSLPATTERN_CHECK_ARGS(2);
703 arg2
= xmlXPathPopString(pctx
);
704 arg1
= xmlXPathPopString(pctx
);
705 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) < 0);
710 static void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx
, int nargs
)
712 xmlChar
*arg1
, *arg2
;
713 XSLPATTERN_CHECK_ARGS(2);
715 arg2
= xmlXPathPopString(pctx
);
716 arg1
= xmlXPathPopString(pctx
);
717 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) <= 0);
722 static void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx
, int nargs
)
724 xmlChar
*arg1
, *arg2
;
725 XSLPATTERN_CHECK_ARGS(2);
727 arg2
= xmlXPathPopString(pctx
);
728 arg1
= xmlXPathPopString(pctx
);
729 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) > 0);
734 static void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx
, int nargs
)
736 xmlChar
*arg1
, *arg2
;
737 XSLPATTERN_CHECK_ARGS(2);
739 arg2
= xmlXPathPopString(pctx
);
740 arg1
= xmlXPathPopString(pctx
);
741 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) >= 0);
746 static void query_serror(void* ctx
, xmlErrorPtr err
)
748 LIBXML2_CALLBACK_SERROR(domselection_create
, err
);
751 HRESULT
create_selection(xmlNodePtr node
, xmlChar
* query
, IXMLDOMNodeList
**out
)
753 domselection
*This
= heap_alloc(sizeof(domselection
));
754 xmlXPathContextPtr ctxt
= xmlXPathNewContext(node
->doc
);
757 TRACE("(%p, %s, %p)\n", node
, debugstr_a((char const*)query
), out
);
760 if (!This
|| !ctxt
|| !query
)
762 xmlXPathFreeContext(ctxt
);
764 return E_OUTOFMEMORY
;
767 This
->IXMLDOMSelection_iface
.lpVtbl
= &domselection_vtbl
;
771 This
->enumvariant
= NULL
;
772 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IXMLDOMSelection_iface
, &domselection_dispex
);
773 xmldoc_add_ref(This
->node
->doc
);
775 ctxt
->error
= query_serror
;
777 registerNamespaces(ctxt
);
779 if (is_xpathmode(This
->node
->doc
))
781 xmlXPathRegisterAllFunctions(ctxt
);
782 This
->result
= xmlXPathEvalExpression(query
, ctxt
);
786 xmlChar
* pattern_query
= XSLPattern_to_XPath(ctxt
, query
);
788 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"not", xmlXPathNotFunction
);
789 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"boolean", xmlXPathBooleanFunction
);
791 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"index", XSLPattern_index
);
792 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"end", XSLPattern_end
);
793 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"nodeType", XSLPattern_nodeType
);
795 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IEq", XSLPattern_OP_IEq
);
796 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_INEq", XSLPattern_OP_INEq
);
797 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILt", XSLPattern_OP_ILt
);
798 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILEq", XSLPattern_OP_ILEq
);
799 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGt", XSLPattern_OP_IGt
);
800 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGEq", XSLPattern_OP_IGEq
);
802 This
->result
= xmlXPathEvalExpression(pattern_query
, ctxt
);
803 xmlFree(pattern_query
);
806 if (!This
->result
|| This
->result
->type
!= XPATH_NODESET
)
812 *out
= (IXMLDOMNodeList
*)&This
->IXMLDOMSelection_iface
;
814 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This
->result
->nodesetval
));
817 if (This
&& FAILED(hr
))
818 IXMLDOMSelection_Release( &This
->IXMLDOMSelection_iface
);
819 xmlXPathFreeContext(ctxt
);