xref: /reactos/dll/win32/msxml3/xmlelem.c (revision 84ccccab)
1 /*
2  * XML Element implementation
3  *
4  * Copyright 2007 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "precomp.h"
22 
23 #ifdef HAVE_LIBXML2
24 
25 static HRESULT XMLElementCollection_create( xmlNodePtr node, LPVOID *ppObj );
26 
27 /**********************************************************************
28  * IXMLElement
29  */
30 typedef struct _xmlelem
31 {
32     IXMLElement IXMLElement_iface;
33     LONG ref;
34     xmlNodePtr node;
35     BOOL own;
36 } xmlelem;
37 
38 static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
39 {
40     return CONTAINING_RECORD(iface, xmlelem, IXMLElement_iface);
41 }
42 
43 static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
44 {
45     xmlelem *This = impl_from_IXMLElement(iface);
46 
47     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
48 
49     if (IsEqualGUID(riid, &IID_IUnknown)  ||
50         IsEqualGUID(riid, &IID_IDispatch) ||
51         IsEqualGUID(riid, &IID_IXMLElement))
52     {
53         *ppvObject = iface;
54     }
55     else
56     {
57         FIXME("interface %s not implemented\n", debugstr_guid(riid));
58         *ppvObject = NULL;
59         return E_NOINTERFACE;
60     }
61 
62     IXMLElement_AddRef(iface);
63 
64     return S_OK;
65 }
66 
67 static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
68 {
69     xmlelem *This = impl_from_IXMLElement(iface);
70     TRACE("%p\n", This);
71     return InterlockedIncrement(&This->ref);
72 }
73 
74 static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
75 {
76     xmlelem *This = impl_from_IXMLElement(iface);
77     LONG ref;
78 
79     TRACE("%p\n", This);
80 
81     ref = InterlockedDecrement(&This->ref);
82     if (ref == 0)
83     {
84         if (This->own) xmlFreeNode(This->node);
85         heap_free(This);
86     }
87 
88     return ref;
89 }
90 
91 static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
92 {
93     xmlelem *This = impl_from_IXMLElement(iface);
94 
95     TRACE("(%p)->(%p)\n", This, pctinfo);
96 
97     *pctinfo = 1;
98 
99     return S_OK;
100 }
101 
102 static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
103                                           LCID lcid, ITypeInfo** ppTInfo)
104 {
105     xmlelem *This = impl_from_IXMLElement(iface);
106     HRESULT hr;
107 
108     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
109 
110     hr = get_typeinfo(IXMLElement_tid, ppTInfo);
111 
112     return hr;
113 }
114 
115 static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
116                                             LPOLESTR* rgszNames, UINT cNames,
117                                             LCID lcid, DISPID* rgDispId)
118 {
119     xmlelem *This = impl_from_IXMLElement(iface);
120     ITypeInfo *typeinfo;
121     HRESULT hr;
122 
123     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
124           lcid, rgDispId);
125 
126     if(!rgszNames || cNames == 0 || !rgDispId)
127         return E_INVALIDARG;
128 
129     hr = get_typeinfo(IXMLElement_tid, &typeinfo);
130     if(SUCCEEDED(hr))
131     {
132         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
133         ITypeInfo_Release(typeinfo);
134     }
135 
136     return hr;
137 }
138 
139 static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
140                                      REFIID riid, LCID lcid, WORD wFlags,
141                                      DISPPARAMS* pDispParams, VARIANT* pVarResult,
142                                      EXCEPINFO* pExcepInfo, UINT* puArgErr)
143 {
144     xmlelem *This = impl_from_IXMLElement(iface);
145     ITypeInfo *typeinfo;
146     HRESULT hr;
147 
148     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
149           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
150 
151     hr = get_typeinfo(IXMLElement_tid, &typeinfo);
152     if(SUCCEEDED(hr))
153     {
154         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLElement_iface, dispIdMember, wFlags, pDispParams,
155                 pVarResult, pExcepInfo, puArgErr);
156         ITypeInfo_Release(typeinfo);
157     }
158 
159     return hr;
160 }
161 
162 static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
163 {
164     xmlelem *This = impl_from_IXMLElement(iface);
165 
166     TRACE("(%p)->(%p)\n", This, p);
167 
168     if (!p)
169         return E_INVALIDARG;
170 
171     if (*This->node->name) {
172         *p = bstr_from_xmlChar(This->node->name);
173         CharUpperBuffW(*p, SysStringLen(*p));
174     }else {
175         *p = NULL;
176     }
177 
178     TRACE("returning %s\n", debugstr_w(*p));
179 
180     return S_OK;
181 }
182 
183 static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
184 {
185     xmlelem *This = impl_from_IXMLElement(iface);
186 
187     FIXME("(%p)->(%s): stub\n", This, debugstr_w(p));
188 
189     if (!p)
190         return E_INVALIDARG;
191 
192     return E_NOTIMPL;
193 }
194 
195 static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
196 {
197     xmlelem *This = impl_from_IXMLElement(iface);
198 
199     TRACE("(%p)->(%p)\n", This, parent);
200 
201     if (!parent)
202         return E_INVALIDARG;
203 
204     *parent = NULL;
205 
206     if (!This->node->parent)
207         return S_FALSE;
208 
209     return XMLElement_create(This->node->parent, (LPVOID *)parent, FALSE);
210 }
211 
212 static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
213                                             VARIANT PropertyValue)
214 {
215     xmlelem *This = impl_from_IXMLElement(iface);
216     xmlChar *name, *value;
217     xmlAttrPtr attr;
218 
219     TRACE("(%p)->(%s %s)\n", This, debugstr_w(strPropertyName), debugstr_variant(&PropertyValue));
220 
221     if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
222         return E_INVALIDARG;
223 
224     name = xmlchar_from_wchar(strPropertyName);
225     value = xmlchar_from_wchar(V_BSTR(&PropertyValue));
226     attr = xmlSetProp(This->node, name, value);
227 
228     heap_free(name);
229     heap_free(value);
230     return (attr) ? S_OK : S_FALSE;
231 }
232 
233 static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR name,
234     VARIANT *value)
235 {
236     static const WCHAR xmllangW[] = { 'x','m','l',':','l','a','n','g',0 };
237     xmlelem *This = impl_from_IXMLElement(iface);
238     xmlChar *val = NULL;
239 
240     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(name), value);
241 
242     if (!value)
243         return E_INVALIDARG;
244 
245     VariantInit(value);
246     V_BSTR(value) = NULL;
247 
248     if (!name)
249         return E_INVALIDARG;
250 
251     /* case for xml:lang attribute */
252     if (!lstrcmpiW(name, xmllangW))
253     {
254         xmlNsPtr ns;
255         ns = xmlSearchNs(This->node->doc, This->node, (xmlChar*)"xml");
256         val = xmlGetNsProp(This->node, (xmlChar*)"lang", ns->href);
257     }
258     else
259     {
260         xmlAttrPtr attr;
261         xmlChar *xml_name;
262 
263         xml_name = xmlchar_from_wchar(name);
264         attr = This->node->properties;
265         while (attr)
266         {
267             BSTR attr_name;
268 
269             attr_name = bstr_from_xmlChar(attr->name);
270             if (!lstrcmpiW(name, attr_name))
271             {
272                 val = xmlNodeListGetString(attr->doc, attr->children, 1);
273                 SysFreeString(attr_name);
274                 break;
275             }
276 
277             attr = attr->next;
278             SysFreeString(attr_name);
279         }
280 
281         heap_free(xml_name);
282     }
283 
284     if (val)
285     {
286         V_VT(value) = VT_BSTR;
287         V_BSTR(value) = bstr_from_xmlChar(val);
288     }
289 
290     xmlFree(val);
291     TRACE("returning %s\n", debugstr_w(V_BSTR(value)));
292     return (val) ? S_OK : S_FALSE;
293 }
294 
295 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
296 {
297     xmlelem *This = impl_from_IXMLElement(iface);
298     xmlChar *name;
299     xmlAttrPtr attr;
300     int res;
301     HRESULT hr = S_FALSE;
302 
303     TRACE("(%p)->(%s)\n", This, debugstr_w(strPropertyName));
304 
305     if (!strPropertyName)
306         return E_INVALIDARG;
307 
308     name = xmlchar_from_wchar(strPropertyName);
309     attr = xmlHasProp(This->node, name);
310     if (!attr)
311         goto done;
312 
313     res = xmlRemoveProp(attr);
314 
315     if (res == 0)
316         hr = S_OK;
317 
318 done:
319     heap_free(name);
320     return hr;
321 }
322 
323 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
324 {
325     xmlelem *This = impl_from_IXMLElement(iface);
326 
327     TRACE("(%p)->(%p)\n", This, p);
328 
329     if (!p)
330         return E_INVALIDARG;
331 
332     return XMLElementCollection_create(This->node, (LPVOID *)p);
333 }
334 
335 static LONG type_libxml_to_msxml(xmlElementType type)
336 {
337     switch (type)
338     {
339         case XML_ELEMENT_NODE:
340             return XMLELEMTYPE_ELEMENT;
341         case XML_TEXT_NODE:
342             return XMLELEMTYPE_TEXT;
343         case XML_COMMENT_NODE:
344             return XMLELEMTYPE_COMMENT;
345         case XML_DOCUMENT_NODE:
346             return XMLELEMTYPE_DOCUMENT;
347         case XML_DTD_NODE:
348             return XMLELEMTYPE_DTD;
349         case XML_PI_NODE:
350             return XMLELEMTYPE_PI;
351         default:
352             break;
353     }
354 
355     return XMLELEMTYPE_OTHER;
356 }
357 
358 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, LONG *p)
359 {
360     xmlelem *This = impl_from_IXMLElement(iface);
361 
362     TRACE("(%p)->(%p)\n", This, p);
363 
364     if (!p)
365         return E_INVALIDARG;
366 
367     *p = type_libxml_to_msxml(This->node->type);
368     TRACE("returning %d\n", *p);
369     return S_OK;
370 }
371 
372 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
373 {
374     xmlelem *This = impl_from_IXMLElement(iface);
375     xmlChar *content;
376 
377     TRACE("(%p)->(%p)\n", This, p);
378 
379     if (!p)
380         return E_INVALIDARG;
381 
382     content = xmlNodeGetContent(This->node);
383     *p = bstr_from_xmlChar(content);
384     TRACE("returning %s\n", debugstr_w(*p));
385 
386     xmlFree(content);
387     return S_OK;
388 }
389 
390 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
391 {
392     xmlelem *This = impl_from_IXMLElement(iface);
393     xmlChar *content;
394 
395     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
396 
397     /* FIXME: test which types can be used */
398     if (This->node->type == XML_ELEMENT_NODE)
399         return E_NOTIMPL;
400 
401     content = xmlchar_from_wchar(p);
402     xmlNodeSetContent(This->node, content);
403 
404     heap_free(content);
405 
406     return S_OK;
407 }
408 
409 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
410                                        LONG lIndex, LONG lreserved)
411 {
412     xmlelem *This = impl_from_IXMLElement(iface);
413     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
414     xmlNodePtr child;
415 
416     TRACE("(%p)->(%p %d %d)\n", This, pChildElem, lIndex, lreserved);
417 
418     if (lIndex == 0)
419         child = xmlAddChild(This->node, childElem->node);
420     else
421         child = xmlAddNextSibling(This->node, childElem->node->last);
422 
423     /* parent is responsible for child data */
424     if (child) childElem->own = FALSE;
425 
426     return (child) ? S_OK : S_FALSE;
427 }
428 
429 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
430 {
431     xmlelem *This = impl_from_IXMLElement(iface);
432     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
433 
434     TRACE("(%p)->(%p)\n", This, childElem);
435 
436     if (!pChildElem)
437         return E_INVALIDARG;
438 
439     /* only supported for This is childElem parent case */
440     if (This->node != childElem->node->parent)
441         return E_INVALIDARG;
442 
443     xmlUnlinkNode(childElem->node);
444     /* standalone element now */
445     childElem->own = TRUE;
446 
447     return S_OK;
448 }
449 
450 static const struct IXMLElementVtbl xmlelem_vtbl =
451 {
452     xmlelem_QueryInterface,
453     xmlelem_AddRef,
454     xmlelem_Release,
455     xmlelem_GetTypeInfoCount,
456     xmlelem_GetTypeInfo,
457     xmlelem_GetIDsOfNames,
458     xmlelem_Invoke,
459     xmlelem_get_tagName,
460     xmlelem_put_tagName,
461     xmlelem_get_parent,
462     xmlelem_setAttribute,
463     xmlelem_getAttribute,
464     xmlelem_removeAttribute,
465     xmlelem_get_children,
466     xmlelem_get_type,
467     xmlelem_get_text,
468     xmlelem_put_text,
469     xmlelem_addChild,
470     xmlelem_removeChild
471 };
472 
473 HRESULT XMLElement_create(xmlNodePtr node, LPVOID *ppObj, BOOL own)
474 {
475     xmlelem *elem;
476 
477     TRACE("(%p)\n", ppObj);
478 
479     if (!ppObj)
480         return E_INVALIDARG;
481 
482     *ppObj = NULL;
483 
484     elem = heap_alloc(sizeof (*elem));
485     if(!elem)
486         return E_OUTOFMEMORY;
487 
488     elem->IXMLElement_iface.lpVtbl = &xmlelem_vtbl;
489     elem->ref = 1;
490     elem->node = node;
491     elem->own  = own;
492 
493     *ppObj = &elem->IXMLElement_iface;
494 
495     TRACE("returning iface %p\n", *ppObj);
496     return S_OK;
497 }
498 
499 /************************************************************************
500  * IXMLElementCollection
501  */
502 typedef struct _xmlelem_collection
503 {
504     IXMLElementCollection IXMLElementCollection_iface;
505     IEnumVARIANT IEnumVARIANT_iface;
506     LONG ref;
507     LONG length;
508     xmlNodePtr node;
509 
510     /* IEnumVARIANT members */
511     xmlNodePtr current;
512 } xmlelem_collection;
513 
514 static inline LONG xmlelem_collection_updatelength(xmlelem_collection *collection)
515 {
516     xmlNodePtr ptr = collection->node->children;
517 
518     collection->length = 0;
519     while (ptr)
520     {
521         collection->length++;
522         ptr = ptr->next;
523     }
524     return collection->length;
525 }
526 
527 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
528 {
529     return CONTAINING_RECORD(iface, xmlelem_collection, IXMLElementCollection_iface);
530 }
531 
532 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
533 {
534     return CONTAINING_RECORD(iface, xmlelem_collection, IEnumVARIANT_iface);
535 }
536 
537 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
538 {
539     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
540 
541     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
542 
543     if (IsEqualGUID(riid, &IID_IUnknown) ||
544         IsEqualGUID(riid, &IID_IXMLElementCollection))
545     {
546         *ppvObject = iface;
547     }
548     else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
549     {
550         *ppvObject = &This->IEnumVARIANT_iface;
551     }
552     else
553     {
554         FIXME("interface %s not implemented\n", debugstr_guid(riid));
555         *ppvObject = NULL;
556         return E_NOINTERFACE;
557     }
558 
559     IXMLElementCollection_AddRef(iface);
560 
561     return S_OK;
562 }
563 
564 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
565 {
566     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
567     TRACE("(%p)\n", This);
568     return InterlockedIncrement(&This->ref);
569 }
570 
571 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
572 {
573     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
574     LONG ref;
575 
576     TRACE("(%p)\n", This);
577 
578     ref = InterlockedDecrement(&This->ref);
579     if (ref == 0)
580     {
581         heap_free(This);
582     }
583 
584     return ref;
585 }
586 
587 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
588 {
589     FIXME("\n");
590     return E_NOTIMPL;
591 }
592 
593 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
594                                                      LCID lcid, ITypeInfo** ppTInfo)
595 {
596     FIXME("\n");
597     return E_NOTIMPL;
598 }
599 
600 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
601                                                        LPOLESTR* rgszNames, UINT cNames,
602                                                        LCID lcid, DISPID* rgDispId)
603 {
604     FIXME("\n");
605     return E_NOTIMPL;
606 }
607 
608 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
609                                                 REFIID riid, LCID lcid, WORD wFlags,
610                                                 DISPPARAMS* pDispParams, VARIANT* pVarResult,
611                                                 EXCEPINFO* pExcepInfo, UINT* puArgErr)
612 {
613     FIXME("\n");
614     return E_NOTIMPL;
615 }
616 
617 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, LONG v)
618 {
619     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
620     TRACE("(%p)->(%d)\n", This, v);
621     return E_FAIL;
622 }
623 
624 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, LONG *p)
625 {
626     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
627 
628     TRACE("(%p)->(%p)\n", This, p);
629 
630     if (!p)
631         return E_INVALIDARG;
632 
633     *p = xmlelem_collection_updatelength(This);
634     return S_OK;
635 }
636 
637 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
638 {
639     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
640 
641     TRACE("(%p)->(%p)\n", This, ppUnk);
642 
643     if (!ppUnk)
644         return E_INVALIDARG;
645 
646     IXMLElementCollection_AddRef(iface);
647     *ppUnk = (IUnknown *)&This->IEnumVARIANT_iface;
648     return S_OK;
649 }
650 
651 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
652                                               VARIANT var2, IDispatch **ppDisp)
653 {
654     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
655     xmlNodePtr ptr = This->node->children;
656     int index, i;
657 
658     TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&var1), debugstr_variant(&var2), ppDisp);
659 
660     if (!ppDisp)
661         return E_INVALIDARG;
662 
663     *ppDisp = NULL;
664 
665     index = V_I4(&var1);
666     if (index < 0)
667         return E_INVALIDARG;
668 
669     xmlelem_collection_updatelength(This);
670     if (index >= This->length)
671         return E_FAIL;
672 
673     for (i = 0; i < index; i++)
674         ptr = ptr->next;
675 
676     return XMLElement_create(ptr, (LPVOID *)ppDisp, FALSE);
677 }
678 
679 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
680 {
681     xmlelem_collection_QueryInterface,
682     xmlelem_collection_AddRef,
683     xmlelem_collection_Release,
684     xmlelem_collection_GetTypeInfoCount,
685     xmlelem_collection_GetTypeInfo,
686     xmlelem_collection_GetIDsOfNames,
687     xmlelem_collection_Invoke,
688     xmlelem_collection_put_length,
689     xmlelem_collection_get_length,
690     xmlelem_collection_get__newEnum,
691     xmlelem_collection_item
692 };
693 
694 /************************************************************************
695  * xmlelem_collection implementation of IEnumVARIANT.
696  */
697 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
698     IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
699 {
700     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
701 
702     TRACE("(%p)->(%s %p)\n", this, debugstr_guid(riid), ppvObj);
703 
704     if (IsEqualGUID(riid, &IID_IUnknown) ||
705         IsEqualGUID(riid, &IID_IEnumVARIANT))
706     {
707         *ppvObj = iface;
708         IEnumVARIANT_AddRef(iface);
709         return S_OK;
710     }
711 
712     FIXME("interface %s not implemented\n", debugstr_guid(riid));
713     *ppvObj = NULL;
714     return E_NOINTERFACE;
715 }
716 
717 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
718     IEnumVARIANT *iface)
719 {
720     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
721     return IXMLElementCollection_AddRef(&this->IXMLElementCollection_iface);
722 }
723 
724 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
725     IEnumVARIANT *iface)
726 {
727     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
728     return IXMLElementCollection_Release(&this->IXMLElementCollection_iface);
729 }
730 
731 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
732     IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *fetched)
733 {
734     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
735     xmlNodePtr ptr = This->current;
736 
737     TRACE("(%p)->(%d %p %p)\n", This, celt, rgVar, fetched);
738 
739     if (!rgVar)
740         return E_INVALIDARG;
741 
742     /* FIXME: handle celt */
743     if (fetched)
744         *fetched = 1;
745 
746     if (This->current)
747         This->current = This->current->next;
748     else
749     {
750         V_VT(rgVar) = VT_EMPTY;
751         if (fetched) *fetched = 0;
752         return S_FALSE;
753     }
754 
755     V_VT(rgVar) = VT_DISPATCH;
756     return XMLElement_create(ptr, (LPVOID *)&V_DISPATCH(rgVar), FALSE);
757 }
758 
759 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
760     IEnumVARIANT *iface, ULONG celt)
761 {
762     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
763     FIXME("(%p)->(%d): stub\n", This, celt);
764     return E_NOTIMPL;
765 }
766 
767 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
768     IEnumVARIANT *iface)
769 {
770     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
771     TRACE("(%p)\n", This);
772     This->current = This->node->children;
773     return S_OK;
774 }
775 
776 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
777     IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
778 {
779     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
780     FIXME("(%p)->(%p): stub\n", This, ppEnum);
781     return E_NOTIMPL;
782 }
783 
784 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
785 {
786     xmlelem_collection_IEnumVARIANT_QueryInterface,
787     xmlelem_collection_IEnumVARIANT_AddRef,
788     xmlelem_collection_IEnumVARIANT_Release,
789     xmlelem_collection_IEnumVARIANT_Next,
790     xmlelem_collection_IEnumVARIANT_Skip,
791     xmlelem_collection_IEnumVARIANT_Reset,
792     xmlelem_collection_IEnumVARIANT_Clone
793 };
794 
795 static HRESULT XMLElementCollection_create(xmlNodePtr node, LPVOID *ppObj)
796 {
797     xmlelem_collection *collection;
798 
799     TRACE("(%p)\n", ppObj);
800 
801     *ppObj = NULL;
802 
803     if (!node->children)
804         return S_FALSE;
805 
806     collection = heap_alloc(sizeof (*collection));
807     if(!collection)
808         return E_OUTOFMEMORY;
809 
810     collection->IXMLElementCollection_iface.lpVtbl = &xmlelem_collection_vtbl;
811     collection->IEnumVARIANT_iface.lpVtbl = &xmlelem_collection_IEnumVARIANTvtbl;
812     collection->ref = 1;
813     collection->length = 0;
814     collection->node = node;
815     collection->current = node->children;
816     xmlelem_collection_updatelength(collection);
817 
818     *ppObj = &collection->IXMLElementCollection_iface;
819 
820     TRACE("returning iface %p\n", *ppObj);
821     return S_OK;
822 }
823 
824 #endif
825