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>
40 #include "msxml2did.h"
42 #include "msxml_private.h"
44 #include "wine/debug.h"
46 /* This file implements the object returned by a XPath query. Note that this is
47 * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
48 * They are different because the list returned by XPath queries:
49 * - is static - gives the results for the XML tree as it existed during the
50 * execution of the query
51 * - supports IXMLDOMSelection
55 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
59 int registerNamespaces(xmlXPathContextPtr ctxt
);
60 xmlChar
* XSLPattern_to_XPath(xmlXPathContextPtr ctxt
, xmlChar
const* xslpat_str
);
62 typedef struct _enumvariant
64 IEnumVARIANT IEnumVARIANT_iface
;
67 IXMLDOMSelection
*selection
;
73 typedef struct _domselection
76 IXMLDOMSelection IXMLDOMSelection_iface
;
79 xmlXPathObjectPtr result
;
81 IEnumVARIANT
*enumvariant
;
84 static inline domselection
*impl_from_IXMLDOMSelection( IXMLDOMSelection
*iface
)
86 return CONTAINING_RECORD(iface
, domselection
, IXMLDOMSelection_iface
);
89 static inline enumvariant
*impl_from_IEnumVARIANT( IEnumVARIANT
*iface
)
91 return CONTAINING_RECORD(iface
, enumvariant
, IEnumVARIANT_iface
);
94 static HRESULT
create_enumvariant(IXMLDOMSelection
*, BOOL
, IUnknown
**);
96 static HRESULT WINAPI
domselection_QueryInterface(
97 IXMLDOMSelection
*iface
,
101 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
103 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
108 if ( IsEqualGUID( riid
, &IID_IUnknown
) ||
109 IsEqualGUID( riid
, &IID_IXMLDOMNodeList
) ||
110 IsEqualGUID( riid
, &IID_IXMLDOMSelection
))
112 *ppvObject
= &This
->IXMLDOMSelection_iface
;
114 else if (IsEqualGUID( riid
, &IID_IEnumVARIANT
))
116 if (!This
->enumvariant
)
118 HRESULT hr
= create_enumvariant(iface
, FALSE
, (IUnknown
**)&This
->enumvariant
);
119 if (FAILED(hr
)) return hr
;
122 return IEnumVARIANT_QueryInterface(This
->enumvariant
, &IID_IEnumVARIANT
, ppvObject
);
124 else if (dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
126 return *ppvObject
? S_OK
: E_NOINTERFACE
;
130 TRACE("interface %s not implemented\n", debugstr_guid(riid
));
132 return E_NOINTERFACE
;
135 IXMLDOMSelection_AddRef( iface
);
140 static ULONG WINAPI
domselection_AddRef(
141 IXMLDOMSelection
*iface
)
143 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
144 ULONG ref
= InterlockedIncrement( &This
->ref
);
145 TRACE("(%p)->(%d)\n", This
, ref
);
149 static ULONG WINAPI
domselection_Release(
150 IXMLDOMSelection
*iface
)
152 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
153 ULONG ref
= InterlockedDecrement(&This
->ref
);
155 TRACE("(%p)->(%d)\n", This
, ref
);
158 xmlXPathFreeObject(This
->result
);
159 xmldoc_release(This
->node
->doc
);
160 if (This
->enumvariant
) IEnumVARIANT_Release(This
->enumvariant
);
161 release_dispex(&This
->dispex
);
168 static HRESULT WINAPI
domselection_GetTypeInfoCount(
169 IXMLDOMSelection
*iface
,
172 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
173 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
176 static HRESULT WINAPI
domselection_GetTypeInfo(
177 IXMLDOMSelection
*iface
,
180 ITypeInfo
** ppTInfo
)
182 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
183 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
184 iTInfo
, lcid
, ppTInfo
);
187 static HRESULT WINAPI
domselection_GetIDsOfNames(
188 IXMLDOMSelection
*iface
,
195 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
196 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
197 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
200 static HRESULT WINAPI
domselection_Invoke(
201 IXMLDOMSelection
*iface
,
206 DISPPARAMS
* pDispParams
,
208 EXCEPINFO
* pExcepInfo
,
211 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
212 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
213 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
216 static HRESULT WINAPI
domselection_get_item(
217 IXMLDOMSelection
* iface
,
219 IXMLDOMNode
** listItem
)
221 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
223 TRACE("(%p)->(%d %p)\n", This
, index
, listItem
);
230 if (index
< 0 || index
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
233 *listItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, index
));
234 This
->resultPos
= index
+ 1;
239 static HRESULT WINAPI
domselection_get_length(
240 IXMLDOMSelection
* iface
,
243 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
245 TRACE("(%p)->(%p)\n", This
, listLength
);
250 *listLength
= xmlXPathNodeSetGetLength(This
->result
->nodesetval
);
254 static HRESULT WINAPI
domselection_nextNode(
255 IXMLDOMSelection
* iface
,
256 IXMLDOMNode
** nextItem
)
258 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
260 TRACE("(%p)->(%p)\n", This
, nextItem
);
267 if (This
->resultPos
>= xmlXPathNodeSetGetLength(This
->result
->nodesetval
))
270 *nextItem
= create_node(xmlXPathNodeSetItem(This
->result
->nodesetval
, This
->resultPos
));
275 static HRESULT WINAPI
domselection_reset(
276 IXMLDOMSelection
* iface
)
278 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
285 static HRESULT WINAPI
domselection_get__newEnum(
286 IXMLDOMSelection
* iface
,
289 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
291 TRACE("(%p)->(%p)\n", This
, ppUnk
);
293 return create_enumvariant(iface
, TRUE
, ppUnk
);
296 static HRESULT WINAPI
domselection_get_expr(
297 IXMLDOMSelection
* iface
,
300 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
301 FIXME("(%p)->(%p)\n", This
, p
);
305 static HRESULT WINAPI
domselection_put_expr(
306 IXMLDOMSelection
* iface
,
309 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
310 FIXME("(%p)->(%s)\n", This
, debugstr_w(p
));
314 static HRESULT WINAPI
domselection_get_context(
315 IXMLDOMSelection
* iface
,
318 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
319 FIXME("(%p)->(%p)\n", This
, node
);
323 static HRESULT WINAPI
domselection_putref_context(
324 IXMLDOMSelection
* iface
,
327 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
328 FIXME("(%p)->(%p)\n", This
, node
);
332 static HRESULT WINAPI
domselection_peekNode(
333 IXMLDOMSelection
* iface
,
336 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
337 FIXME("(%p)->(%p)\n", This
, node
);
341 static HRESULT WINAPI
domselection_matches(
342 IXMLDOMSelection
* iface
,
344 IXMLDOMNode
**out_node
)
346 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
347 FIXME("(%p)->(%p %p)\n", This
, node
, out_node
);
351 static HRESULT WINAPI
domselection_removeNext(
352 IXMLDOMSelection
* iface
,
355 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
356 FIXME("(%p)->(%p)\n", This
, node
);
360 static HRESULT WINAPI
domselection_removeAll(
361 IXMLDOMSelection
* iface
)
363 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
364 FIXME("(%p)\n", This
);
368 static HRESULT WINAPI
domselection_clone(
369 IXMLDOMSelection
* iface
,
370 IXMLDOMSelection
**node
)
372 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
373 FIXME("(%p)->(%p)\n", This
, node
);
377 static HRESULT WINAPI
domselection_getProperty(
378 IXMLDOMSelection
* iface
,
382 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
383 FIXME("(%p)->(%s %p)\n", This
, debugstr_w(p
), var
);
387 static HRESULT WINAPI
domselection_setProperty(
388 IXMLDOMSelection
* iface
,
392 domselection
*This
= impl_from_IXMLDOMSelection( iface
);
393 FIXME("(%p)->(%s %s)\n", This
, debugstr_w(p
), debugstr_variant(&var
));
397 static const struct IXMLDOMSelectionVtbl domselection_vtbl
=
399 domselection_QueryInterface
,
401 domselection_Release
,
402 domselection_GetTypeInfoCount
,
403 domselection_GetTypeInfo
,
404 domselection_GetIDsOfNames
,
406 domselection_get_item
,
407 domselection_get_length
,
408 domselection_nextNode
,
410 domselection_get__newEnum
,
411 domselection_get_expr
,
412 domselection_put_expr
,
413 domselection_get_context
,
414 domselection_putref_context
,
415 domselection_peekNode
,
416 domselection_matches
,
417 domselection_removeNext
,
418 domselection_removeAll
,
420 domselection_getProperty
,
421 domselection_setProperty
424 /* IEnumVARIANT support */
425 static HRESULT WINAPI
enumvariant_QueryInterface(
430 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
432 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
436 if ( IsEqualGUID( riid
, &IID_IUnknown
) ||
437 IsEqualGUID( riid
, &IID_IEnumVARIANT
))
439 *ppvObject
= &This
->IEnumVARIANT_iface
;
442 return IXMLDOMSelection_QueryInterface(This
->selection
, riid
, ppvObject
);
444 IEnumVARIANT_AddRef( iface
);
449 static ULONG WINAPI
enumvariant_AddRef(IEnumVARIANT
*iface
)
451 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
452 ULONG ref
= InterlockedIncrement( &This
->ref
);
453 TRACE("(%p)->(%d)\n", This
, ref
);
457 static ULONG WINAPI
enumvariant_Release(IEnumVARIANT
*iface
)
459 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
460 ULONG ref
= InterlockedDecrement(&This
->ref
);
462 TRACE("(%p)->(%d)\n", This
, ref
);
465 if (This
->own
) IXMLDOMSelection_Release(This
->selection
);
472 static HRESULT WINAPI
enumvariant_Next(
478 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
482 TRACE("(%p)->(%u %p %p)\n", This
, celt
, var
, fetched
);
484 if (fetched
) *fetched
= 0;
486 if (celt
&& !var
) return E_INVALIDARG
;
488 for (; celt
> 0; celt
--, var
++, This
->pos
++)
490 IDispatch
*disp
= NULL
;
494 hr
= IXMLDOMSelection_get_item(This
->selection
, This
->pos
, &node
);
495 if (hr
!= S_OK
) break;
497 IXMLDOMNode_QueryInterface(node
, &IID_IDispatch
, (void**)&disp
);
498 IXMLDOMNode_Release(node
);
500 V_VT(var
) = VT_DISPATCH
;
501 V_DISPATCH(var
) = disp
;
506 if (fetched
) (*fetched
)++;
508 /* we need to advance one step more for some reason */
510 IXMLDOMSelection_nextNode(This
->selection
, &node
);
512 return celt
== 0 ? S_OK
: S_FALSE
;
515 static HRESULT WINAPI
enumvariant_Skip(
519 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
520 FIXME("(%p)->(%u): stub\n", This
, celt
);
524 static HRESULT WINAPI
enumvariant_Reset(IEnumVARIANT
*iface
)
526 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
527 FIXME("(%p): stub\n", This
);
531 static HRESULT WINAPI
enumvariant_Clone(
532 IEnumVARIANT
*iface
, IEnumVARIANT
**ppenum
)
534 enumvariant
*This
= impl_from_IEnumVARIANT( iface
);
535 FIXME("(%p)->(%p): stub\n", This
, ppenum
);
539 static const struct IEnumVARIANTVtbl EnumVARIANTVtbl
=
541 enumvariant_QueryInterface
,
550 static HRESULT
create_enumvariant(IXMLDOMSelection
*selection
, BOOL own
, IUnknown
**penum
)
554 This
= heap_alloc(sizeof(enumvariant
));
555 if (!This
) return E_OUTOFMEMORY
;
557 This
->IEnumVARIANT_iface
.lpVtbl
= &EnumVARIANTVtbl
;
559 This
->selection
= selection
;
564 IXMLDOMSelection_AddRef(selection
);
566 return IEnumVARIANT_QueryInterface(&This
->IEnumVARIANT_iface
, &IID_IUnknown
, (void**)penum
);
569 static HRESULT
domselection_get_dispid(IUnknown
*iface
, BSTR name
, DWORD flags
, DISPID
*dispid
)
574 for(ptr
= name
; *ptr
&& isdigitW(*ptr
); ptr
++)
575 idx
= idx
*10 + (*ptr
-'0');
577 return DISP_E_UNKNOWNNAME
;
579 *dispid
= DISPID_DOM_COLLECTION_BASE
+ idx
;
580 TRACE("ret %x\n", *dispid
);
584 static HRESULT
domselection_invoke(IUnknown
*iface
, DISPID id
, LCID lcid
, WORD flags
, DISPPARAMS
*params
,
585 VARIANT
*res
, EXCEPINFO
*ei
)
587 domselection
*This
= impl_from_IXMLDOMSelection( (IXMLDOMSelection
*)iface
);
589 TRACE("(%p)->(%x %x %x %p %p %p)\n", This
, id
, lcid
, flags
, params
, res
, ei
);
591 V_VT(res
) = VT_DISPATCH
;
592 V_DISPATCH(res
) = NULL
;
594 if (id
< DISPID_DOM_COLLECTION_BASE
|| id
> DISPID_DOM_COLLECTION_MAX
)
595 return DISP_E_UNKNOWNNAME
;
599 case INVOKE_PROPERTYGET
:
601 IXMLDOMNode
*disp
= NULL
;
603 IXMLDOMSelection_get_item(&This
->IXMLDOMSelection_iface
, id
- DISPID_DOM_COLLECTION_BASE
, &disp
);
604 V_DISPATCH(res
) = (IDispatch
*)disp
;
609 FIXME("unimplemented flags %x\n", flags
);
614 TRACE("ret %p\n", V_DISPATCH(res
));
619 static const dispex_static_data_vtbl_t domselection_dispex_vtbl
= {
620 domselection_get_dispid
,
624 static const tid_t domselection_iface_tids
[] = {
625 IXMLDOMSelection_tid
,
628 static dispex_static_data_t domselection_dispex
= {
629 &domselection_dispex_vtbl
,
630 IXMLDOMSelection_tid
,
632 domselection_iface_tids
635 #define XSLPATTERN_CHECK_ARGS(n) \
637 FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
638 xmlXPathSetArityError(pctx); \
643 static void XSLPattern_index(xmlXPathParserContextPtr pctx
, int nargs
)
645 XSLPATTERN_CHECK_ARGS(0);
647 xmlXPathPositionFunction(pctx
, 0);
648 xmlXPathReturnNumber(pctx
, xmlXPathPopNumber(pctx
) - 1.0);
651 static void XSLPattern_end(xmlXPathParserContextPtr pctx
, int nargs
)
654 XSLPATTERN_CHECK_ARGS(0);
656 xmlXPathPositionFunction(pctx
, 0);
657 pos
= xmlXPathPopNumber(pctx
);
658 xmlXPathLastFunction(pctx
, 0);
659 last
= xmlXPathPopNumber(pctx
);
660 xmlXPathReturnBoolean(pctx
, pos
== last
);
663 static void XSLPattern_nodeType(xmlXPathParserContextPtr pctx
, int nargs
)
665 XSLPATTERN_CHECK_ARGS(0);
666 xmlXPathReturnNumber(pctx
, pctx
->context
->node
->type
);
669 static void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx
, int nargs
)
671 xmlChar
*arg1
, *arg2
;
672 XSLPATTERN_CHECK_ARGS(2);
674 arg2
= xmlXPathPopString(pctx
);
675 arg1
= xmlXPathPopString(pctx
);
676 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) == 0);
681 static void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx
, int nargs
)
683 xmlChar
*arg1
, *arg2
;
684 XSLPATTERN_CHECK_ARGS(2);
686 arg2
= xmlXPathPopString(pctx
);
687 arg1
= xmlXPathPopString(pctx
);
688 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) != 0);
693 static void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx
, int nargs
)
695 xmlChar
*arg1
, *arg2
;
696 XSLPATTERN_CHECK_ARGS(2);
698 arg2
= xmlXPathPopString(pctx
);
699 arg1
= xmlXPathPopString(pctx
);
700 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) < 0);
705 static void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx
, int nargs
)
707 xmlChar
*arg1
, *arg2
;
708 XSLPATTERN_CHECK_ARGS(2);
710 arg2
= xmlXPathPopString(pctx
);
711 arg1
= xmlXPathPopString(pctx
);
712 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) <= 0);
717 static void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx
, int nargs
)
719 xmlChar
*arg1
, *arg2
;
720 XSLPATTERN_CHECK_ARGS(2);
722 arg2
= xmlXPathPopString(pctx
);
723 arg1
= xmlXPathPopString(pctx
);
724 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) > 0);
729 static void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx
, int nargs
)
731 xmlChar
*arg1
, *arg2
;
732 XSLPATTERN_CHECK_ARGS(2);
734 arg2
= xmlXPathPopString(pctx
);
735 arg1
= xmlXPathPopString(pctx
);
736 xmlXPathReturnBoolean(pctx
, xmlStrcasecmp(arg1
, arg2
) >= 0);
741 static void query_serror(void* ctx
, xmlErrorPtr err
)
743 LIBXML2_CALLBACK_SERROR(domselection_create
, err
);
746 HRESULT
create_selection(xmlNodePtr node
, xmlChar
* query
, IXMLDOMNodeList
**out
)
748 domselection
*This
= heap_alloc(sizeof(domselection
));
749 xmlXPathContextPtr ctxt
= xmlXPathNewContext(node
->doc
);
752 TRACE("(%p, %s, %p)\n", node
, debugstr_a((char const*)query
), out
);
755 if (!This
|| !ctxt
|| !query
)
757 xmlXPathFreeContext(ctxt
);
759 return E_OUTOFMEMORY
;
762 This
->IXMLDOMSelection_iface
.lpVtbl
= &domselection_vtbl
;
766 This
->enumvariant
= NULL
;
767 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IXMLDOMSelection_iface
, &domselection_dispex
);
768 xmldoc_add_ref(This
->node
->doc
);
770 ctxt
->error
= query_serror
;
772 registerNamespaces(ctxt
);
774 if (is_xpathmode(This
->node
->doc
))
776 xmlXPathRegisterAllFunctions(ctxt
);
777 This
->result
= xmlXPathEvalExpression(query
, ctxt
);
781 xmlChar
* pattern_query
= XSLPattern_to_XPath(ctxt
, query
);
783 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"not", xmlXPathNotFunction
);
784 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"boolean", xmlXPathBooleanFunction
);
786 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"index", XSLPattern_index
);
787 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"end", XSLPattern_end
);
788 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"nodeType", XSLPattern_nodeType
);
790 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IEq", XSLPattern_OP_IEq
);
791 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_INEq", XSLPattern_OP_INEq
);
792 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILt", XSLPattern_OP_ILt
);
793 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_ILEq", XSLPattern_OP_ILEq
);
794 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGt", XSLPattern_OP_IGt
);
795 xmlXPathRegisterFunc(ctxt
, (xmlChar
const*)"OP_IGEq", XSLPattern_OP_IGEq
);
797 This
->result
= xmlXPathEvalExpression(pattern_query
, ctxt
);
798 xmlFree(pattern_query
);
801 if (!This
->result
|| This
->result
->type
!= XPATH_NODESET
)
807 *out
= (IXMLDOMNodeList
*)&This
->IXMLDOMSelection_iface
;
809 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This
->result
->nodesetval
));
812 if (This
&& FAILED(hr
))
813 IXMLDOMSelection_Release( &This
->IXMLDOMSelection_iface
);
814 xmlXPathFreeContext(ctxt
);