msxml3: Fix domdoc_getElementsByTagName()/domelem_getElementsByTagName().
[wine] / dlls / msxml3 / element.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
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 #define COBJMACROS
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
31 #include "msxml6.h"
32
33 #include "msxml_private.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
38
39 #ifdef HAVE_LIBXML2
40
41 static const xmlChar DT_prefix[] = "dt";
42 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
43
44 typedef struct _domelem
45 {
46     xmlnode node;
47     const struct IXMLDOMElementVtbl *lpVtbl;
48     LONG ref;
49 } domelem;
50
51 static inline domelem *impl_from_IXMLDOMElement( IXMLDOMElement *iface )
52 {
53     return (domelem *)((char*)iface - FIELD_OFFSET(domelem, lpVtbl));
54 }
55
56 static inline xmlNodePtr get_element( const domelem *This )
57 {
58     return This->node.node;
59 }
60
61 static HRESULT WINAPI domelem_QueryInterface(
62     IXMLDOMElement *iface,
63     REFIID riid,
64     void** ppvObject )
65 {
66     domelem *This = impl_from_IXMLDOMElement( iface );
67
68     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
69
70     if ( IsEqualGUID( riid, &IID_IXMLDOMElement ) ||
71          IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
72          IsEqualGUID( riid, &IID_IDispatch ) ||
73          IsEqualGUID( riid, &IID_IUnknown ) )
74     {
75         *ppvObject = &This->lpVtbl;
76     }
77     else if(node_query_interface(&This->node, riid, ppvObject))
78     {
79         return *ppvObject ? S_OK : E_NOINTERFACE;
80     }
81     else
82     {
83         FIXME("interface %s not implemented\n", debugstr_guid(riid));
84         return E_NOINTERFACE;
85     }
86
87     IUnknown_AddRef( (IUnknown*)*ppvObject );
88     return S_OK;
89 }
90
91 static ULONG WINAPI domelem_AddRef(
92     IXMLDOMElement *iface )
93 {
94     domelem *This = impl_from_IXMLDOMElement( iface );
95     LONG ref = InterlockedIncrement(&This->ref);
96
97     TRACE("(%p) ref=%d\n", This, ref);
98
99     return ref;
100 }
101
102 static ULONG WINAPI domelem_Release(
103     IXMLDOMElement *iface )
104 {
105     domelem *This = impl_from_IXMLDOMElement( iface );
106     ULONG ref = InterlockedDecrement(&This->ref);
107
108     TRACE("(%p) ref=%d\n", This, ref);
109
110     if(!ref) {
111         destroy_xmlnode(&This->node);
112         heap_free(This);
113     }
114
115     return ref;
116 }
117
118 static HRESULT WINAPI domelem_GetTypeInfoCount(
119     IXMLDOMElement *iface,
120     UINT* pctinfo )
121 {
122     domelem *This = impl_from_IXMLDOMElement( iface );
123
124     TRACE("(%p)->(%p)\n", This, pctinfo);
125
126     *pctinfo = 1;
127
128     return S_OK;
129 }
130
131 static HRESULT WINAPI domelem_GetTypeInfo(
132     IXMLDOMElement *iface,
133     UINT iTInfo, LCID lcid,
134     ITypeInfo** ppTInfo )
135 {
136     domelem *This = impl_from_IXMLDOMElement( iface );
137     HRESULT hr;
138
139     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
140
141     hr = get_typeinfo(IXMLDOMElement_tid, ppTInfo);
142
143     return hr;
144 }
145
146 static HRESULT WINAPI domelem_GetIDsOfNames(
147     IXMLDOMElement *iface,
148     REFIID riid, LPOLESTR* rgszNames,
149     UINT cNames, LCID lcid, DISPID* rgDispId )
150 {
151     domelem *This = impl_from_IXMLDOMElement( iface );
152     ITypeInfo *typeinfo;
153     HRESULT hr;
154
155     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
156           lcid, rgDispId);
157
158     if(!rgszNames || cNames == 0 || !rgDispId)
159         return E_INVALIDARG;
160
161     hr = get_typeinfo(IXMLDOMElement_tid, &typeinfo);
162     if(SUCCEEDED(hr))
163     {
164         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
165         ITypeInfo_Release(typeinfo);
166     }
167
168     return hr;
169 }
170
171 static HRESULT WINAPI domelem_Invoke(
172     IXMLDOMElement *iface,
173     DISPID dispIdMember, REFIID riid, LCID lcid,
174     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
175     EXCEPINFO* pExcepInfo, UINT* puArgErr )
176 {
177     domelem *This = impl_from_IXMLDOMElement( iface );
178     ITypeInfo *typeinfo;
179     HRESULT hr;
180
181     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
182           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
183
184     hr = get_typeinfo(IXMLDOMElement_tid, &typeinfo);
185     if(SUCCEEDED(hr))
186     {
187         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
188                 pVarResult, pExcepInfo, puArgErr);
189         ITypeInfo_Release(typeinfo);
190     }
191
192     return hr;
193 }
194
195 static HRESULT WINAPI domelem_get_nodeName(
196     IXMLDOMElement *iface,
197     BSTR* p )
198 {
199     domelem *This = impl_from_IXMLDOMElement( iface );
200
201     TRACE("(%p)->(%p)\n", This, p);
202
203     return node_get_nodeName(&This->node, p);
204 }
205
206 static HRESULT WINAPI domelem_get_nodeValue(
207     IXMLDOMElement *iface,
208     VARIANT* value)
209 {
210     domelem *This = impl_from_IXMLDOMElement( iface );
211
212     TRACE("(%p)->(%p)\n", This, value);
213
214     if(!value)
215         return E_INVALIDARG;
216
217     V_VT(value) = VT_NULL;
218     V_BSTR(value) = NULL; /* tests show that we should do this */
219     return S_FALSE;
220 }
221
222 static HRESULT WINAPI domelem_put_nodeValue(
223     IXMLDOMElement *iface,
224     VARIANT value)
225 {
226     domelem *This = impl_from_IXMLDOMElement( iface );
227     TRACE("(%p)->(v%d)\n", This, V_VT(&value));
228     return E_FAIL;
229 }
230
231 static HRESULT WINAPI domelem_get_nodeType(
232     IXMLDOMElement *iface,
233     DOMNodeType* domNodeType )
234 {
235     domelem *This = impl_from_IXMLDOMElement( iface );
236
237     TRACE("(%p)->(%p)\n", This, domNodeType);
238
239     *domNodeType = NODE_ELEMENT;
240     return S_OK;
241 }
242
243 static HRESULT WINAPI domelem_get_parentNode(
244     IXMLDOMElement *iface,
245     IXMLDOMNode** parent )
246 {
247     domelem *This = impl_from_IXMLDOMElement( iface );
248
249     TRACE("(%p)->(%p)\n", This, parent);
250
251     return node_get_parent(&This->node, parent);
252 }
253
254 static HRESULT WINAPI domelem_get_childNodes(
255     IXMLDOMElement *iface,
256     IXMLDOMNodeList** outList)
257 {
258     domelem *This = impl_from_IXMLDOMElement( iface );
259
260     TRACE("(%p)->(%p)\n", This, outList);
261
262     return node_get_child_nodes(&This->node, outList);
263 }
264
265 static HRESULT WINAPI domelem_get_firstChild(
266     IXMLDOMElement *iface,
267     IXMLDOMNode** domNode)
268 {
269     domelem *This = impl_from_IXMLDOMElement( iface );
270
271     TRACE("(%p)->(%p)\n", This, domNode);
272
273     return node_get_first_child(&This->node, domNode);
274 }
275
276 static HRESULT WINAPI domelem_get_lastChild(
277     IXMLDOMElement *iface,
278     IXMLDOMNode** domNode)
279 {
280     domelem *This = impl_from_IXMLDOMElement( iface );
281
282     TRACE("(%p)->(%p)\n", This, domNode);
283
284     return node_get_last_child(&This->node, domNode);
285 }
286
287 static HRESULT WINAPI domelem_get_previousSibling(
288     IXMLDOMElement *iface,
289     IXMLDOMNode** domNode)
290 {
291     domelem *This = impl_from_IXMLDOMElement( iface );
292
293     TRACE("(%p)->(%p)\n", This, domNode);
294
295     return node_get_previous_sibling(&This->node, domNode);
296 }
297
298 static HRESULT WINAPI domelem_get_nextSibling(
299     IXMLDOMElement *iface,
300     IXMLDOMNode** domNode)
301 {
302     domelem *This = impl_from_IXMLDOMElement( iface );
303
304     TRACE("(%p)->(%p)\n", This, domNode);
305
306     return node_get_next_sibling(&This->node, domNode);
307 }
308
309 static HRESULT WINAPI domelem_get_attributes(
310     IXMLDOMElement *iface,
311     IXMLDOMNamedNodeMap** attributeMap)
312 {
313     domelem *This = impl_from_IXMLDOMElement( iface );
314
315     TRACE("(%p)->(%p)\n", This, attributeMap);
316
317     *attributeMap = create_nodemap((IXMLDOMNode*)&This->lpVtbl);
318     return S_OK;
319 }
320
321 static HRESULT WINAPI domelem_insertBefore(
322     IXMLDOMElement *iface,
323     IXMLDOMNode* newNode, VARIANT refChild,
324     IXMLDOMNode** outOldNode)
325 {
326     domelem *This = impl_from_IXMLDOMElement( iface );
327
328     TRACE("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
329
330     return node_insert_before(&This->node, newNode, &refChild, outOldNode);
331 }
332
333 static HRESULT WINAPI domelem_replaceChild(
334     IXMLDOMElement *iface,
335     IXMLDOMNode* newNode,
336     IXMLDOMNode* oldNode,
337     IXMLDOMNode** outOldNode)
338 {
339     domelem *This = impl_from_IXMLDOMElement( iface );
340
341     TRACE("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
342
343     return node_replace_child(&This->node, newNode, oldNode, outOldNode);
344 }
345
346 static HRESULT WINAPI domelem_removeChild(
347     IXMLDOMElement *iface,
348     IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
349 {
350     domelem *This = impl_from_IXMLDOMElement( iface );
351     return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), domNode, oldNode );
352 }
353
354 static HRESULT WINAPI domelem_appendChild(
355     IXMLDOMElement *iface,
356     IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
357 {
358     domelem *This = impl_from_IXMLDOMElement( iface );
359     return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newNode, outNewNode );
360 }
361
362 static HRESULT WINAPI domelem_hasChildNodes(
363     IXMLDOMElement *iface,
364     VARIANT_BOOL* pbool)
365 {
366     domelem *This = impl_from_IXMLDOMElement( iface );
367     return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), pbool );
368 }
369
370 static HRESULT WINAPI domelem_get_ownerDocument(
371     IXMLDOMElement *iface,
372     IXMLDOMDocument** domDocument)
373 {
374     domelem *This = impl_from_IXMLDOMElement( iface );
375     return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), domDocument );
376 }
377
378 static HRESULT WINAPI domelem_cloneNode(
379     IXMLDOMElement *iface,
380     VARIANT_BOOL deep, IXMLDOMNode** outNode)
381 {
382     domelem *This = impl_from_IXMLDOMElement( iface );
383     TRACE("(%p)->(%d %p)\n", This, deep, outNode);
384     return node_clone( &This->node, deep, outNode );
385 }
386
387 static HRESULT WINAPI domelem_get_nodeTypeString(
388     IXMLDOMElement *iface,
389     BSTR* p)
390 {
391     domelem *This = impl_from_IXMLDOMElement( iface );
392     static const WCHAR elementW[] = {'e','l','e','m','e','n','t',0};
393
394     TRACE("(%p)->(%p)\n", This, p);
395
396     return return_bstr(elementW, p);
397 }
398
399 static HRESULT WINAPI domelem_get_text(
400     IXMLDOMElement *iface,
401     BSTR* p)
402 {
403     domelem *This = impl_from_IXMLDOMElement( iface );
404     return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), p );
405 }
406
407 static HRESULT WINAPI domelem_put_text(
408     IXMLDOMElement *iface,
409     BSTR p)
410 {
411     domelem *This = impl_from_IXMLDOMElement( iface );
412     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
413     return node_put_text( &This->node, p );
414 }
415
416 static HRESULT WINAPI domelem_get_specified(
417     IXMLDOMElement *iface,
418     VARIANT_BOOL* isSpecified)
419 {
420     domelem *This = impl_from_IXMLDOMElement( iface );
421     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
422     *isSpecified = VARIANT_TRUE;
423     return S_OK;
424 }
425
426 static HRESULT WINAPI domelem_get_definition(
427     IXMLDOMElement *iface,
428     IXMLDOMNode** definitionNode)
429 {
430     domelem *This = impl_from_IXMLDOMElement( iface );
431     FIXME("(%p)->(%p)\n", This, definitionNode);
432     return E_NOTIMPL;
433 }
434
435 static inline BYTE hex_to_byte(xmlChar c)
436 {
437     if(c <= '9') return c-'0';
438     if(c <= 'F') return c-'A'+10;
439     return c-'a'+10;
440 }
441
442 static inline BYTE base64_to_byte(xmlChar c)
443 {
444     if(c == '+') return 62;
445     if(c == '/') return 63;
446     if(c <= '9') return c-'0'+52;
447     if(c <= 'Z') return c-'A';
448     return c-'a'+26;
449 }
450
451 static inline HRESULT VARIANT_from_DT(XDR_DT dt, xmlChar* str, VARIANT* v)
452 {
453     VARIANT src;
454     HRESULT hr = S_OK;
455     BOOL handled = FALSE;
456
457     VariantInit(&src);
458
459     switch (dt)
460     {
461     case DT_INVALID:
462     case DT_STRING:
463     case DT_NMTOKEN:
464     case DT_NMTOKENS:
465     case DT_NUMBER:
466     case DT_URI:
467     case DT_UUID:
468         {
469             V_VT(v) = VT_BSTR;
470             V_BSTR(v) = bstr_from_xmlChar(str);
471
472             if(!V_BSTR(v))
473                 return E_OUTOFMEMORY;
474             handled = TRUE;
475         }
476         break;
477     case DT_DATE:
478     case DT_DATE_TZ:
479     case DT_DATETIME:
480     case DT_DATETIME_TZ:
481     case DT_TIME:
482     case DT_TIME_TZ:
483         {
484             WCHAR *p, *e;
485             SYSTEMTIME st;
486             DOUBLE date = 0.0;
487
488             st.wYear = 1899;
489             st.wMonth = 12;
490             st.wDay = 30;
491             st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
492
493             V_VT(&src) = VT_BSTR;
494             V_BSTR(&src) = bstr_from_xmlChar(str);
495
496             if(!V_BSTR(&src))
497                 return E_OUTOFMEMORY;
498
499             p = V_BSTR(&src);
500             e = p + SysStringLen(V_BSTR(&src));
501
502             if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
503             {
504                 st.wYear = atoiW(p);
505                 st.wMonth = atoiW(p+5);
506                 st.wDay = atoiW(p+8);
507                 p += 10;
508
509                 if(*p == 'T') p++;
510             }
511
512             if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
513             {
514                 st.wHour = atoiW(p);
515                 st.wMinute = atoiW(p+3);
516                 st.wSecond = atoiW(p+6);
517                 p += 8;
518
519                 if(*p == '.')
520                 {
521                     p++;
522                     while(isdigitW(*p)) p++;
523                 }
524             }
525
526             SystemTimeToVariantTime(&st, &date);
527             V_VT(v) = VT_DATE;
528             V_DATE(v) = date;
529
530             if(*p == '+') /* parse timezone offset (+hh:mm) */
531                 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
532             else if(*p == '-') /* parse timezone offset (-hh:mm) */
533                 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
534
535             VariantClear(&src);
536             handled = TRUE;
537         }
538         break;
539     case DT_BIN_HEX:
540         {
541             SAFEARRAYBOUND sab;
542             int i, len;
543
544             len = xmlStrlen(str)/2;
545             sab.lLbound = 0;
546             sab.cElements = len;
547
548             V_VT(v) = (VT_ARRAY|VT_UI1);
549             V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
550
551             if(!V_ARRAY(v))
552                 return E_OUTOFMEMORY;
553
554             for(i=0; i<len; i++)
555                 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
556                     + hex_to_byte(str[2*i+1]);
557             handled = TRUE;
558         }
559         break;
560     case DT_BIN_BASE64:
561         {
562             SAFEARRAYBOUND sab;
563             int i, len;
564
565             len  = xmlStrlen(str);
566             if(str[len-2] == '=') i = 2;
567             else if(str[len-1] == '=') i = 1;
568             else i = 0;
569
570             sab.lLbound = 0;
571             sab.cElements = len/4*3-i;
572
573             V_VT(v) = (VT_ARRAY|VT_UI1);
574             V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
575
576             if(!V_ARRAY(v))
577                 return E_OUTOFMEMORY;
578
579             for(i=0; i<len/4; i++)
580             {
581                 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
582                     + (base64_to_byte(str[4*i+1])>>4);
583                 if(3*i+1 < sab.cElements)
584                     ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
585                         + (base64_to_byte(str[4*i+2])>>2);
586                 if(3*i+2 < sab.cElements)
587                     ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
588                         + base64_to_byte(str[4*i+3]);
589             }
590             handled = TRUE;
591         }
592         break;
593     case DT_BOOLEAN:
594         V_VT(v) = VT_BOOL;
595         break;
596     case DT_FIXED_14_4:
597         V_VT(v) = VT_CY;
598         break;
599     case DT_I1:
600         V_VT(v) = VT_I1;
601         break;
602     case DT_I2:
603         V_VT(v) = VT_I2;
604         break;
605     case DT_I4:
606     case DT_INT:
607         V_VT(v) = VT_I4;
608         break;
609     case DT_I8:
610         V_VT(v) = VT_I8;
611         break;
612     case DT_R4:
613         V_VT(v) = VT_R4;
614         break;
615     case DT_FLOAT:
616     case DT_R8:
617         V_VT(v) = VT_R8;
618         break;
619     case DT_UI1:
620         V_VT(v) = VT_UI1;
621         break;
622     case DT_UI2:
623         V_VT(v) = VT_UI2;
624         break;
625     case DT_UI4:
626         V_VT(v) = VT_UI4;
627         break;
628     case DT_UI8:
629         V_VT(v) = VT_UI8;
630         break;
631     case DT_CHAR:
632     case DT_ENTITY:
633     case DT_ENTITIES:
634     case DT_ENUMERATION:
635     case DT_ID:
636     case DT_IDREF:
637     case DT_IDREFS:
638     case DT_NOTATION:
639         FIXME("need to handle dt:%s\n", dt_to_str(dt));
640         V_VT(v) = VT_BSTR;
641         V_BSTR(v) = bstr_from_xmlChar(str);
642         if (!V_BSTR(v))
643             return E_OUTOFMEMORY;
644         handled = TRUE;
645         break;
646     }
647
648     if (!handled)
649     {
650         V_VT(&src) = VT_BSTR;
651         V_BSTR(&src) = bstr_from_xmlChar(str);
652
653         if(!V_BSTR(&src))
654             return E_OUTOFMEMORY;
655
656         hr = VariantChangeTypeEx(v, &src,
657                 MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
658         VariantClear(&src);
659     }
660     return hr;
661 }
662
663 static HRESULT WINAPI domelem_get_nodeTypedValue(
664     IXMLDOMElement *iface,
665     VARIANT* var1)
666 {
667     domelem *This = impl_from_IXMLDOMElement( iface );
668     XDR_DT dt;
669     xmlChar* content;
670     HRESULT hr;
671
672     TRACE("(%p)->(%p)\n", This, var1);
673
674     if(!var1)
675         return E_INVALIDARG;
676
677     V_VT(var1) = VT_NULL;
678
679     dt = element_get_dt(get_element(This));
680     content = xmlNodeGetContent(get_element(This));
681     hr = VARIANT_from_DT(dt, content, var1);
682     xmlFree(content);
683
684     return hr;
685 }
686
687 static HRESULT WINAPI domelem_put_nodeTypedValue(
688     IXMLDOMElement *iface,
689     VARIANT value)
690 {
691     domelem *This = impl_from_IXMLDOMElement( iface );
692     VARIANT type;
693     HRESULT hr;
694
695     TRACE("(%p)\n", This);
696
697     /* for untyped node coerce to BSTR and set */
698     if (IXMLDOMElement_get_dataType(iface, &type) == S_FALSE)
699     {
700         if (V_VT(&value) != VT_BSTR)
701         {
702             hr = VariantChangeType(&value, &value, 0, VT_BSTR);
703             if (hr == S_OK)
704             {
705                 hr = node_set_content(&This->node, V_BSTR(&value));
706                 VariantClear(&value);
707             }
708         }
709         else
710             hr = node_set_content(&This->node, V_BSTR(&value));
711     }
712     else
713     {
714         FIXME("not implemented for typed nodes. type %s\n", debugstr_w(V_BSTR(&value)));
715         VariantClear(&type);
716         return E_NOTIMPL;
717     }
718
719     return hr;
720 }
721
722 XDR_DT element_get_dt(xmlNodePtr node)
723 {
724     XDR_DT dt = DT_INVALID;
725
726     TRACE("(%p)\n", node);
727     if(node->type != XML_ELEMENT_NODE)
728     {
729         FIXME("invalid element node\n");
730         return dt;
731     }
732
733     if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
734     {
735         dt = str_to_dt(node->name, -1);
736     }
737     else
738     {
739         xmlChar* pVal = xmlGetNsProp(node, BAD_CAST "dt", DT_nsURI);
740         if (pVal)
741         {
742             dt = str_to_dt(pVal, -1);
743             xmlFree(pVal);
744         }
745         else if (node->doc)
746         {
747             IXMLDOMDocument3* doc = (IXMLDOMDocument3*)create_domdoc((xmlNodePtr)node->doc);
748             if (doc)
749             {
750                 VARIANT v;
751                 VariantInit(&v);
752
753                 if (IXMLDOMDocument3_get_schemas(doc, &v) == S_OK &&
754                     V_VT(&v) == VT_DISPATCH)
755                 {
756                     dt = SchemaCache_get_node_dt((IXMLDOMSchemaCollection2*)V_DISPATCH(&v), node);
757                 }
758                 VariantClear(&v);
759                 IXMLDOMDocument3_Release(doc);
760             }
761         }
762     }
763
764     TRACE("=> dt:%s\n", dt_to_str(dt));
765     return dt;
766 }
767
768 static HRESULT WINAPI domelem_get_dataType(
769     IXMLDOMElement *iface,
770     VARIANT* typename)
771 {
772     domelem *This = impl_from_IXMLDOMElement( iface );
773     XDR_DT dt;
774
775     TRACE("(%p)->(%p)\n", This, typename);
776
777     if (!typename)
778         return E_INVALIDARG;
779
780     dt = element_get_dt(get_element(This));
781     switch (dt)
782     {
783         case DT_BIN_BASE64:
784         case DT_BIN_HEX:
785         case DT_BOOLEAN:
786         case DT_CHAR:
787         case DT_DATE:
788         case DT_DATE_TZ:
789         case DT_DATETIME:
790         case DT_DATETIME_TZ:
791         case DT_FIXED_14_4:
792         case DT_FLOAT:
793         case DT_I1:
794         case DT_I2:
795         case DT_I4:
796         case DT_I8:
797         case DT_INT:
798         case DT_NUMBER:
799         case DT_R4:
800         case DT_R8:
801         case DT_TIME:
802         case DT_TIME_TZ:
803         case DT_UI1:
804         case DT_UI2:
805         case DT_UI4:
806         case DT_UI8:
807         case DT_URI:
808         case DT_UUID:
809             V_VT(typename) = VT_BSTR;
810             V_BSTR(typename) = SysAllocString(dt_to_bstr(dt));
811
812             if (!V_BSTR(typename))
813                 return E_OUTOFMEMORY;
814             break;
815         default:
816             /* Other types (DTD equivalents) do not return anything here,
817              * but the pointer part of the VARIANT is set to NULL */
818             V_VT(typename) = VT_NULL;
819             V_BSTR(typename) = NULL;
820             break;
821     }
822     return (V_VT(typename) != VT_NULL) ? S_OK : S_FALSE;
823 }
824
825 static HRESULT WINAPI domelem_put_dataType(
826     IXMLDOMElement *iface,
827     BSTR dtName)
828 {
829     domelem *This = impl_from_IXMLDOMElement( iface );
830     HRESULT hr = E_FAIL;
831     xmlChar *str;
832     XDR_DT dt;
833
834     TRACE("(%p)->(%s)\n", This, debugstr_w(dtName));
835
836     if(dtName == NULL)
837         return E_INVALIDARG;
838
839     dt = bstr_to_dt(dtName, -1);
840
841     /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
842        This applies to changing types (string->bool) or setting a new one
843      */
844     str = xmlNodeGetContent(get_element(This));
845     hr = dt_validate(dt, str);
846     xmlFree(str);
847
848     /* Check all supported types. */
849     if (hr == S_OK)
850     {
851         switch (dt)
852         {
853         case DT_BIN_BASE64:
854         case DT_BIN_HEX:
855         case DT_BOOLEAN:
856         case DT_CHAR:
857         case DT_DATE:
858         case DT_DATE_TZ:
859         case DT_DATETIME:
860         case DT_DATETIME_TZ:
861         case DT_FIXED_14_4:
862         case DT_FLOAT:
863         case DT_I1:
864         case DT_I2:
865         case DT_I4:
866         case DT_I8:
867         case DT_INT:
868         case DT_NMTOKEN:
869         case DT_NMTOKENS:
870         case DT_NUMBER:
871         case DT_R4:
872         case DT_R8:
873         case DT_STRING:
874         case DT_TIME:
875         case DT_TIME_TZ:
876         case DT_UI1:
877         case DT_UI2:
878         case DT_UI4:
879         case DT_UI8:
880         case DT_URI:
881         case DT_UUID:
882             {
883                 xmlAttrPtr attr = xmlHasNsProp(get_element(This), DT_prefix, DT_nsURI);
884                 if (attr)
885                 {
886                     attr = xmlSetNsProp(get_element(This), attr->ns, DT_prefix, dt_to_str(dt));
887                     hr = S_OK;
888                 }
889                 else
890                 {
891                     xmlNsPtr ns = xmlNewNs(get_element(This), DT_nsURI, DT_prefix);
892                     if (ns)
893                     {
894                         attr = xmlNewNsProp(get_element(This), ns, DT_prefix, dt_to_str(dt));
895                         if (attr)
896                         {
897                             xmlAddChild(get_element(This), (xmlNodePtr)attr);
898                             hr = S_OK;
899                         }
900                         else
901                             ERR("Failed to create Attribute\n");
902                     }
903                     else
904                         ERR("Failed to create Namespace\n");
905                 }
906             }
907             break;
908         default:
909             FIXME("need to handle dt:%s\n", dt_to_str(dt));
910             break;
911         }
912     }
913
914     return hr;
915 }
916
917 static HRESULT WINAPI domelem_get_xml(
918     IXMLDOMElement *iface,
919     BSTR* p)
920 {
921     domelem *This = impl_from_IXMLDOMElement( iface );
922
923     TRACE("(%p)->(%p)\n", This, p);
924
925     return node_get_xml(&This->node, TRUE, FALSE, p);
926 }
927
928 static HRESULT WINAPI domelem_transformNode(
929     IXMLDOMElement *iface,
930     IXMLDOMNode* domNode, BSTR* p)
931 {
932     domelem *This = impl_from_IXMLDOMElement( iface );
933     return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), domNode, p );
934 }
935
936 static HRESULT WINAPI domelem_selectNodes(
937     IXMLDOMElement *iface,
938     BSTR p, IXMLDOMNodeList** outList)
939 {
940     domelem *This = impl_from_IXMLDOMElement( iface );
941     return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), p, outList );
942 }
943
944 static HRESULT WINAPI domelem_selectSingleNode(
945     IXMLDOMElement *iface,
946     BSTR p, IXMLDOMNode** outNode)
947 {
948     domelem *This = impl_from_IXMLDOMElement( iface );
949     return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), p, outNode );
950 }
951
952 static HRESULT WINAPI domelem_get_parsed(
953     IXMLDOMElement *iface,
954     VARIANT_BOOL* isParsed)
955 {
956     domelem *This = impl_from_IXMLDOMElement( iface );
957     FIXME("(%p)->(%p) stub!\n", This, isParsed);
958     *isParsed = VARIANT_TRUE;
959     return S_OK;
960 }
961
962 static HRESULT WINAPI domelem_get_namespaceURI(
963     IXMLDOMElement *iface,
964     BSTR* p)
965 {
966     domelem *This = impl_from_IXMLDOMElement( iface );
967     return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), p );
968 }
969
970 static HRESULT WINAPI domelem_get_prefix(
971     IXMLDOMElement *iface,
972     BSTR* prefix)
973 {
974     domelem *This = impl_from_IXMLDOMElement( iface );
975     TRACE("(%p)->(%p)\n", This, prefix);
976     return node_get_prefix( &This->node, prefix );
977 }
978
979 static HRESULT WINAPI domelem_get_baseName(
980     IXMLDOMElement *iface,
981     BSTR* name)
982 {
983     domelem *This = impl_from_IXMLDOMElement( iface );
984     TRACE("(%p)->(%p)\n", This, name);
985     return node_get_base_name( &This->node, name );
986 }
987
988 static HRESULT WINAPI domelem_transformNodeToObject(
989     IXMLDOMElement *iface,
990     IXMLDOMNode* domNode, VARIANT var1)
991 {
992     domelem *This = impl_from_IXMLDOMElement( iface );
993     return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), domNode, var1 );
994 }
995
996 static HRESULT WINAPI domelem_get_tagName(
997     IXMLDOMElement *iface,
998     BSTR* p)
999 {
1000     domelem *This = impl_from_IXMLDOMElement( iface );
1001     xmlNodePtr element;
1002     const xmlChar *prefix;
1003     xmlChar *qname;
1004
1005     TRACE("(%p)->(%p)\n", This, p );
1006
1007     if (!p) return E_INVALIDARG;
1008
1009     element = get_element( This );
1010     if ( !element )
1011         return E_FAIL;
1012
1013     prefix = element->ns ? element->ns->prefix : NULL;
1014     qname = xmlBuildQName(element->name, prefix, NULL, 0);
1015
1016     *p = bstr_from_xmlChar(qname);
1017     if (qname != element->name) xmlFree(qname);
1018
1019     return *p ? S_OK : E_OUTOFMEMORY;
1020 }
1021
1022 static HRESULT WINAPI domelem_getAttribute(
1023     IXMLDOMElement *iface,
1024     BSTR name, VARIANT* value)
1025 {
1026     domelem *This = impl_from_IXMLDOMElement( iface );
1027     xmlNodePtr element;
1028     xmlChar *xml_name, *xml_value = NULL;
1029     HRESULT hr = S_FALSE;
1030
1031     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
1032
1033     if(!value || !name)
1034         return E_INVALIDARG;
1035
1036     element = get_element( This );
1037     if ( !element )
1038         return E_FAIL;
1039
1040     V_BSTR(value) = NULL;
1041     V_VT(value) = VT_NULL;
1042
1043     xml_name = xmlChar_from_wchar( name );
1044
1045     if(!xmlValidateNameValue(xml_name))
1046         hr = E_FAIL;
1047     else
1048         xml_value = xmlGetNsProp(element, xml_name, NULL);
1049
1050     heap_free(xml_name);
1051     if(xml_value)
1052     {
1053         V_VT(value) = VT_BSTR;
1054         V_BSTR(value) = bstr_from_xmlChar( xml_value );
1055         xmlFree(xml_value);
1056         hr = S_OK;
1057     }
1058
1059     return hr;
1060 }
1061
1062 static HRESULT WINAPI domelem_setAttribute(
1063     IXMLDOMElement *iface,
1064     BSTR name, VARIANT value)
1065 {
1066     domelem *This = impl_from_IXMLDOMElement( iface );
1067     xmlNodePtr element;
1068     xmlChar *xml_name, *xml_value;
1069     HRESULT hr;
1070     VARIANT var;
1071
1072     TRACE("(%p)->(%s var)\n", This, debugstr_w(name));
1073
1074     element = get_element( This );
1075     if ( !element )
1076         return E_FAIL;
1077
1078     VariantInit(&var);
1079     hr = VariantChangeType(&var, &value, 0, VT_BSTR);
1080     if(hr != S_OK)
1081     {
1082         FIXME("VariantChangeType failed\n");
1083         return hr;
1084     }
1085
1086     xml_name = xmlChar_from_wchar( name );
1087     xml_value = xmlChar_from_wchar( V_BSTR(&var) );
1088
1089     if(!xmlSetNsProp(element, NULL,  xml_name, xml_value))
1090         hr = E_FAIL;
1091
1092     heap_free(xml_value);
1093     heap_free(xml_name);
1094     VariantClear(&var);
1095
1096     return hr;
1097 }
1098
1099 static HRESULT WINAPI domelem_removeAttribute(
1100     IXMLDOMElement *iface,
1101     BSTR p)
1102 {
1103     domelem *This = impl_from_IXMLDOMElement( iface );
1104     IXMLDOMNamedNodeMap *attr;
1105     HRESULT hr;
1106
1107     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
1108
1109     hr = IXMLDOMElement_get_attributes(iface, &attr);
1110     if (hr != S_OK) return hr;
1111
1112     hr = IXMLDOMNamedNodeMap_removeNamedItem(attr, p, NULL);
1113     IXMLDOMNamedNodeMap_Release(attr);
1114
1115     return hr;
1116 }
1117
1118 static HRESULT WINAPI domelem_getAttributeNode(
1119     IXMLDOMElement *iface,
1120     BSTR p, IXMLDOMAttribute** attributeNode )
1121 {
1122     domelem *This = impl_from_IXMLDOMElement( iface );
1123     xmlChar *xml_name;
1124     xmlNodePtr element;
1125     xmlAttrPtr attr;
1126     IUnknown *unk;
1127     HRESULT hr = S_FALSE;
1128
1129     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), attributeNode);
1130
1131     if(!attributeNode)
1132         return E_FAIL;
1133
1134     *attributeNode = NULL;
1135
1136     element = get_element( This );
1137     if ( !element )
1138         return E_FAIL;
1139
1140     xml_name = xmlChar_from_wchar(p);
1141
1142     if(!xmlValidateNameValue(xml_name))
1143     {
1144         heap_free(xml_name);
1145         return E_FAIL;
1146     }
1147
1148     attr = xmlHasProp(element, xml_name);
1149     if(attr) {
1150         unk = create_attribute((xmlNodePtr)attr);
1151         hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMAttribute, (void**)attributeNode);
1152         IUnknown_Release(unk);
1153     }
1154
1155     heap_free(xml_name);
1156
1157     return hr;
1158 }
1159
1160 static HRESULT WINAPI domelem_setAttributeNode(
1161     IXMLDOMElement *iface,
1162     IXMLDOMAttribute* attribute,
1163     IXMLDOMAttribute** old)
1164 {
1165     domelem *This = impl_from_IXMLDOMElement( iface );
1166     xmlChar *name, *value;
1167     BSTR nameW, prefix;
1168     xmlAttrPtr attr;
1169     VARIANT valueW;
1170     HRESULT hr;
1171
1172     FIXME("(%p)->(%p %p): semi-stub\n", This, attribute, old);
1173
1174     if (!attribute) return E_INVALIDARG;
1175
1176     if (old) *old = NULL;
1177
1178     hr = IXMLDOMAttribute_get_nodeName(attribute, &nameW);
1179     if (hr != S_OK) return hr;
1180
1181     hr = IXMLDOMAttribute_get_nodeValue(attribute, &valueW);
1182     if (hr != S_OK)
1183     {
1184         SysFreeString(nameW);
1185         return hr;
1186     }
1187
1188     TRACE("attribute: %s=%s\n", debugstr_w(nameW), debugstr_w(V_BSTR(&valueW)));
1189
1190     hr = IXMLDOMAttribute_get_prefix(attribute, &prefix);
1191     if (hr == S_OK)
1192     {
1193         FIXME("namespaces not supported: %s\n", debugstr_w(prefix));
1194         SysFreeString(prefix);
1195     }
1196
1197     name = xmlChar_from_wchar(nameW);
1198     value = xmlChar_from_wchar(V_BSTR(&valueW));
1199
1200     if (!name || !value)
1201     {
1202         SysFreeString(nameW);
1203         VariantClear(&valueW);
1204         heap_free(name);
1205         heap_free(value);
1206         return E_OUTOFMEMORY;
1207     }
1208
1209     attr = xmlSetNsProp(get_element(This), NULL, name, value);
1210
1211     SysFreeString(nameW);
1212     VariantClear(&valueW);
1213     heap_free(name);
1214     heap_free(value);
1215
1216     return attr ? S_OK : E_FAIL;
1217 }
1218
1219 static HRESULT WINAPI domelem_removeAttributeNode(
1220     IXMLDOMElement *iface,
1221     IXMLDOMAttribute* domAttribute,
1222     IXMLDOMAttribute** attributeNode)
1223 {
1224     domelem *This = impl_from_IXMLDOMElement( iface );
1225     FIXME("(%p)->(%p %p)\n", This, domAttribute, attributeNode);
1226     return E_NOTIMPL;
1227 }
1228
1229 static HRESULT WINAPI domelem_getElementsByTagName(
1230     IXMLDOMElement *iface,
1231     BSTR tagName, IXMLDOMNodeList** resultList)
1232 {
1233     domelem *This = impl_from_IXMLDOMElement( iface );
1234     xmlChar *query;
1235     HRESULT hr;
1236     BOOL XPath;
1237
1238     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1239
1240     if (!tagName || !resultList) return E_INVALIDARG;
1241
1242     XPath = is_xpathmode(get_element(This)->doc);
1243     set_xpathmode(get_element(This)->doc, TRUE);
1244     query = tagName_to_XPath(tagName);
1245     hr = queryresult_create(get_element(This), query, resultList);
1246     xmlFree(query);
1247     set_xpathmode(get_element(This)->doc, XPath);
1248
1249     return hr;
1250 }
1251
1252 static HRESULT WINAPI domelem_normalize(
1253     IXMLDOMElement *iface )
1254 {
1255     domelem *This = impl_from_IXMLDOMElement( iface );
1256     FIXME("%p\n", This);
1257     return E_NOTIMPL;
1258 }
1259
1260 static const struct IXMLDOMElementVtbl domelem_vtbl =
1261 {
1262     domelem_QueryInterface,
1263     domelem_AddRef,
1264     domelem_Release,
1265     domelem_GetTypeInfoCount,
1266     domelem_GetTypeInfo,
1267     domelem_GetIDsOfNames,
1268     domelem_Invoke,
1269     domelem_get_nodeName,
1270     domelem_get_nodeValue,
1271     domelem_put_nodeValue,
1272     domelem_get_nodeType,
1273     domelem_get_parentNode,
1274     domelem_get_childNodes,
1275     domelem_get_firstChild,
1276     domelem_get_lastChild,
1277     domelem_get_previousSibling,
1278     domelem_get_nextSibling,
1279     domelem_get_attributes,
1280     domelem_insertBefore,
1281     domelem_replaceChild,
1282     domelem_removeChild,
1283     domelem_appendChild,
1284     domelem_hasChildNodes,
1285     domelem_get_ownerDocument,
1286     domelem_cloneNode,
1287     domelem_get_nodeTypeString,
1288     domelem_get_text,
1289     domelem_put_text,
1290     domelem_get_specified,
1291     domelem_get_definition,
1292     domelem_get_nodeTypedValue,
1293     domelem_put_nodeTypedValue,
1294     domelem_get_dataType,
1295     domelem_put_dataType,
1296     domelem_get_xml,
1297     domelem_transformNode,
1298     domelem_selectNodes,
1299     domelem_selectSingleNode,
1300     domelem_get_parsed,
1301     domelem_get_namespaceURI,
1302     domelem_get_prefix,
1303     domelem_get_baseName,
1304     domelem_transformNodeToObject,
1305     domelem_get_tagName,
1306     domelem_getAttribute,
1307     domelem_setAttribute,
1308     domelem_removeAttribute,
1309     domelem_getAttributeNode,
1310     domelem_setAttributeNode,
1311     domelem_removeAttributeNode,
1312     domelem_getElementsByTagName,
1313     domelem_normalize,
1314 };
1315
1316 static const tid_t domelem_iface_tids[] = {
1317     IXMLDOMElement_tid,
1318     0
1319 };
1320
1321 static dispex_static_data_t domelem_dispex = {
1322     NULL,
1323     IXMLDOMElement_tid,
1324     NULL,
1325     domelem_iface_tids
1326 };
1327
1328 IUnknown* create_element( xmlNodePtr element )
1329 {
1330     domelem *This;
1331
1332     This = heap_alloc( sizeof *This );
1333     if ( !This )
1334         return NULL;
1335
1336     This->lpVtbl = &domelem_vtbl;
1337     This->ref = 1;
1338
1339     init_xmlnode(&This->node, element, (IXMLDOMNode*)&This->lpVtbl, &domelem_dispex);
1340
1341     return (IUnknown*) &This->lpVtbl;
1342 }
1343
1344 #endif