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 _enumvariant
63 IEnumVARIANT IEnumVARIANT_iface;
66 IXMLDOMSelection *selection;
70 typedef struct _domselection
73 IXMLDOMSelection IXMLDOMSelection_iface;
76 xmlXPathObjectPtr result;
78 IEnumVARIANT *enumvariant;
81 static inline domselection *impl_from_IXMLDOMSelection( IXMLDOMSelection *iface )
83 return CONTAINING_RECORD(iface, domselection, IXMLDOMSelection_iface);
86 static inline enumvariant *impl_from_IEnumVARIANT( IEnumVARIANT *iface )
88 return CONTAINING_RECORD(iface, enumvariant, IEnumVARIANT_iface);
91 static HRESULT create_enumvariant(IXMLDOMSelection*, BOOL, IUnknown**);
93 static HRESULT WINAPI domselection_QueryInterface(
94 IXMLDOMSelection *iface,
98 domselection *This = impl_from_IXMLDOMSelection( iface );
100 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
105 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
106 IsEqualGUID( riid, &IID_IXMLDOMNodeList ) ||
107 IsEqualGUID( riid, &IID_IXMLDOMSelection ))
109 *ppvObject = &This->IXMLDOMSelection_iface;
111 else if (IsEqualGUID( riid, &IID_IEnumVARIANT ))
113 if (!This->enumvariant)
115 HRESULT hr = create_enumvariant(iface, FALSE, (IUnknown**)&This->enumvariant);
116 if (FAILED(hr)) return hr;
119 return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject);
121 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
123 return *ppvObject ? S_OK : E_NOINTERFACE;
127 TRACE("interface %s not implemented\n", debugstr_guid(riid));
129 return E_NOINTERFACE;
132 IXMLDOMSelection_AddRef( iface );
137 static ULONG WINAPI domselection_AddRef(
138 IXMLDOMSelection *iface )
140 domselection *This = impl_from_IXMLDOMSelection( iface );
141 ULONG ref = InterlockedIncrement( &This->ref );
142 TRACE("(%p)->(%d)\n", This, ref);
146 static ULONG WINAPI domselection_Release(
147 IXMLDOMSelection *iface )
149 domselection *This = impl_from_IXMLDOMSelection( iface );
150 ULONG ref = InterlockedDecrement(&This->ref);
152 TRACE("(%p)->(%d)\n", This, ref);
155 xmlXPathFreeObject(This->result);
156 xmldoc_release(This->node->doc);
157 if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant);
164 static HRESULT WINAPI domselection_GetTypeInfoCount(
165 IXMLDOMSelection *iface,
168 domselection *This = impl_from_IXMLDOMSelection( iface );
170 TRACE("(%p)->(%p)\n", This, pctinfo);
177 static HRESULT WINAPI domselection_GetTypeInfo(
178 IXMLDOMSelection *iface,
181 ITypeInfo** ppTInfo )
183 domselection *This = impl_from_IXMLDOMSelection( iface );
186 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
188 hr = get_typeinfo(IXMLDOMSelection_tid, ppTInfo);
193 static HRESULT WINAPI domselection_GetIDsOfNames(
194 IXMLDOMSelection *iface,
201 domselection *This = impl_from_IXMLDOMSelection( iface );
205 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
208 if(!rgszNames || cNames == 0 || !rgDispId)
211 hr = get_typeinfo(IXMLDOMSelection_tid, &typeinfo);
214 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
215 ITypeInfo_Release(typeinfo);
221 static HRESULT WINAPI domselection_Invoke(
222 IXMLDOMSelection *iface,
227 DISPPARAMS* pDispParams,
229 EXCEPINFO* pExcepInfo,
232 domselection *This = impl_from_IXMLDOMSelection( iface );
236 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
237 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
239 hr = get_typeinfo(IXMLDOMSelection_tid, &typeinfo);
242 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMSelection_iface, dispIdMember, wFlags, pDispParams,
243 pVarResult, pExcepInfo, puArgErr);
244 ITypeInfo_Release(typeinfo);
250 static HRESULT WINAPI domselection_get_item(
251 IXMLDOMSelection* iface,
253 IXMLDOMNode** listItem)
255 domselection *This = impl_from_IXMLDOMSelection( iface );
257 TRACE("(%p)->(%d %p)\n", This, index, listItem);
264 if (index < 0 || index >= xmlXPathNodeSetGetLength(This->result->nodesetval))
267 *listItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, index));
268 This->resultPos = index + 1;
273 static HRESULT WINAPI domselection_get_length(
274 IXMLDOMSelection* iface,
277 domselection *This = impl_from_IXMLDOMSelection( iface );
279 TRACE("(%p)->(%p)\n", This, listLength);
284 *listLength = xmlXPathNodeSetGetLength(This->result->nodesetval);
288 static HRESULT WINAPI domselection_nextNode(
289 IXMLDOMSelection* iface,
290 IXMLDOMNode** nextItem)
292 domselection *This = impl_from_IXMLDOMSelection( iface );
294 TRACE("(%p)->(%p)\n", This, nextItem );
301 if (This->resultPos >= xmlXPathNodeSetGetLength(This->result->nodesetval))
304 *nextItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, This->resultPos));
309 static HRESULT WINAPI domselection_reset(
310 IXMLDOMSelection* iface)
312 domselection *This = impl_from_IXMLDOMSelection( iface );
319 static HRESULT WINAPI domselection_get__newEnum(
320 IXMLDOMSelection* iface,
323 domselection *This = impl_from_IXMLDOMSelection( iface );
325 TRACE("(%p)->(%p)\n", This, ppUnk);
327 return create_enumvariant(iface, TRUE, ppUnk);
330 static HRESULT WINAPI domselection_get_expr(
331 IXMLDOMSelection* iface,
334 domselection *This = impl_from_IXMLDOMSelection( iface );
335 FIXME("(%p)->(%p)\n", This, p);
339 static HRESULT WINAPI domselection_put_expr(
340 IXMLDOMSelection* iface,
343 domselection *This = impl_from_IXMLDOMSelection( iface );
344 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
348 static HRESULT WINAPI domselection_get_context(
349 IXMLDOMSelection* iface,
352 domselection *This = impl_from_IXMLDOMSelection( iface );
353 FIXME("(%p)->(%p)\n", This, node);
357 static HRESULT WINAPI domselection_putref_context(
358 IXMLDOMSelection* iface,
361 domselection *This = impl_from_IXMLDOMSelection( iface );
362 FIXME("(%p)->(%p)\n", This, node);
366 static HRESULT WINAPI domselection_peekNode(
367 IXMLDOMSelection* iface,
370 domselection *This = impl_from_IXMLDOMSelection( iface );
371 FIXME("(%p)->(%p)\n", This, node);
375 static HRESULT WINAPI domselection_matches(
376 IXMLDOMSelection* iface,
378 IXMLDOMNode **out_node)
380 domselection *This = impl_from_IXMLDOMSelection( iface );
381 FIXME("(%p)->(%p %p)\n", This, node, out_node);
385 static HRESULT WINAPI domselection_removeNext(
386 IXMLDOMSelection* iface,
389 domselection *This = impl_from_IXMLDOMSelection( iface );
390 FIXME("(%p)->(%p)\n", This, node);
394 static HRESULT WINAPI domselection_removeAll(
395 IXMLDOMSelection* iface)
397 domselection *This = impl_from_IXMLDOMSelection( iface );
398 FIXME("(%p)\n", This);
402 static HRESULT WINAPI domselection_clone(
403 IXMLDOMSelection* iface,
404 IXMLDOMSelection **node)
406 domselection *This = impl_from_IXMLDOMSelection( iface );
407 FIXME("(%p)->(%p)\n", This, node);
411 static HRESULT WINAPI domselection_getProperty(
412 IXMLDOMSelection* iface,
416 domselection *This = impl_from_IXMLDOMSelection( iface );
417 FIXME("(%p)->(%s %p)\n", This, debugstr_w(p), var);
421 static HRESULT WINAPI domselection_setProperty(
422 IXMLDOMSelection* iface,
426 domselection *This = impl_from_IXMLDOMSelection( iface );
427 FIXME("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&var));
431 static const struct IXMLDOMSelectionVtbl domselection_vtbl =
433 domselection_QueryInterface,
435 domselection_Release,
436 domselection_GetTypeInfoCount,
437 domselection_GetTypeInfo,
438 domselection_GetIDsOfNames,
440 domselection_get_item,
441 domselection_get_length,
442 domselection_nextNode,
444 domselection_get__newEnum,
445 domselection_get_expr,
446 domselection_put_expr,
447 domselection_get_context,
448 domselection_putref_context,
449 domselection_peekNode,
450 domselection_matches,
451 domselection_removeNext,
452 domselection_removeAll,
454 domselection_getProperty,
455 domselection_setProperty
458 /* IEnumVARIANT support */
459 static HRESULT WINAPI enumvariant_QueryInterface(
464 enumvariant *This = impl_from_IEnumVARIANT( iface );
466 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
470 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
471 IsEqualGUID( riid, &IID_IEnumVARIANT ))
473 *ppvObject = &This->IEnumVARIANT_iface;
476 return IXMLDOMSelection_QueryInterface(This->selection, riid, ppvObject);
478 IEnumVARIANT_AddRef( iface );
483 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface )
485 enumvariant *This = impl_from_IEnumVARIANT( iface );
486 ULONG ref = InterlockedIncrement( &This->ref );
487 TRACE("(%p)->(%d)\n", This, ref);
491 static ULONG WINAPI enumvariant_Release(IEnumVARIANT *iface )
493 enumvariant *This = impl_from_IEnumVARIANT( iface );
494 ULONG ref = InterlockedDecrement(&This->ref);
496 TRACE("(%p)->(%d)\n", This, ref);
499 if (This->own) IXMLDOMSelection_Release(This->selection);
506 static HRESULT WINAPI enumvariant_Next(
512 enumvariant *This = impl_from_IEnumVARIANT( iface );
513 FIXME("(%p)->(%u %p %p): stub\n", This, celt, rgvar, pceltFetched);
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 static HRESULT create_enumvariant(IXMLDOMSelection *selection, BOOL own, IUnknown **penum)
556 This = heap_alloc(sizeof(enumvariant));
557 if (!This) return E_OUTOFMEMORY;
559 This->IEnumVARIANT_iface.lpVtbl = &EnumVARIANTVtbl;
561 This->selection = selection;
565 IXMLDOMSelection_AddRef(selection);
567 return IEnumVARIANT_QueryInterface(&This->IEnumVARIANT_iface, &IID_IUnknown, (void**)penum);
570 static HRESULT domselection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
572 domselection *This = impl_from_IXMLDOMSelection( (IXMLDOMSelection*)iface );
576 for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
577 idx = idx*10 + (*ptr-'0');
579 return DISP_E_UNKNOWNNAME;
581 if(idx >= xmlXPathNodeSetGetLength(This->result->nodesetval))
582 return DISP_E_UNKNOWNNAME;
584 *dispid = MSXML_DISPID_CUSTOM_MIN + 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;
601 case INVOKE_PROPERTYGET:
603 IXMLDOMNode *disp = NULL;
605 domselection_get_item(&This->IXMLDOMSelection_iface, id - MSXML_DISPID_CUSTOM_MIN, &disp);
606 V_DISPATCH(res) = (IDispatch*)disp;
611 FIXME("unimplemented flags %x\n", flags);
616 TRACE("ret %p\n", V_DISPATCH(res));
621 static const dispex_static_data_vtbl_t domselection_dispex_vtbl = {
622 domselection_get_dispid,
626 static const tid_t domselection_iface_tids[] = {
627 IXMLDOMSelection_tid,
630 static dispex_static_data_t domselection_dispex = {
631 &domselection_dispex_vtbl,
632 IXMLDOMSelection_tid,
634 domselection_iface_tids
637 #define XSLPATTERN_CHECK_ARGS(n) \
639 FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
640 xmlXPathSetArityError(pctx); \
645 static void XSLPattern_index(xmlXPathParserContextPtr pctx, int nargs)
647 XSLPATTERN_CHECK_ARGS(0);
649 xmlXPathPositionFunction(pctx, 0);
650 xmlXPathReturnNumber(pctx, xmlXPathPopNumber(pctx) - 1.0);
653 static void XSLPattern_end(xmlXPathParserContextPtr pctx, int nargs)
656 XSLPATTERN_CHECK_ARGS(0);
658 xmlXPathPositionFunction(pctx, 0);
659 pos = xmlXPathPopNumber(pctx);
660 xmlXPathLastFunction(pctx, 0);
661 last = xmlXPathPopNumber(pctx);
662 xmlXPathReturnBoolean(pctx, pos == last);
665 static void XSLPattern_nodeType(xmlXPathParserContextPtr pctx, int nargs)
667 XSLPATTERN_CHECK_ARGS(0);
668 xmlXPathReturnNumber(pctx, pctx->context->node->type);
671 static void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx, int nargs)
673 xmlChar *arg1, *arg2;
674 XSLPATTERN_CHECK_ARGS(2);
676 arg2 = xmlXPathPopString(pctx);
677 arg1 = xmlXPathPopString(pctx);
678 xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) == 0);
683 static void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx, int nargs)
685 xmlChar *arg1, *arg2;
686 XSLPATTERN_CHECK_ARGS(2);
688 arg2 = xmlXPathPopString(pctx);
689 arg1 = xmlXPathPopString(pctx);
690 xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) != 0);
695 static void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx, int nargs)
697 xmlChar *arg1, *arg2;
698 XSLPATTERN_CHECK_ARGS(2);
700 arg2 = xmlXPathPopString(pctx);
701 arg1 = xmlXPathPopString(pctx);
702 xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) < 0);
707 static void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx, int nargs)
709 xmlChar *arg1, *arg2;
710 XSLPATTERN_CHECK_ARGS(2);
712 arg2 = xmlXPathPopString(pctx);
713 arg1 = xmlXPathPopString(pctx);
714 xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) <= 0);
719 static void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx, int nargs)
721 xmlChar *arg1, *arg2;
722 XSLPATTERN_CHECK_ARGS(2);
724 arg2 = xmlXPathPopString(pctx);
725 arg1 = xmlXPathPopString(pctx);
726 xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) > 0);
731 static void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx, int nargs)
733 xmlChar *arg1, *arg2;
734 XSLPATTERN_CHECK_ARGS(2);
736 arg2 = xmlXPathPopString(pctx);
737 arg1 = xmlXPathPopString(pctx);
738 xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) >= 0);
743 static void query_serror(void* ctx, xmlErrorPtr err)
745 LIBXML2_CALLBACK_SERROR(domselection_create, err);
748 HRESULT create_selection(xmlNodePtr node, xmlChar* query, IXMLDOMNodeList **out)
750 domselection *This = heap_alloc(sizeof(domselection));
751 xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
754 TRACE("(%p, %s, %p)\n", node, wine_dbgstr_a((char const*)query), out);
757 if (!This || !ctxt || !query)
763 This->IXMLDOMSelection_iface.lpVtbl = &domselection_vtbl;
767 This->enumvariant = NULL;
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 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSelection_iface, &domselection_dispex);
809 *out = (IXMLDOMNodeList*)&This->IXMLDOMSelection_iface;
811 TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This->result->nodesetval));
814 if (This && FAILED(hr))
815 IXMLDOMSelection_Release( &This->IXMLDOMSelection_iface );
816 xmlXPathFreeContext(ctxt);